pe1hvh d9ad4c83b8 feat(bbs): DM-based BBS with channel-based access, multi-channel whitelist, short syntax(#v1.14.0)
Adds an offline BBS accessible via Direct Message to the node's own key.
Access is channel-based: anyone seen on a configured BBS channel is
automatically whitelisted for DM access. Channels stay clean.

- Multi-channel configuration: any combination of device channels can be
  selected; senders on any of them are auto-whitelisted
- Short syntax: !p <cat> <text> and !r [cat] alongside full !bbs syntax
- Category abbreviations computed automatically (shortest unique prefix)
- handle_channel_msg: bootstrap reply on channel + auto-whitelist sender
- handle_dm: DM entry point, checks whitelist, routes to post/read/help
- DM reply routed back to sender via command_sink
- SQLite message store with WAL mode and configurable retention
2026-03-14 20:01:07 +01:00
2026-03-12 14:26:38 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00
2026-03-09 17:53:29 +01:00

MeshCore GUI — Native USB & BLE

Cross-frequency bridge included — no MQTT, no broker, no cloud. Just LoRa ↔ LoRa.

Status

Python License Platform Transport Bridge image

A graphical user interface for MeshCore mesh network devices with native USB serial and Bluetooth Low Energy (BLE) support, for on your desktop or as a headless service on your local network.

Table of Contents


1. Why This Project Exists

MeshCore devices like the SenseCAP T1000-E can be managed through two interfaces: USB serial and BLE (Bluetooth Low Energy). The official companion apps communicate with devices over BLE, but they are mobile-only. For desktop or headless operation, USB serial is the most reliable option and works on all platforms.

This project provides a native desktop GUI that connects to your MeshCore device over USB serial or Bluetooth LE:

  • Dual transport — auto-detects the connection type from the device argument: serial port path → USB serial, MAC address → Bluetooth LE
  • Serial mode — requires Serial Companion firmware on the device; works on all platforms
  • BLE mode — connects wirelessly via Bluetooth Low Energy with automatic PIN pairing; requires Linux with BlueZ (D-Bus). Note: recent BlueZ versions (5.66+) may cause connection instability — see 5.1. System Dependencies for details
  • Cross-platform — written in Python using cross-platform libraries, runs on Linux, macOS and Windows (serial mode); BLE mode is Linux-only
  • Headless capable — since the interface is web-based (powered by NiceGUI), it also runs headless on devices like a Raspberry Pi, accessible from any browser on your local network
  • Message archive — all messages are persisted to disk with configurable retention, so you maintain a searchable history of mesh traffic
  • Bots and observation — run a keyword-triggered auto-reply bot or passively observe mesh traffic 24/7
  • Room Server support — login to Room Servers directly from the GUI with dedicated message panels per room
  • Cross-frequency bridge — connect two MeshCore devices on different frequencies with an independent bridge daemon that forwards channel messages bidirectionally, with zero changes to the main codebase

Note: This project is under active development. Not all features from the official MeshCore Companion apps have been implemented yet. Contributions and feedback are welcome.

Note: This application has been tested on Linux (Ubuntu 24.04) and Raspberry Pi 5 (Debian Bookworm, headless) with both serial and BLE transports. macOS and Windows should work for serial mode since all dependencies (nicegui, meshcore) are cross-platform, but this has not been verified. BLE mode requires Linux with BlueZ. Feedback and contributions for other platforms are welcome.

Under the hood it uses meshcore as the protocol layer, meshcoredecoder for raw LoRa packet decryption and route extraction, and NiceGUI for the web-based interface.

2. Features

  • Real-time Dashboard — Device info, contacts, messages and RX log
  • Interactive Map — Leaflet map with markers for own position and contacts
  • Channel Messages — Send and receive messages on channels
  • Direct Messages — Click on a contact to send a DM
  • Contact Maintenance — Pin/unpin contacts to protect them from deletion, bulk-delete unpinned contacts from the device, and toggle automatic contact addition from mesh adverts
  • Message Filtering — Filter messages per channel via checkboxes
  • Message Route Visualization — Click any message to open a detailed route page showing the path (hops) through the mesh network on an interactive map, with a hop summary, route table and reply panel
  • Message Archive — All messages and RX log entries are persisted to disk with configurable retention. Browse archived messages via the archive viewer with filters (channel, time range, text search), pagination and inline route tables
  • Room Server Support — Login to Room Servers directly from the GUI. Each Room Server gets a dedicated panel with message display, send functionality and login/logout controls. Passwords are stored securely outside the repository. Message author attribution correctly resolves the real sender from signed messages
  • Dynamic Channel Discovery — Channels are automatically discovered from the device at startup via probing, eliminating the need to manually configure CHANNELS_CONFIG
  • Keyword Bot — Built-in auto-reply bot that responds to configurable keywords on selected channels, with cooldown and loop prevention
  • Packet Decoding — Raw LoRa packets from RX log are decoded and decrypted using channel keys, providing message hashes, path hashes and hop data
  • Message Deduplication — Dual-strategy dedup (hash-based and content-based) prevents duplicate messages from appearing
  • Local Cache — Device info, contacts and channel keys are cached to disk (~/.meshcore-gui/cache/) so the GUI is instantly populated on startup from the last known state, even before the serial link connects. Contacts from the device are merged with cached contacts so offline nodes are preserved. Channel keys that fail to load at startup are retried in the background every 30 seconds
  • Periodic Contact Refresh — Contacts are automatically refreshed from the device at a configurable interval (default: 5 minutes) and merged with the cache
  • Threaded Architecture — Device communication in separate thread for stable UI
  • Dual Transport — Auto-detects USB serial or Bluetooth LE from the device argument; BLE includes automatic PIN pairing and bond management
  • Cross-Frequency Bridge — Standalone bridge daemon (meshcore_bridge) connects two devices on different frequencies by forwarding messages on a configurable bridge channel. Runs as a separate process with its own DOMCA-themed dashboard, YAML configuration, loop prevention and systemd service installer. Requires zero changes to meshcore_gui. See 11. Cross-Frequency Bridge for details

3. Screenshots

a_Screenshots Screenshot from 2026-02-18 09-27-59 Screenshot from 2026-02-18 09-28-27 image

4. Requirements

  • Python 3.10+
  • Serial mode: USB serial connection + Serial Companion firmware on the device
  • BLE mode: Bluetooth adapter + Linux with BlueZ (D-Bus); additional Python packages: bleak, dbus_fast

4.1. Platform Support

Platform Serial BLE Status
Linux (Ubuntu/Debian) pySerial bleak + dbus_fast Tested
Raspberry Pi 5 (Debian Bookworm) pySerial bleak + dbus_fast Tested (headless)
macOS pySerial No D-Bus Serial untested
Windows 10/11 pySerial No D-Bus Serial untested

5. Installation

5.1. System Dependencies

Linux (Ubuntu/Debian) — Serial:

sudo apt update
sudo apt install python3-pip python3-venv

Linux (Ubuntu/Debian) — BLE (additionally):

sudo apt install bluetooth bluez

Verify that the Bluetooth service is running:

sudo systemctl status bluetooth

⚠️ BlueZ driver warning: Recent versions of BlueZ (5.66+, shipped with Ubuntu 24.04 and Debian Bookworm) introduced changes to the BLE connection handling and D-Bus agent API that can cause connection instability, pairing failures and unexpected disconnects in BLE mode. Known symptoms include:

  • Pairing succeeds but the connection drops within seconds
  • org.bluez.Error.AuthenticationFailed or org.bluez.Error.ConnectionAttemptFailed in the logs
  • Repeated bond/unbond cycles without a stable connection

Workaround: If you experience BLE instability, try downgrading BlueZ to 5.65 or pinning the package version. Alternatively, use USB serial mode which is not affected by BlueZ and provides the most reliable connection on all platforms. See 13.1.2. BLE Quick Fixes for troubleshooting steps.

Raspberry Pi (Raspberry Pi OS Lite) — Serial:

sudo apt update
sudo apt install python3-pip python3-venv git

Raspberry Pi — BLE (additionally):

sudo apt install bluetooth bluez

The Raspberry Pi 5 has a built-in Bluetooth adapter. Verify with hciconfig or bluetoothctl show.

⚠️ Raspberry Pi OS Bookworm ships with BlueZ 5.66+ which is affected by the BLE stability issues described above. If BLE connections are unreliable, consider USB serial as the primary transport.

macOS:

# Python 3.10+ via Homebrew (if not already installed)
brew install python

No additional system packages needed. BLE mode is not supported on macOS (requires Linux D-Bus).

Windows:

  • Install Python 3.10+ (check "Add to PATH" during installation)
  • No additional system packages needed. BLE mode is not supported on Windows (requires Linux D-Bus).

5.1.1. D-Bus Policy for BLE (Linux only)

BLE mode uses a D-Bus PIN agent to handle automatic pairing. Your user needs permission to interact with BlueZ over the system bus. Create a policy file:

sudo tee /etc/dbus-1/system.d/meshcore-ble.conf > /dev/null << 'EOF'
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
  "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
  <policy user="YOUR_USERNAME">
    <allow send_destination="org.bluez"/>
    <allow send_interface="org.bluez.Agent1"/>
    <allow send_interface="org.bluez.AgentManager1"/>
  </policy>
</busconfig>
EOF

Replace YOUR_USERNAME with your actual username. This step is handled automatically if you use the install_ble_stable.sh installer (see 7.5.1).

Note: Without this policy, the BLE PIN agent cannot register with BlueZ and pairing will fail with a D-Bus permission error.

5.2. Clone the Repository

git clone https://github.com/pe1hvh/meshcore-gui.git
cd meshcore-gui

5.3. Create Virtual Environment

Linux / macOS:

python3 -m venv venv
source venv/bin/activate

Windows:

python -m venv venv
venv\Scripts\activate

5.4. Install Python Packages

Core (Serial mode):

pip install nicegui meshcore meshcoredecoder

BLE mode (additionally):

pip install bleak dbus_fast

Note: BLE dependencies (bleak, dbus_fast) are only needed when connecting via Bluetooth LE. Serial-only installs do not require them — they are imported lazily at runtime.

6. Usage

6.1. Activate the Virtual Environment

Linux / macOS:

cd meshcore-gui
source venv/bin/activate

Windows:

cd meshcore-gui
venv\Scripts\activate

6.2. Find Your Device

Serial — Linux:

ls -l /dev/serial/by-id

Look for your MeshCore device and note the device path (e.g., /dev/ttyUSB0).

Serial — macOS:

ls /dev/tty.usb* /dev/tty.usbserial* /dev/tty.usbmodem*

Serial — Windows: Open Device Manager → Ports (COM & LPT) and note the COM port (e.g., COM3).

BLE — Linux:

bluetoothctl scan on

Look for your MeshCore device and note the MAC address (e.g., AA:BB:CC:DD:EE:FF).

6.3. Configure Channels (optional)

Channels are automatically discovered from the device at startup via the serial link. No manual configuration is required.

If you want to cache the discovered channel list to disk (for faster startup), set CHANNEL_CACHE_ENABLED = True in meshcore_gui/config.py. By default, channels are always fetched fresh from the device.

Note: The maximum number of channel slots probed can be adjusted via MAX_CHANNELS in config.py (default: 8, which matches the MeshCore protocol limit).

6.4. Start the GUI

See 7. Starting the Application below for all startup methods.

7. Starting the Application

MeshCore GUI is a web-based application powered by NiceGUI. Once started, it serves a dashboard that you can access from any browser — locally or over your network. There are several ways to run it, depending on your use case.

All examples below assume you have activated the virtual environment and are in the project directory:

cd ~/meshcore-gui
source venv/bin/activate       # Linux / macOS

7.1. Command-Line Options

The transport mode is auto-detected from the device argument:

  • Path like /dev/ttyUSB0 or COM3 → Serial mode
  • MAC address like literal:AA:BB:CC:DD:EE:FF → BLE mode
Flag Description Default Mode
--debug-on Enable verbose debug logging (stdout + log file) Off Both
--port=PORT Web server port 8081 Both
--ssl Enable HTTPS with auto-generated certificate Off Both
--baud=BAUD Serial baudrate 115200 Serial
--serial-cx-dly=SECONDS Serial connection delay 0.1 Serial
--ble-pin PIN BLE pairing PIN 123456 BLE

All flags are optional and can be combined in any order:

# Serial
python meshcore_gui.py /dev/ttyUSB0 --debug-on --port=8082 --baud=115200

# BLE
python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on --ble-pin 654321

7.2. Method 1: Interactive (foreground)

The simplest way to start — runs in your current terminal. Output is visible directly. Press Ctrl+C to stop.

Serial:

python meshcore_gui.py /dev/ttyUSB0

BLE:

python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF

Open your browser at http://localhost:8081 (or the port you specified with --port).

This is the recommended method during development or when debugging, because you see all output immediately in your terminal.

7.3. Method 2: Background with Visible Output (nohup + tail)

Runs in the background but keeps the output visible in your terminal. Useful for SSH sessions where you want to monitor the application while keeping the terminal usable.

Serial:

nohup python meshcore_gui.py /dev/ttyUSB0 --debug-on > ~/meshcore.log 2>&1 &
tail -f ~/meshcore.log

BLE:

nohup python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on > ~/meshcore.log 2>&1 &
tail -f ~/meshcore.log

The first command starts the application in the background and writes all output to ~/meshcore.log. The & at the end returns control to your terminal. The second command follows the log file in real-time — press Ctrl+C to stop following (the application keeps running).

7.4. Method 3: Background with Terminal Free (nohup)

Runs entirely in the background. Your terminal is free and the application survives closing your SSH session. Ideal for headless devices where you start the application once and leave it running.

Serial:

nohup python meshcore_gui.py /dev/ttyUSB0 --debug-on > ~/meshcore.log 2>&1 &

BLE:

nohup python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on > ~/meshcore.log 2>&1 &

To check if it is running:

ps aux | grep meshcore_gui

To view recent output:

tail -50 ~/meshcore.log

To stop it:

pkill -f meshcore_gui

Tip: Avoid redirecting to /dev/null — keeping the output in a log file preserves connection errors and other diagnostics. When --debug-on is enabled, detailed debug output is also written to a per-device rotating log file at ~/.meshcore-gui/logs/<ADDRESS>_meshcore_gui.log (e.g. F0_9E_9E_75_A3_01_meshcore_gui.log, max 20 MB, rotates automatically).

A systemd service starts automatically on boot, restarts on crashes, and integrates with system logging. This is the recommended method for permanent headless deployments (e.g. Raspberry Pi).

7.5.1. Automated Setup

Use the appropriate installer for your transport:

# Serial connection
bash install_serial.sh

# BLE connection
bash install_ble_stable.sh

Serial environment variables (optional):

SERIAL_PORT=/dev/ttyACM0
BAUD=115200
SERIAL_CX_DLY=0.1
WEB_PORT=8081
DEBUG_ON=yes

BLE environment variables (optional):

BLE_ADDRESS=AA:BB:CC:DD:EE:FF
WEB_PORT=8081
DEBUG_ON=yes

The BLE installer also installs the D-Bus policy file and configures the systemd service with the correct DBUS_SYSTEM_BUS_ADDRESS environment variable.

7.5.2. Manual Setup

Serial

Step 1 — Create the service file:

sudo nano /etc/systemd/system/meshcore-gui.service
[Unit]
Description=MeshCore GUI (Serial)

[Service]
Type=simple
User=your-username
WorkingDirectory=/home/your-username/meshcore-gui
ExecStart=/home/your-username/meshcore-gui/venv/bin/python meshcore_gui.py /dev/ttyUSB0 --debug-on --port=8081 --baud=115200
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target

Replace your-username, /dev/ttyUSB0 and port with your actual values.

BLE

Step 1 — Ensure the D-Bus policy is installed (see 5.1.1).

Step 2 — Create the service file:

sudo nano /etc/systemd/system/meshcore-gui.service
[Unit]
Description=MeshCore GUI (BLE)
After=bluetooth.target
Wants=bluetooth.target

[Service]
Type=simple
User=your-username
WorkingDirectory=/home/your-username/meshcore-gui
ExecStart=/home/your-username/meshcore-gui/venv/bin/python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on --port=8081 --ble-pin 123456
Restart=on-failure
RestartSec=30
Environment=DBUS_SYSTEM_BUS_ADDRESS=unix:path=/var/run/dbus/system_bus_socket
[Install]
WantedBy=multi-user.target

Replace your-username, AA:BB:CC:DD:EE:FF and PIN with your actual values. The DBUS_SYSTEM_BUS_ADDRESS environment variable is required for the BLE PIN agent to communicate with BlueZ.

Enable and start

For both serial and BLE:

sudo systemctl daemon-reload
sudo systemctl enable meshcore-gui
sudo systemctl start meshcore-gui

Useful service commands:

Command Description
sudo systemctl status meshcore-gui Check if the service is running
sudo journalctl -u meshcore-gui -f Follow the live log output
sudo journalctl -u meshcore-gui --since "1 hour ago" View recent logs
sudo systemctl restart meshcore-gui Restart after a configuration change
sudo systemctl stop meshcore-gui Stop the service
sudo systemctl disable meshcore-gui Prevent starting on boot

7.6. Accessing the Interface

Once the application is running (via any method), open a browser and navigate to:

http://localhost:8081

From another device on the same network, use the hostname or IP address:

http://<hostname-or-ip>:8081

For example: http://raspberrypi5nas:8081 or http://192.168.2.234:8081. This works from any device on the same network — desktop, laptop, tablet or phone.

7.7. Running Multiple Instances

You can run multiple instances simultaneously (e.g. for different MeshCore devices) by assigning each a different port:

# Two serial devices
python meshcore_gui.py /dev/ttyUSB0 --port=8081 --baud=115200 &
python meshcore_gui.py /dev/ttyUSB1 --port=8082 --baud=115200 &

# Mixed: serial + BLE
python meshcore_gui.py /dev/ttyACM0 --port=8081 &
python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --port=8082 &

Each instance gets its own log file, cache and archive, all keyed by the device identifier (serial port or BLE address).

7.8. Migrating Existing Data

If you are moving from an existing installation, copy the data directory to preserve your cache, pinned contacts, room server passwords and message archive:

scp -r ~/.meshcore-gui user@headless-device:~/

7.9. Raspberry Pi 5 Notes

The Raspberry Pi 5 is a good fit for running MeshCore GUI headless:

  • Serial: USB serial adapter or direct USB connection to the device
  • BLE: Built-in Bluetooth adapter; works out of the box with BlueZ on Raspberry Pi OS
  • RAM: 2 GB is sufficient; 4 GB or more provides extra headroom for long-running operation
  • OS: Raspberry Pi OS Lite (64-bit, Bookworm) — no desktop environment needed
  • Storage: 16 GB+ SD card or NVMe; the application stores cache and archive data in ~/.meshcore-gui/
  • Power: Low idle power consumption (~5W), suitable for 24/7 operation

Ensure your user has permission to access the serial device (e.g. member of dialout on many Linux distros).

8. Configuration

Setting Location Description
OPERATOR_CALLSIGN meshcore_gui/config.py Operator callsign shown on landing page and drawer footer (default: "PE1HVH")
LANDING_SVG_PATH meshcore_gui/config.py Path to the landing page SVG file; supports {callsign} placeholder (default: static/landing_default.svg)
DEBUG meshcore_gui/config.py Set to True for verbose logging (or use --debug-on)
MAX_CHANNELS meshcore_gui/config.py Maximum channel slots to probe on device (default: 8)
CHANNEL_CACHE_ENABLED meshcore_gui/config.py Cache discovered channels to disk for faster startup (default: False — always fresh from device)
DEFAULT_TIMEOUT meshcore_gui/config.py Default command timeout in seconds (default: 10.0)
MESHCORE_LIB_DEBUG meshcore_gui/config.py Enable meshcore library debug logging (default: True)
SERIAL_BAUDRATE meshcore_gui/config.py Serial baudrate (default: 115200)
SERIAL_CX_DELAY meshcore_gui/config.py Serial connection delay (default: 0.1)
TRANSPORT meshcore_gui/config.py Auto-detected transport mode: "serial" or "ble" (set at startup)
BLE_PIN meshcore_gui/config.py BLE pairing PIN for T1000e devices (default: "123456")
RECONNECT_MAX_RETRIES meshcore_gui/config.py Maximum reconnect attempts after a disconnect (default: 5)
RECONNECT_BASE_DELAY meshcore_gui/config.py Base delay in seconds between reconnect attempts, multiplied by attempt number (default: 5.0)
CONTACT_REFRESH_SECONDS meshcore_gui/config.py Interval between periodic contact refreshes (default: 300s / 5 minutes)
MESSAGE_RETENTION_DAYS meshcore_gui/config.py Retention period for archived messages (default: 30 days)
RXLOG_RETENTION_DAYS meshcore_gui/config.py Retention period for archived RX log entries (default: 7 days)
CONTACT_RETENTION_DAYS meshcore_gui/config.py Retention period for cached contacts (default: 90 days)
KEY_RETRY_INTERVAL meshcore_gui/ble/worker.py Interval between background retry attempts for missing channel keys (default: 30s)
BOT_DEVICE_NAME meshcore_gui/config.py Device name set when bot mode is active (default: ;NL-OV-ZWL-STDSHGN-WKC Bot)
BOT_CHANNELS meshcore_gui/services/bot.py Channel indices the bot listens on
BOT_COOLDOWN_SECONDS meshcore_gui/services/bot.py Minimum seconds between bot replies
BOT_KEYWORDS meshcore_gui/services/bot.py Keyword → reply template mapping
Room passwords ~/.meshcore-gui/room_passwords/<ADDRESS>.json Per-device Room Server passwords (managed via GUI, stored outside repository)
Serial Port CLI argument Device serial port (e.g. /dev/ttyUSB0 or COM3)
BLE Address CLI argument BLE MAC address (e.g. literal:AA:BB:CC:DD:EE:FF)
--port=PORT CLI flag Web server port (default: 8081)
--baud=BAUD CLI flag Serial baudrate (default: 115200)
--serial-cx-dly=SECONDS CLI flag Serial connection delay (default: 0.1)
--ble-pin PIN CLI flag BLE pairing PIN (default: 123456)
--ssl CLI flag Enable HTTPS with auto-generated self-signed certificate
--debug-on CLI flag Enable verbose debug logging

9. Functionality

9.1. Device Info

  • Name, frequency, SF/BW, TX power, location, firmware version

9.2. Contacts

  • List of known nodes with type and location
  • Click on a contact to send a DM (or add a Room Server panel for type=3 contacts)
  • Pin/Unpin: Checkbox per contact to pin it — pinned contacts are sorted to the top and visually marked with a yellow background. Pin state is persisted locally and survives app restart.
  • Individual delete: 🗑️ button per unpinned contact to remove a single contact from the device with confirmation dialog. Pinned contacts are protected.
  • Bulk delete: "🧹 Clean up" button removes all unpinned contacts from the device in one action, with a confirmation dialog showing how many will be removed vs. kept. Optional "Also delete from history" checkbox to clear locally cached data.
  • Auto-add toggle: "📥 Auto-add" checkbox controls whether the device automatically adds new contacts when it receives adverts from other mesh nodes. Disabled by default to prevent the contact list from filling up.

9.3. Map

  • OpenStreetMap with markers for own position and contacts
  • Shows your own position (blue marker)
  • Automatically centers on your own position

9.4. Channel Messages

  • Select a channel in the dropdown
  • Type your message and click "Send"
  • Received messages appear in the messages list
  • Filter messages via the checkboxes

9.5. Direct Messages (DM)

  • Click on a contact in the contacts list
  • A dialog opens where you can type your message
  • Click "Send" to send the DM

9.6. Message Route Visualization

Click on any message in the messages list to open a route page in a new tab. The route page shows:

  • Hop summary — Number of hops and SNR
  • Interactive map — Leaflet map with markers for sender, repeaters and receiver, connected by a polyline showing the message path
  • Route table — Detailed table with each hop: name, ID (first byte of public key), node type and GPS coordinates
  • Reply panel — Pre-filled reply message with route acknowledgement (sender, path length, repeater IDs)

Route data is resolved from two sources (in priority order):

  1. RX log packet decode — Path hashes extracted from the raw LoRa packet via meshcoredecoder
  2. Contact out_path — Stored route from the sender's contact record (fallback)

Route table data (path hashes, resolved repeater names and channel names) is captured at receive time and stored in the archive. This means route tables (names and IDs) remain correct even when contacts are renamed, removed or offline. Sender identity is resolved via pubkey lookup with an automatic name-based fallback when the pubkey lookup fails. Map visualization still depends on live contact GPS data — see 12. Known Limitations.

9.7. Room Server

Room Servers (type=3 contacts) allow group-style messaging via a shared server node in the mesh network.

Adding a Room Server: Click on any Room Server contact (🏠 icon) in the contacts list. A dialog opens where you enter the room password. Click "Add & Login" to create a dedicated room panel and log in.

Room panel features:

  • Each Room Server gets its own card in the centre column below the Messages panel
  • After login: the password field is replaced by a Logout button
  • Messages from the room are displayed in the card with correct author attribution (the real sender, not the room server)
  • Send messages to the room via the input field and Send button
  • Room panels are restored from stored passwords on app restart

How it works under the hood:

  • Login via send_login(pubkey, password) — the Room Server authenticates and starts pushing messages over LoRa RF
  • Messages arrive asynchronously via MESSAGES_WAITING events (event-driven, no polling)
  • Room messages use txt_type=2 (signed), where the signature field contains the 4-byte pubkey prefix of the real author
  • The first message may take 1075 seconds to arrive after login (inherent LoRa RF latency)
  • Passwords are stored in ~/.meshcore-gui/room_passwords/ outside the repository

Note: The Room Server pushes messages round-robin to all logged-in clients. With many clients or large message buffers, it can take several minutes to receive all historical messages.

9.8. Message Archive

All incoming messages and RX log entries are automatically persisted to disk in ~/.meshcore-gui/archive/. One JSON file per data type per device identifier.

Click the 📚 Archive button in the Messages panel header to open the archive viewer in a new tab. The archive viewer provides:

  • Pagination — 50 messages per page, with Previous/Next navigation
  • Channel filter — Filter by specific channel or view all
  • Time range filter — Last 24 hours, 7 days, 30 days, 90 days, or all time
  • Text search — Case-insensitive search in message text
  • Inline route tables — Expandable route display per message (sender, repeaters, receiver with names and IDs)
  • Reply from archive — Expandable reply panel per message with pre-filled @sender mention

Old data is automatically cleaned up based on configurable retention periods (MESSAGE_RETENTION_DAYS, RXLOG_RETENTION_DAYS in config.py).

9.9. Local Cache

Device info, contacts and channel keys are automatically cached to disk in ~/.meshcore-gui/cache/. One JSON file is created per device identifier.

Startup behaviour:

  1. Cache is loaded first — GUI is immediately populated with the last known state
  2. Connection is established in the background (serial or BLE)
  3. Fresh data from the device updates both the GUI and the cache

Channel key loading:

Channel key loading uses a cache-first strategy with device fallback:

  1. Cached keys are loaded first and never overwritten by name-derived fallbacks
  2. Each channel is queried from the device at startup
  3. Channels that fail are retried in the background every 30 seconds
  4. Successfully loaded keys are immediately written to the cache for next startup

Contact merge strategy:

  • New contacts from the device are added to the cache with a last_seen timestamp
  • Existing contacts are updated (fresh data wins)
  • Contacts only in cache (node offline) are preserved

If the connection fails (serial or BLE), the GUI remains usable with cached data and shows an offline status.

9.10. Keyword Bot

The built-in bot automatically replies to messages containing recognised keywords. Enable or disable it via the 🤖 BOT checkbox in the filter bar.

Device name switching: When the BOT checkbox is enabled, the device name is automatically changed to the configured BOT_DEVICE_NAME (default: ;NL-OV-ZWL-STDSHGN-WKC Bot). The original device name is saved and restored when bot mode is disabled. This allows the mesh network to identify the node as a bot by its name.

Default keywords:

Keyword Reply
test <sender>, rcvd | SNR <snr> | path(<hops>); <repeaters>
ping Pong!
help test, ping, help

Safety guards:

  • Only replies on configured channels (BOT_CHANNELS)
  • Ignores own messages and messages from other bots (names ending in "Bot")
  • Cooldown period between replies (default: 5 seconds)

Customisation: Edit BOT_KEYWORDS in meshcore_gui/services/bot.py. Templates support {sender}, {snr} and {path} variables.

9.11. RX Log

  • Received packets with SNR and type

9.12. Actions

  • Refresh data
  • Send advertisement

10. Architecture

┌─────────────────┐     ┌─────────────────┐
│   Main Thread   │     │  Worker Thread  │
│   (NiceGUI)     │     │   (asyncio)     │
│                 │     │                 │
│  ┌───────────┐  │     │  ┌───────────┐  │
│  │ Dashboard │◄─┼──┬──┼─►│  Worker   │  │
│  └───────────┘  │  │  │  │ (Serial   │  │
│        │        │  │  │  │  or BLE)  │  │
│        ▼        │  │  │  └─────┬─────┘  │
│  ┌───────────┐  │  │  │   │Commands │   │
│  │  Timer    │  │  │  │   │Events   │   │
│  │  (500ms)  │  │  │  │   │Decoder  │   │
│  └───────────┘  │  │  │   └────┬────┘   │
│        │        │  │  │        │        │
│  ┌─────┴─────┐  │  │  │   ┌────┴────┐   │
│  │  Panels   │  │  │  │   │   Bot   │   │
│  │  RoutePage│  │  │  │   │  Dedup  │   │
│  │ ArchivePg │  │  │  │   │  Cache  │   │
│  │ RoomSrvPnl│  │  │  │   └─────────┘   │
│  └───────────┘  │  │  │   ┌─────────┐   │
│                 │  │  │   │Reconnect│   │
│                 │  │  │   │  Loop   │   │
│                 │  │  │   └─────────┘   │
└─────────────────┘  │  └─────────────────┘
              ┌──────┴──────┐
              │ SharedData  │     ┌───────────────┐
              │ (thread-    │     │ DeviceCache   │
              │  safe)      │     │ (~/.meshcore- │
              └──────┬──────┘     │  gui/cache/)  │
                     │            └───────────────┘
              ┌──────┴──────┐     ┌───────────────┐
              │ Message     │     │ PinStore      │
              │ Archive     │     │ Contact       │
              │ (~/.meshcore│     │  Cleaner      │
              │ -gui/       │     │ RoomPassword  │
              │  archive/)  │     │  Store        │
              └─────────────┘     └───────────────┘
  • Worker (Serial/BLE): Runs in separate thread with its own asyncio loop. Auto-detected transport: SerialWorker for USB serial, BLEWorker for Bluetooth LE (with PIN agent and bond management). Both share a common base class with disconnect detection, auto-reconnect and background key retry
  • CommandHandler: Executes commands (send message, advert, refresh, purge unpinned, set auto-add, set bot name, restore name, login room, send room msg, remove single contact)
  • EventHandler: Processes incoming device events (messages, RX log) with path hash caching between RX_LOG and fallback handlers, and resolves repeater names at receive time for self-contained archive data
  • PacketDecoder: Decodes raw LoRa packets and extracts route data
  • MeshBot: Keyword-triggered auto-reply on configured channels with automatic device name switching
  • DualDeduplicator: Prevents duplicate messages (hash-based + content-based)
  • DeviceCache: Local JSON cache per device for instant startup and offline resilience
  • MessageArchive: Persistent storage for messages and RX log with configurable retention and automatic cleanup
  • PinStore: Persistent pin state storage per device (JSON-backed)
  • ContactCleanerService: Bulk-delete logic for unpinned contacts with statistics
  • RoomServerPanel: Per-room-server card management with login/logout, message display and send functionality
  • RoomPasswordStore: Persistent Room Server password storage per device in ~/.meshcore-gui/room_passwords/ (JSON-backed, analogous to PinStore)
  • SharedData: Thread-safe data sharing between serial worker and GUI via Protocol interfaces
  • DashboardPage: Main GUI with modular panels (device, contacts, map, messages, etc.)
  • RoutePage: Standalone route visualization page opened per message
  • ArchivePage: Archive viewer with filters, pagination and inline route tables
  • Communication: Via command queue (GUI→worker) and shared state with flags (worker→GUI)

11. Cross-Frequency Bridge

11.1. Bridge Overview

meshcore_bridge is a standalone daemon that connects two MeshCore devices operating on different radio frequencies. It forwards messages on a configurable bridge channel from one device to the other, effectively extending your mesh network across frequency boundaries.

The bridge runs as an independent process, imports the existing meshcore_gui modules (SharedData, Worker, models, config) as a library, and requires zero modifications to the meshcore_gui codebase.

┌───────────────────────────────────────────┐
│           meshcore_bridge daemon           │
│                                           │
│  ┌──────────────┐    ┌────────────────┐   │
│  │ SharedData A │    │  BridgeEngine  │   │
│  │ + Worker A   │◄──►│  (forward &    │   │
│  │ (ttyUSB1)    │    │   dedup)       │   │
│  └──────────────┘    └────────────────┘   │
│  ┌──────────────┐         │               │
│  │ SharedData B │◄────────┘               │
│  │ + Worker B   │                         │
│  │ (ttyUSB2)    │                         │
│  └──────────────┘                         │
│                                           │
│  ┌───────────────────────────────────┐    │
│  │  Bridge Dashboard (NiceGUI :9092) │    │
│  └───────────────────────────────────┘    │
└───────────────────────────────────────────┘

Key properties:

  • Separate process — the bridge runs independently from meshcore_gui; both can run simultaneously on the same host
  • Loop prevention — three mechanisms prevent message loops: direction filter, message hash tracking, and echo suppression
  • Private channels — encrypted channels work transparently because the bridge operates at the plaintext level between firmware decryption and encryption
  • DOMCA dashboard — status page on its own port showing both device connections, bridge statistics and a forwarded message log
  • YAML configuration — all settings in a single bridge_config.yaml file

11.2. Quick Start

# 1. Install the additional dependency
pip install pyyaml

# 2. Edit the configuration
cp bridge_config.yaml bridge_config.yaml.local
nano bridge_config.yaml.local

# 3. Start the bridge
python meshcore_bridge.py --config=bridge_config.yaml.local

# 4. Open the dashboard at http://localhost:9092

Prerequisites: two MeshCore devices connected via USB serial to the same host, with the bridge channel configured on both devices using the same channel secret/password.

11.3. Bridge Configuration

All settings are defined in bridge_config.yaml:

bridge:
  channel_name: "bridge"        # Channel name (for display)
  channel_idx_a: 3              # Channel index on device A
  channel_idx_b: 3              # Channel index on device B
  poll_interval_ms: 200         # Polling interval (ms)
  forward_prefix: true          # Add [sender] prefix to forwarded messages
  max_forwarded_cache: 500      # Loop prevention cache size

device_a:
  port: /dev/ttyUSB1
  baud: 115200
  label: "869.525 MHz"

device_b:
  port: /dev/ttyUSB2
  baud: 115200
  label: "868.000 MHz"

gui:
  port: 9092
  title: "MeshCore Bridge"

CLI options: --config=PATH, --port=PORT, --debug-on, --help.

11.4. systemd Service

Install the bridge as a systemd daemon for production use:

sudo bash install_bridge.sh
sudo nano /etc/meshcore/bridge_config.yaml
sudo systemctl start meshcore-bridge
sudo systemctl enable meshcore-bridge

To uninstall: sudo bash install_bridge.sh --uninstall

For full documentation including architecture details, troubleshooting and assumptions, see BRIDGE.md.

12. Known Limitations

  1. Channel discovery timing — Dynamic channel discovery probes the device at startup; on very slow links (especially BLE), some channels may be missed on first attempt. Channels are retried in the background and cached for subsequent startups when CHANNEL_CACHE_ENABLED = True
  2. Initial load time — GUI waits for device data before the first render is complete (mitigated by cache: if cached data exists, the GUI populates instantly)
  3. Archive route map visualization — Route table names and IDs are now stored at receive time and display correctly regardless of current contacts. However, the route map still depends on GPS coordinates from contacts currently in memory; archived messages without recent contact data may show incomplete map markers
  1. Room Server message latency — Room Server messages travel over LoRa RF and arrive asynchronously (1075 seconds per message). With many logged-in clients, receiving all historical messages can take 10+ minutes due to the round-robin push protocol
  2. BLE Linux only — BLE mode requires Linux with BlueZ and D-Bus. macOS and Windows are not supported for BLE connections because the PIN agent relies on the D-Bus system bus
  3. BlueZ 5.66+ instability — Recent BlueZ versions (shipped with Ubuntu 24.04, Debian Bookworm, Raspberry Pi OS Bookworm) can cause BLE connection instability, pairing failures and unexpected disconnects. USB serial is not affected and is recommended as the most reliable transport

13. Troubleshooting

14.1. Linux

For Linux troubleshooting, start by checking device permissions and that the correct device argument is used.

13.1.1. Serial Quick Fixes

GUI remains empty / serial connection fails
  1. Check the service logs:
    journalctl -u meshcore-gui -n 50 --no-pager
    
  2. Confirm the serial device exists and is readable:
    ls -l /dev/serial/by-id
    
  3. Ensure your user has serial permissions (commonly dialout on Linux):
    sudo usermod -a -G dialout $USER
    # Log out and back in
    
  4. Kill any existing GUI instance and free the port:
    pkill -9 -f meshcore_gui
    sleep 3
    
  5. Restart the GUI:
    python meshcore_gui.py /dev/ttyUSB0
    

13.1.2. BLE Quick Fixes

GUI remains empty / BLE connection fails
  1. Verify Bluetooth is running:

    sudo systemctl status bluetooth
    

    If not running: sudo systemctl start bluetooth

  2. Check that the device is visible:

    bluetoothctl scan on
    

    Look for your device's MAC address. Press Ctrl+C to stop scanning.

  3. Verify the D-Bus policy is installed:

    ls -l /etc/dbus-1/system.d/meshcore-ble.conf
    

    If missing, see 5.1.1. D-Bus Policy for BLE.

  4. Remove stale BLE bond (if the device was previously paired):

    bluetoothctl remove AA:BB:CC:DD:EE:FF
    
  5. Kill any existing GUI instance:

    pkill -9 -f meshcore_gui
    sleep 3
    
  6. Restart the GUI:

    python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on
    

    Check the debug output for D-Bus or pairing errors.

BLE PIN agent errors

If you see org.freedesktop.DBus.Error.AccessDenied in the logs, the D-Bus policy is missing or incorrect. Reinstall it per 5.1.1 and reload D-Bus:

sudo systemctl reload dbus
BLE reconnect issues

If the connection drops and does not recover, the BLE bond may be stale. The application includes automatic bond cleanup and reconnect logic, but in some cases a manual bond removal is needed:

bluetoothctl remove AA:BB:CC:DD:EE:FF
sudo systemctl restart meshcore-gui
BlueZ 5.66+ driver instability

If BLE connections are consistently unreliable (frequent disconnects, pairing loops, authentication errors), the issue is likely caused by changes in BlueZ 5.66+. Check your BlueZ version:

bluetoothctl --version

If the version is 5.66 or higher, you have several options:

  1. Switch to USB serial (recommended) — the most reliable workaround. Connect your device via USB and use serial mode instead:

    python meshcore_gui.py /dev/ttyACM0
    
  2. Downgrade BlueZ — on Debian/Ubuntu, you can pin an older version:

    sudo apt install bluez=5.65-0ubuntu1
    sudo apt-mark hold bluez
    

    Note: exact package versions vary by distribution.

  3. Disable LE Privacy and Secure Connections — in some cases, adding these options to /etc/bluetooth/main.conf can help:

    [General]
    Privacy = off
    
    [LE]
    MinConnectionInterval=6
    MaxConnectionInterval=9
    ConnectionLatency=0
    

    Restart Bluetooth after editing: sudo systemctl restart bluetooth

14.2. macOS

  • Ensure the device shows up under /dev/tty.usb*, /dev/tty.usbserial*, or /dev/tty.usbmodem*
  • Close any other app that might be using the serial port

13.3. Windows

  • Confirm the COM port in Device Manager → Ports (COM & LPT)
  • Close any other app that might be using the COM port

13.4. All Platforms

13.4.1. Device Not Found

Serial: Make sure the MeshCore device is powered on, running Serial Companion firmware, and the correct serial port is selected.

BLE: Ensure the device is powered on and discoverable (bluetoothctl scan on). Check that the MAC address is correct and that the BLE PIN matches (default: 123456). On Linux, verify D-Bus permissions — see docs/ble/BLE_ARCHITECTURE.md for details.

13.4.2. Messages Not Arriving

  • Check if your channels are correctly configured
  • Use meshcli to verify that messages are arriving

13.4.3. Clearing the Cache

If cached data causes issues (e.g. stale contacts), delete the cache file:

rm ~/.meshcore-gui/cache/*.json

The cache will be recreated on the next successful serial connection.

14. Development

14.1. Debug Mode

Enable via command line flag:

python meshcore_gui.py /dev/ttyUSB0 --debug-on

Or set DEBUG = True in meshcore_gui/config.py.

Debug output is written to both stdout and a per-device rotating log file at ~/.meshcore-gui/logs/<ADDRESS>_meshcore_gui.log (e.g. F0_9E_9E_75_A3_01_meshcore_gui.log).

14.2. Project Structure

meshcore-gui/
├── meshcore_gui.py                  # Entry point (auto-detects Serial or BLE)
├── install_ble_stable.sh            # BLE installer (systemd service for BLE connections)
├── install_serial.sh                # Serial installer (systemd service for serial connections)
├── meshcore_gui/                    # Application package
│   ├── __init__.py
│   ├── __main__.py                  # Alternative entry: python -m meshcore_gui
│   ├── config.py                    # OPERATOR_CALLSIGN, LANDING_SVG_PATH, DEBUG flag, channel discovery settings (MAX_CHANNELS, CHANNEL_CACHE_ENABLED), SERIAL_* defaults, BLE_PIN, TRANSPORT mode, RECONNECT_* settings, refresh interval, retention settings, BOT_DEVICE_NAME, per-device log file naming
│   ├── ble/                         # Connection layer (serial + BLE transport)
│   │   ├── __init__.py
│   │   ├── worker.py                # _BaseWorker + SerialWorker + BLEWorker + create_worker() factory; thread lifecycle, cache-first startup, disconnect detection, auto-reconnect, background key retry
│   │   ├── ble_agent.py             # BlueZ D-Bus PIN agent for BLE pairing (Linux only, lazy-loaded)
│   │   ├── ble_reconnect.py         # BLE bond cleanup and reconnect loop via D-Bus (lazy-loaded)
│   │   ├── commands.py              # Command execution (send, refresh, advert)
│   │   ├── events.py                # Event callbacks (messages, RX log) with path hash caching and name resolution at receive time
│   │   └── packet_decoder.py        # Raw LoRa packet decoding via meshcoredecoder
│   ├── core/                        # Domain models and shared state
│   │   ├── __init__.py
│   │   ├── models.py                # Dataclasses: Message, Contact, DeviceInfo, RxLogEntry, RouteNode
│   │   ├── shared_data.py           # Thread-safe shared data store
│   │   └── protocols.py             # Protocol interfaces (ISP/DIP)
│   ├── gui/                         # NiceGUI web interface
│   │   ├── __init__.py
│   │   ├── constants.py             # UI display constants
│   │   ├── dashboard.py             # Main dashboard page orchestrator, loads landing SVG from config.LANDING_SVG_PATH
│   │   ├── route_page.py            # Message route visualization page
│   │   ├── archive_page.py          # Message archive viewer with filters and pagination
│   │   └── panels/                  # Modular UI panels
│   │       ├── __init__.py
│   │       ├── device_panel.py      # Device info display
│   │       ├── contacts_panel.py    # Contacts list with DM, pin/unpin, bulk delete, auto-add toggle
│   │       ├── map_panel.py         # Leaflet map
│   │       ├── input_panel.py       # Message input and channel select
│   │       ├── filter_panel.py      # Channel filters and bot toggle
│   │       ├── messages_panel.py    # Filtered message display with archive button
│   │       ├── actions_panel.py     # Refresh and advert buttons
│   │       ├── room_server_panel.py # Per-room-server card with login/logout and messages
│   │       └── rxlog_panel.py       # RX log table
│   └── services/                    # Business logic
│       ├── __init__.py
│       ├── bot.py                   # Keyword-triggered auto-reply bot
│       ├── cache.py                 # Local JSON cache per device
│       ├── contact_cleaner.py       # Bulk-delete logic for unpinned contacts
│       ├── dedup.py                 # Message deduplication
│       ├── message_archive.py       # Persistent message and RX log archive
│       ├── pin_store.py             # Persistent pin state storage per device
│       ├── room_password_store.py   # Persistent Room Server password storage per device
│       └── route_builder.py         # Route data construction
├── docs/
│   ├── TROUBLESHOOTING.md           # BLE troubleshooting guide (detailed)
│   ├── MeshCore_GUI_Design.docx     # Design document
│   ├── ble_capture_workflow_t_1000_e_explanation.md
│   └── ble_capture_workflow_t_1000_e_uitleg.md
├── meshcore_bridge.py               # Bridge entry point
├── meshcore_bridge/                  # Bridge daemon package
│   ├── __init__.py
│   ├── __main__.py                  # CLI, dual-worker setup, NiceGUI server
│   ├── config.py                    # YAML config loading (BridgeConfig dataclass)
│   ├── bridge_engine.py             # Core bridge logic: poll, forward, dedup, loop prevention
│   └── gui/                         # Bridge dashboard (DOMCA themed)
│       ├── __init__.py
│       ├── dashboard.py             # Bridge status dashboard page
│       └── panels/
│           ├── __init__.py
│           ├── status_panel.py      # Device A/B connection status + statistics
│           └── log_panel.py         # Forwarded message log
├── bridge_config.yaml               # Bridge configuration template (YAML)
├── install_bridge.sh                # Bridge systemd service installer
├── BRIDGE.md                        # Bridge documentation
├── .gitattributes
├── .gitignore
├── LICENSE
├── CHANGELOG.md
└── README.md

15. BBS — Bulletin Board System

MeshCore GUI includes an offline BBS that lets mesh nodes exchange structured messages by category, with optional region tagging.

Toegangsmodel

De beheerder koppelt één of meer channels aan het BBS. Iedereen die op zo'n channel een bericht stuurt wordt automatisch gewhitelist. Daarna kunnen zij commando's sturen via Direct Message aan de BBS-node — het channel zelf blijft schoon.

Eerste contact:  !bbs help  op het channel
                 → node ziet de public key → whitelist
Daarna:          !p U hulp nodig  als DM naar de node
                 → verwerkt, reply via DM terug

Wie nooit iets heeft gestuurd op een geconfigureerd channel staat niet op de whitelist en wordt silently genegeerd.

Settings

Open via het tandwiel (⚙) in het BBS-panel, of navigeer naar /bbs-settings.

BBS Settings
──────────────────────────────────────────
Channels:    ☑ [1] NoodNet Zwolle
             ☑ [2] NoodNet Dalfsen
             ☐ [3] NoodNet OV
Categories:  URGENT, MEDICAL, LOGISTICS, STATUS, GENERAL
Retain:      48 hours
[Save]

▶ Advanced
  Regions (comma-separated)
  Allowed keys (leeg = auto-geleerd via channel-activiteit)
  • Channels — vink alle channels aan waarvan deelnemers toegang krijgen tot het BBS.
  • Categories — komma-gescheiden lijst van geldige categorie-tags.
  • Retain — berichtretentie in uren (standaard 48).
  • Advanced → Regions — optionele regio-tags voor geografische filtering.
  • Advanced → Allowed keys — handmatige whitelist-override; leeg laten om alleen automatisch te leren.

Commando-syntax

Korte syntax

Commando Beschrijving
!p <cat> <tekst> Bericht posten
!p <regio> <cat> <tekst> Posten met regio
!r Laatste 5 berichten lezen (alle categorieën)
!r <cat> Lezen gefilterd op categorie
!r <regio> <cat> Lezen gefilterd op regio en categorie

Categorie-afkortingen worden automatisch berekend als de kortste unieke prefix. Voorbeeld met URGENT, MEDICAL, LOGISTICS, STATUS, GENERAL:

U=URGENT  M=MEDICAL  L=LOGISTICS  S=STATUS  G=GENERAL

!r zonder argumenten en !bbs help geven altijd de afkortingstabel mee.

Volledige syntax

Commando Beschrijving
!bbs help Toon commando's en afkortingstabel
!bbs post <category> <tekst> Bericht posten
!bbs post <regio> <category> <tekst> Posten met regio
!bbs read Laatste 5 berichten
!bbs read <category> Gefilterd op categorie
!bbs read <regio> <category> Gefilterd op regio en categorie

Voorbeeld help-reply

BBS [NoodNet Zwolle, NoodNet Dalfsen] | !p [cat] [text] | !r [cat] | U=URGENT M=MEDICAL L=LOGISTICS S=STATUS G=GENERAL

Foutafhandeling

Situatie Reply
Onbekende categorie Lijst met geldige categorieën en afkortingen
Ambigue afkorting Lijst met overeenkomende categorieën
Sender niet op whitelist Silent drop — geen reply

Storage

~/.meshcore-gui/bbs/bbs_messages.db    — SQLite berichtenopslag (WAL-mode)
~/.meshcore-gui/bbs/bbs_config.json    — Board-configuratie

16. Roadmap

This project is under active development. The most common features from the official MeshCore Companion apps are being implemented gradually. Planned additions include:

  • Cross-frequency bridge — standalone daemon connecting two devices on different frequencies via configurable channel forwarding (see 11. Cross-Frequency Bridge)
  • BBS — Bulletin Board System — offline message board with DM-based commands, category/region filtering and automatic abbreviations (see 15. BBS)
  • Observer mode — passively monitor mesh traffic without transmitting, useful for network analysis, coverage mapping and long-term logging
  • Room Server administration — authenticate as admin to manage Room Server settings and users directly from the GUI
  • Repeater management — connect to repeater nodes to view status and adjust configuration

Have a feature request or want to contribute? Open an issue or submit a pull request.

16. Disclaimer

This is an independent community project and is not affiliated with or endorsed by the official MeshCore development team. It is built on top of the open-source meshcore Python library.

17. License

MIT License - see LICENSE file

18. Author

PE1HVHGitHub

19. Acknowledgments

Languages
Python 91.9%
Shell 5%
JavaScript 2.9%
CSS 0.2%