Skip to content
Open
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ A Python bot that connects to MeshCore mesh networks via serial port, BLE, or TC

1. Clone the repository:
```bash
git clone <repository-url>
git clone https://github.com/agessaman/meshcore-bot
cd meshcore-bot
```

Expand Down
6 changes: 4 additions & 2 deletions config.ini.example
Original file line number Diff line number Diff line change
Expand Up @@ -1723,9 +1723,11 @@ enabled = false
# flood_scope = #west

# Daily weather forecast time
# Format: HH:MM (24-hour format, e.g., "6:00" for 6 AM)
# Single time: HH:MM (24-hour format, e.g., "6:00" for 6 AM)
# Multiple times: comma-separated (e.g., "6:00, 12:00, 18:00")
# Interval: "every hour", "every 2 hours", "every 30 minutes", or "@hourly"
# Or use "sunrise" or "sunset" for dynamic times based on your location
# Bot will send daily weather forecast at this time
# Bot will send weather forecast at the configured schedule
weather_alarm = 6:00

# NOTE: Temperature, wind speed, and precipitation units are inherited from [Weather] section
Expand Down
84 changes: 64 additions & 20 deletions docs/command-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,27 +86,34 @@ greetings

### `cmd`

List available commands in compact format.
List available commands in compact format, or return a configured reference URL.

**Usage:**
```
cmd
```

**Response:** Compact list of all available commands.
**Response:** Compact list of all available commands, unless `[Cmd_Command]` sets `cmd_reference_url` — then the bot replies with `Full command reference: <url>` instead of the inline list.

**Configuration:** `[Cmd_Command]` — `enabled`, `cmd_reference_url` (optional).

---

### `version`
### `version` or `ver`

Show the bot's current software version.

**Aliases:** `ver`

**Usage:**
```
version
ver
```

**Response:** Version string for the running MeshCore bot build.
**Response:** `@[User] Bot version: v0.9.x` (or branch-commit on non-release builds).

**Configuration:** `[Version_Command]` — `enabled` (default true).

---

Expand Down Expand Up @@ -170,9 +177,11 @@ wxa 10001

**Response:** Current weather conditions, forecast for tonight/tomorrow, and active weather alerts. Includes:
- Current conditions (temperature, humidity, wind, etc.)
- Short-term forecast (tonight, tomorrow)
- Short-term forecast (tonight, tomorrow) with **high/low** temperatures when available
- Weather alerts if any are active

**Configuration:** `[Weather]` — `weather_provider` (`noaa` or `openmeteo`), `temperature_high_low_format`, `use_bot_location_when_no_location`, and optional **`custom.mqtt_weather.*`** topics for MQTT-sourced weather.

**Note:** Weather alerts are automatically included when available.

---
Expand Down Expand Up @@ -203,11 +212,11 @@ gwx 35.6762,139.6503
- Current temperature and conditions
- Feels-like temperature
- Wind speed and direction
- Humidity
- Dew point
- Visibility
- Pressure
- Forecast for today/tonight and tomorrow
- Humidity, dew point, visibility, pressure
- Forecast with **high/low** temperatures
- **Multi-day** forecasts when requested (e.g. `gwx Tokyo 7` or `7d` suffix — see `config.ini.example`)

**Configuration:** `[Weather]` — `openmeteo_model` (model selection), `use_bot_location_when_no_location` (fallback when no location in message), `temperature_high_low_format`, and optional **`custom.mqtt_weather.<name>`** MQTT topics.

---

Expand Down Expand Up @@ -313,7 +322,7 @@ overhead <latitude>,<longitude>
- `ladd` - Show only LADD aircraft
- `pia` - Show only PIA aircraft
- `squawk=<code>` - Filter by transponder squawk code
- `limit=<n>` - Limit number of results (default: 10, max: 50)
- `limit=<n>` - Limit API fetch size (overrides `[Airplanes_Command]` `max_results` for this request)
- `closest` - Sort by distance (closest first)
- `highest` - Sort by altitude (highest first)
- `fastest` - Sort by speed (fastest first)
Expand All @@ -332,15 +341,14 @@ airplanes 47.6,-122.3 radius=25 closest
```

**Response:**
- **Single aircraft**: Detailed format with callsign, type, altitude, speed, track, distance, bearing, vertical rate, and registration
- **Multiple aircraft**: Compact list format with callsign, altitude, speed, distance, and bearing
- **Single aircraft** (`overhead`): Detailed format with callsign, type, altitude, speed, track, distance, bearing, vertical rate, and registration
- **Multiple aircraft**: All matches are packed into **one mesh message** (RF length limited). If not everything fits, the reply ends with `...+N more` for the remainder count

**Configuration:**
The command can be configured in `config.ini` under `[Airplanes_Command]`:
**Configuration:** `[Airplanes_Command]`:
- `enabled` - Enable/disable the command
- `api_url` - API endpoint URL (default: `http://api.airplanes.live/v2/`)
- `default_radius` - Default search radius in nautical miles
- `max_results` - Maximum number of results to return
- `max_results` - Default API result cap (`0` = no configured cap; output is still bounded by single-message RF limits)
- `url_timeout` - API request timeout in seconds

**Note:** Uses companion location from database if available, otherwise falls back to bot location from config. The API is rate-limited to 1 request per second.
Expand Down Expand Up @@ -663,6 +671,32 @@ catfact

---

### RandomLine (configurable triggers)

Not a single fixed command name — **`[RandomLine]`** defines trigger words that return a random line from a text file. Useful for fortunes, facts, or custom responses.

**Example config** (see `config.ini.example`):

```ini
[RandomLine]
triggers.fortune = fortune,fortunes
file.fortune = data/randomlines/fortunes.txt
prefix.fortune = 🥠
```

**Usage:** Send an exact trigger word (e.g. `fortune`) as the message or command stem.

**Options per entry:**
- `triggers.<key>` — Comma-separated trigger words (exact match after parsing)
- `file.<key>` — Path to line-delimited text file (BSD fortune format supported)
- `prefix.<key>` — String prepended to the chosen line
- `channel.<key>` / `channels.<key>` — Restrict to specific channels
- `category.<key>` — Website command-reference category

There is no separate built-in `fortune` command — use RandomLine with a fortunes file.

---

## Sports Commands

### `sports`
Expand Down Expand Up @@ -690,7 +724,9 @@ sports mlb

### `path` or `decode` or `route`

Decode and display the routing path of a message.
Decode and display the routing path of a message. Supports **multi-byte** hop encodings (1-, 2-, and 3-byte prefixes) when present in the path.

**Aliases:** `decode`, `route`

**Usage:**
```
Expand All @@ -699,7 +735,13 @@ decode
route
```

**Response:** Shows the complete routing path the message took through the mesh network, including all intermediate nodes.
**Response:** Routing path through the mesh, including intermediate nodes. Repeater selection may use graph validation, proximity scoring, and configured presets.

**Configuration:** `[Path_Command]` — see [Path Command](path-command-config.md) for presets, graph settings, and tuning. Key option:

- **`geographic_scoring_enabled`** (default `true`) — When `false`, geographic proximity guessing is disabled for path decode. This is a **config** toggle, not a chat subcommand.

Optional **`enable_p_shortcut`** (default true) allows abbreviated path selection flows documented in the Path Command guide.

---

Expand Down Expand Up @@ -1054,9 +1096,11 @@ View configured scheduled messages and advert interval.
schedule
```

**Response:** Lists configured scheduled posts (each line shows the cron or preset schedule, or legacy `HH:MM` if you still use deprecated HHMM keys) plus current advert timing.
**Response:** Lists scheduled posts from `[Scheduled_Messages]` (cron or preset schedule, or legacy `HH:MM` keys) plus current advert timing. Scoped entries show regional flood scope when configured (`channel:#scope:message`).

**Configuration:** `[Schedule_Command]` — `enabled`, `dm_only` (default true: schedule is visible in DMs only unless changed).

**Note:** DM-only command by default.
**Note:** Admin-level visibility; configure `dm_only = false` to allow channel use.

---

Expand Down
4 changes: 4 additions & 0 deletions docs/config-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ The bot will not start without these sections. The validator reports them as **e
- `[WebViewer]` → use `[Web_Viewer]`
- `[FeedManager]` → use `[Feed_Manager]`
- `[Jokes]` → use `[Joke_Command]` / `[DadJoke_Command]` (see [Configuration](configuration.md) and [Upgrade](upgrade.md) for legacy support).
- **`[Aliases]`** — Deprecated in v0.9. Move entries to per-command `aliases =` under each `*_Command` section. The validator may report this as **info**; see [Upgrade guide](upgrade.md#upgrading-from-v08--v09).
- **Unknown sections** (not in the canonical list and not a `*_Command` section) are reported as **info**; the validator may suggest a similar section name if it looks like a command.

### Optional sections (info only)
Expand All @@ -56,6 +57,9 @@ If these are absent, the validator reports **info** (no error):
- **`[Admin_ACL]`** – Absent means admin commands (repeater, webviewer, reload, channelpause) are disabled.
- **`[Banned_Users]`** – Absent means no users are banned.
- **`[Localization]`** – Absent means defaults (e.g. `language=en`, `translation_path=translations/`) are used.
- **`[Rate_Limits]`**, **`[Webhook]`** – Optional; no error if absent.

The validator does not deeply validate `[Rate_Limits]` key shapes or `[Webhook]` API settings — refer to `config.ini.example` and [Configuration](configuration.md).

### Public channel guard

Expand Down
37 changes: 37 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ The main sections include:
| `[Keywords]` | Keyword → response pairs |
| `[Weather]` | Units and settings shared by `wx` / `gwx` and Weather Service |
| `[Logging]` | Log file path and level |
| `[Web_Viewer]` | Web dashboard (host, port, password, auto_start) |
| `[Data_Retention]` | Database table retention periods — see [Data retention](data-retention.md) |
| `[Rate_Limits]` | Per-channel minimum seconds between bot messages |
| `[Webhook]` | Inbound HTTP POST relay to channels or DMs |
| `[Version_Command]` | `version` / `ver` command |
| `[Schedule_Command]` | `schedule` command visibility |

### Connection: transport reconnect

Expand Down Expand Up @@ -128,6 +134,35 @@ Common per-command options (when supported by that command):
- Comma list: only those channels
- **`aliases`** – Extra trigger words for that command, comma-separated **stems only** (e.g. `aliases = weather, w`). Do not put the bot's **`command_prefix`** or punctuation in this value (no `!` or `.`)

### Per-command aliases (v0.9)

The global **`[Aliases]`** section is **deprecated**. Define aliases in each command’s own section:

```ini
[Wx_Command]
enabled = true
aliases = weather, w
```

Remove any legacy `[Aliases]` block when upgrading. See [Upgrade guide](upgrade.md#upgrading-from-v08--v09).

### Rate limiting

**`[Rate_Limits]`** sets per-channel minimum seconds between bot messages:

```ini
[Rate_Limits]
channel.BotCmds_seconds = 15
```

Channels without an entry are unrestricted. Global and per-user rate limits remain under `[Bot]`.

### Inbound webhook

**`[Webhook]`** runs an HTTP server that accepts POST requests and relays JSON payloads to MeshCore channels or DMs. See `config.ini.example` for `enabled`, `host`, `port`, `secret_token`, `allowed_channels`, and `rate_limit_per_minute`. Use bearer token or `X-Webhook-Token` when `secret_token` is set.

Bind to `127.0.0.1` unless your firewall restricts access. Default port **8765** (must not conflict with the web viewer on **8080**).

Full reference: see `config.ini.example` in the repository for every section and option, with inline comments.

## Data retention
Expand All @@ -140,6 +175,8 @@ The Path command has many options (presets, proximity, graph validation, etc.).

**[Path Command](path-command-config.md)** – Presets, geographic and graph settings, and tuning.

Key option: **`geographic_scoring_enabled`** (default `true`) in `[Path_Command]` — when `false`, geographic proximity guessing is disabled for path decode.

## Service plugin configuration

Service plugins (Discord Bridge, Telegram Bridge, Packet Capture, Map Uploader, Weather Service, Earthquake Service, Repeater Prefix Collision Service, and Webhook Service) each have their own section and are documented under [Service Plugins](service-plugins.md). The MQTT weather relay uses the `MqttWeather` section plus custom topic keys under `[Weather]`.
Expand Down
2 changes: 1 addition & 1 deletion docs/data-retention.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Data retention

The bot stores data in a SQLite database for the web viewer, stats, repeater management, and path routing. To limit database size, **data retention** controls how long rows are kept. Cleanup runs **daily** from the bot’s scheduler, so retention is enforced even when the standalone web viewer is not running.
The bot stores data in a SQLite database for the web viewer, stats, repeater management, and path routing. To limit database size, **data retention** controls how long rows are kept. Cleanup runs **daily** from the bot’s APScheduler-based maintenance loop, so retention is enforced even when the standalone web viewer is not running.

## Configuration

Expand Down
4 changes: 3 additions & 1 deletion docs/discord-bridge.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ The Discord Bridge service posts MeshCore channel messages to Discord channels v
**Features:**
- One-way message flow (MeshCore → Discord only)
- Multi-channel mapping (map multiple MeshCore channels to different Discord channels)
- **Multi-webhook fan-out** — comma-separated webhook URLs per MeshCore channel
- Webhook-based (simple, secure, no bot permissions needed)
- **DMs are NEVER bridged** (hardcoded for privacy)
- Rate limit monitoring (warns when approaching Discord's limits)
Expand All @@ -29,8 +30,9 @@ Edit `config.ini`:
[DiscordBridge]
enabled = true

# Map MeshCore channels to Discord webhooks
# Map MeshCore channels to Discord webhooks (comma-separated for multiple destinations)
bridge.general = https://discord.com/api/webhooks/YOUR_WEBHOOK_URL_HERE
# bridge.alerts = https://discord.com/api/webhooks/URL1,https://discord.com/api/webhooks/URL2
```

### 3. Restart Bot
Expand Down
30 changes: 26 additions & 4 deletions docs/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,13 +204,13 @@ docker-compose up -d --build

## Using Pre-built Images

If you're using GitHub Container Registry images:
Official images are published to **GitHub Container Registry** (`ghcr.io/agessaman/meshcore-bot`) on tagged releases and `main`.

1. **Update docker-compose.yml** to use the image:
```yaml
services:
meshcore-bot:
image: ghcr.io/your-username/meshcore-bot:latest
image: ghcr.io/agessaman/meshcore-bot:latest
# Remove or comment out the 'build' section
```

Expand All @@ -220,6 +220,26 @@ If you're using GitHub Container Registry images:
docker-compose up -d
```

## Multi-architecture images

CI builds multi-platform images with SBOM and provenance attestations:

| Platform | Typical hardware |
|----------|------------------|
| `linux/amd64` | x86-64 servers and desktops |
| `linux/arm64` | Raspberry Pi 4/5 (64-bit OS), Apple Silicon via emulation |
| `linux/arm/v7` | Raspberry Pi 3 and older (32-bit Raspberry Pi OS) |

On ARM devices, pull the matching platform (Docker usually selects automatically):

```bash
docker pull --platform linux/arm64 ghcr.io/agessaman/meshcore-bot:latest
```

Or build locally for your architecture with `docker compose build`.

**Non-Docker installs:** Debian packages are available via `make deb` in the repository. See the [Upgrade guide](upgrade.md).

## Troubleshooting

### Permission Issues
Expand Down Expand Up @@ -468,7 +488,7 @@ docker-compose up -d

4. **Secrets**: Never commit API keys or sensitive data to version control. Use environment variables or secrets management

5. **Web viewer**: If enabled, ensure it's only accessible on trusted networks or use a reverse proxy with authentication
5. **Web viewer**: Set `web_viewer_password` in `[Web_Viewer]` when `host = 0.0.0.0`. Use a reverse proxy with TLS on untrusted networks. See [Web Viewer](web-viewer.md).

## Connecting COM Ports to Docker on Windows 11 {#connecting-com-ports-to-docker-on-windows-11}

Expand Down Expand Up @@ -536,4 +556,6 @@ serial_port = /dev/ttyUSB0

- [Docker Documentation](https://docs.docker.com/)
- [Docker Compose Documentation](https://docs.docker.com/compose/)
- [Main README](https://github.com/agessaman/meshcore-bot/blob/main/README.md) for general bot configuration.
- [Main README](https://github.com/agessaman/meshcore-bot/blob/main/README.md) for general bot configuration
- [Upgrade guide](upgrade.md) for v0.9 migration notes
- [Web Viewer](web-viewer.md) for dashboard configuration
12 changes: 11 additions & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,21 @@ Without `--upgrade`, the script does *not* update the service file (systemd/laun

**Recommendation:** Use `./install-service.sh --upgrade` after `git pull` when you want to upgrade; that updates files, dependencies, and the service, and reloads the service, while keeping your `config.ini` intact.

### I'm upgrading to v0.9. What do I need to change?

v0.9 requires **Python 3.10+** and **`meshcore >= 2.3.6`**. Your `config.ini` is preserved by the install script, but you should review:

- Remove global **`[Aliases]`** and use per-command `aliases =` instead
- Set **`web_viewer_password`** if the web viewer is exposed beyond localhost
- Start the bot once so **database migrations** run

See the full checklist in the [Upgrade guide](upgrade.md).

### I moved a previous database into a new install; the bot runs but I see "Error processing message queue" or "Error processing channel operations". What should I do?

Moving an old database into a new install can cause those errors when:

1. **Schema mismatch** — The old DB may be missing tables or columns (e.g. `feed_message_queue`, `channel_operations`, or `message_send_interval_seconds` on `feed_subscriptions`). The bot runs `CREATE TABLE IF NOT EXISTS` and `ALTER TABLE` on startup, so missing tables/columns are usually added. If the exception in the log is `no such column`, the schema in the copied DB is older than expected; ensure the bot has started at least once so migrations run.
1. **Schema mismatch** — The old DB may be missing tables or columns. v0.9 uses versioned migrations (`MigrationRunner`) at startup. Ensure you are on the latest code and start the bot at least once so migrations complete. If the log shows `no such column`, the copied DB may be from a much older release — see the [Upgrade guide](upgrade.md).
2. **Stale queue/ops** — Pending rows in `feed_message_queue` or `channel_operations` from the old install may reference channels or feeds that don’t exist or differ on the new install. You can clear them so the scheduler stops hitting errors (with the bot stopped). If `sqlite3` is not installed, use Python instead:
- Clear unsent queue and pending channel ops (Python; no extra packages):
```bash
Expand Down
7 changes: 6 additions & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ Get meshcore-bot running on your machine in a few minutes.

2. **Configure**

Copy an example config and edit with your connection and bot settings:
**Interactive (recommended):** `make config` — ncurses editor for `config.ini`.

Or copy an example config and edit with your connection and bot settings:

- **Full config** (all commands and options):
```bash
Expand Down Expand Up @@ -89,5 +91,8 @@ meshcore-bot.url = "github:agessaman/meshcore-bot/";
## Next steps

- **[Command Reference](command-reference.md)** — Full command reference (wx, aqi, sun, path, prefix, etc.)
- **[Upgrade guide](upgrade.md)** — Migrating to v0.9 from older releases
- **[Config validation](config-validation.md)** — Validate `config.ini` before first run
- **[Data retention](data-retention.md)** — Database cleanup defaults
- **[README](https://github.com/agessaman/meshcore-bot/blob/main/README.md)** — Features, keywords, configuration overview
- **Guides** (sidebar) — Path command, repeater commands, feeds, weather service, Discord bridge, map uploader, packet capture
Loading