diff --git a/README.md b/README.md
index 5f3a1af..ef661b0 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,6 @@
# MeshCore GUI
-
-> ⚠️ **This branch is in active development and testing. It is not production-ready. Use at your own risk. **
-
+
+



@@ -16,27 +15,32 @@ This project provides a **native desktop GUI** that connects to your MeshCore de
> **Note:** This application has only been tested on Linux (Ubuntu 24.04). macOS and Windows should work since all dependencies (`bleak`, `nicegui`, `meshcore`) are cross-platform, but this has not been verified. Feedback and contributions for other platforms are welcome.
-Under the hood it uses `bleak` for Bluetooth Low Energy (which talks to BlueZ on Linux, CoreBluetooth on macOS, and WinRT on Windows), `meshcore` as the protocol layer, and `NiceGUI` for the web-based interface.
+Under the hood it uses `bleak` for Bluetooth Low Energy (which talks to BlueZ on Linux, CoreBluetooth on macOS, and WinRT on Windows), `meshcore` as the protocol layer, `meshcoredecoder` for raw LoRa packet decryption and route extraction, and `NiceGUI` for the web-based interface.
> **Linux users:** BLE on Linux can be temperamental. BlueZ occasionally gets into a bad state, especially after repeated connect/disconnect cycles. If you run into connection issues, see the [Troubleshooting Guide](docs/TROUBLESHOOTING.md). On macOS and Windows, BLE is generally more stable out of the box.
## TODO
+
* **Message persistence** — Store sent and received messages to disk so chat history is preserved across sessions
* **Automatic channel discovery** — Robustly detect and subscribe to available channels without manual configuration
* **Auto-detect BLE address** — Automatically discover and store the BLE device address in config, eliminating manual entry
+
## 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
-- **Message Filtering** - Filter messages per channel via checkboxes
-- **Threaded Architecture** - BLE communication in separate thread for stable UI
+- **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
+- **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
+- **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
+- **Threaded Architecture** — BLE communication in separate thread for stable UI
## Screenshots
-
-
-
+
+
## Requirements
@@ -97,7 +101,7 @@ venv\Scripts\activate
### 4. Install Python packages
```bash
-pip install nicegui meshcore bleak
+pip install nicegui meshcore bleak meshcoredecoder
```
## Usage
@@ -169,17 +173,27 @@ python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF
Replace `literal:AA:BB:CC:DD:EE:FF` with the MAC address of your device.
+For verbose debug logging:
+
+```bash
+python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on
+```
+
### 5. Open the interface
The GUI opens automatically in your browser at `http://localhost:8080`
## Configuration
-| Setting | Description |
-|---------|-------------|
-| `DEBUG` | Set to `True` for verbose logging |
-| `CHANNELS_CONFIG` | List of channels (hardcoded due to BLE timing issues) |
-| BLE Address | Command line argument |
+| Setting | Location | Description |
+|---------|----------|-------------|
+| `DEBUG` | `meshcore_gui/config.py` | Set to `True` for verbose logging (or use `--debug-on`) |
+| `CHANNELS_CONFIG` | `meshcore_gui/config.py` | List of channels (hardcoded due to BLE timing issues) |
+| `BOT_CHANNELS` | `meshcore_gui/services/bot.py` | Channel indices the bot listens on |
+| `BOT_NAME` | `meshcore_gui/services/bot.py` | Display name prepended to bot replies |
+| `BOT_COOLDOWN_SECONDS` | `meshcore_gui/services/bot.py` | Minimum seconds between bot replies |
+| `BOT_KEYWORDS` | `meshcore_gui/services/bot.py` | Keyword → reply template mapping |
+| BLE Address | Command line argument | |
## Functionality
@@ -206,6 +220,38 @@ The GUI opens automatically in your browser at `http://localhost:8080`
- A dialog opens where you can type your message
- Click "Send" to send the DM
+### 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)
+
+### 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.
+
+**Default keywords:**
+
+| Keyword | Reply |
+|---------|-------|
+| `test` | `Zwolle Bot: , rcvd \| SNR \| path(); ` |
+| `ping` | `Zwolle Bot: Pong!` |
+| `help` | `Zwolle Bot: 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 `{bot}`, `{sender}`, `{snr}` and `{path}` variables.
+
### RX Log
- Received packets with SNR and type
@@ -221,14 +267,19 @@ The GUI opens automatically in your browser at `http://localhost:8080`
│ (NiceGUI) │ │ (asyncio) │
│ │ │ │
│ ┌───────────┐ │ │ ┌───────────┐ │
-│ │ GUI │◄─┼──┬──┼─►│ BLEWorker │ │
-│ └───────────┘ │ │ │ └───────────┘ │
+│ │ Dashboard │◄─┼──┬──┼─►│ BLEWorker │ │
+│ └───────────┘ │ │ │ └─────┬─────┘ │
│ │ │ │ │ │ │
-│ ▼ │ │ │ ▼ │
-│ ┌───────────┐ │ │ │ ┌───────────┐ │
-│ │ Timer │ │ │ │ │ MeshCore │ │
-│ │ (500ms) │ │ │ │ │ BLE │ │
-│ └───────────┘ │ │ │ └───────────┘ │
+│ ▼ │ │ │ ┌────┴────┐ │
+│ ┌───────────┐ │ │ │ │Commands │ │
+│ │ Timer │ │ │ │ │Events │ │
+│ │ (500ms) │ │ │ │ │Decoder │ │
+│ └───────────┘ │ │ │ └────┬────┘ │
+│ │ │ │ │ │ │
+│ ┌─────┴─────┐ │ │ │ ┌────┴────┐ │
+│ │ Panels │ │ │ │ │ Bot │ │
+│ │ RoutePage│ │ │ │ │ Dedup │ │
+│ └───────────┘ │ │ │ └─────────┘ │
└─────────────────┘ │ └─────────────────┘
│
┌──────┴──────┐
@@ -239,15 +290,21 @@ The GUI opens automatically in your browser at `http://localhost:8080`
```
- **BLEWorker**: Runs in separate thread with its own asyncio loop
-- **SharedData**: Thread-safe data sharing between BLE and GUI
-- **MeshCoreGUI**: NiceGUI interface in main thread
-- **Communication**: Via queue (GUI→BLE) and shared state with flags (BLE→GUI)
+- **CommandHandler**: Executes commands (send message, advert, refresh)
+- **EventHandler**: Processes incoming BLE events (messages, RX log)
+- **PacketDecoder**: Decodes raw LoRa packets and extracts route data
+- **MeshBot**: Keyword-triggered auto-reply on configured channels
+- **DualDeduplicator**: Prevents duplicate messages (hash-based + content-based)
+- **SharedData**: Thread-safe data sharing between BLE and GUI via Protocol interfaces
+- **DashboardPage**: Main GUI with modular panels (device, contacts, map, messages, etc.)
+- **RoutePage**: Standalone route visualization page opened per message
+- **Communication**: Via command queue (GUI→BLE) and shared state with flags (BLE→GUI)
## Known Limitations
-1. **Channels hardcoded** - The `get_channel()` function in meshcore-py is unreliable via BLE
-2. **send_appstart() sometimes fails** - Device info may remain empty with connection problems
-3. **Initial load time** - GUI waits for BLE data before the first render is complete
+1. **Channels hardcoded** — The `get_channel()` function in meshcore-py is unreliable via BLE
+2. **send_appstart() sometimes fails** — Device info may remain empty with connection problems
+3. **Initial load time** — GUI waits for BLE data before the first render is complete
## Troubleshooting
@@ -305,12 +362,14 @@ Make sure the MeshCore device is powered on and in BLE Companion mode. Run the B
### Debug mode
-Set `DEBUG = True` in the script for verbose logging:
+Enable via command line flag:
-```python
-DEBUG = True
+```bash
+python meshcore_gui.py literal:AA:BB:CC:DD:EE:FF --debug-on
```
+Or set `DEBUG = True` in `meshcore_gui/config.py`.
+
### Project structure
```
@@ -318,17 +377,42 @@ meshcore-gui/
├── meshcore_gui.py # Entry point
├── meshcore_gui/ # Application package
│ ├── __init__.py
-│ ├── ble_worker.py
-│ ├── config.py
-│ ├── main_page.py
-│ ├── protocols.py
-│ ├── route_builder.py
-│ ├── route_page.py
-│ └── shared_data.py
+│ ├── __main__.py # Alternative entry: python -m meshcore_gui
+│ ├── config.py # DEBUG flag, channel configuration
+│ ├── ble/ # BLE communication layer
+│ │ ├── __init__.py
+│ │ ├── worker.py # BLE thread, connection lifecycle
+│ │ ├── commands.py # Command execution (send, refresh, advert)
+│ │ ├── events.py # Event callbacks (messages, RX log)
+│ │ └── packet_decoder.py # Raw LoRa packet decoding via meshcoredecoder
+│ ├── core/ # Domain models and shared state
+│ │ ├── __init__.py
+│ │ ├── models.py # Dataclasses: Message, Contact, RouteNode, etc.
+│ │ ├── 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
+│ │ ├── route_page.py # Message route visualization page
+│ │ └── panels/ # Modular UI panels
+│ │ ├── __init__.py
+│ │ ├── device_panel.py # Device info display
+│ │ ├── contacts_panel.py # Contacts list with DM support
+│ │ ├── 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
+│ │ ├── actions_panel.py # Refresh and advert buttons
+│ │ └── rxlog_panel.py # RX log table
+│ └── services/ # Business logic
+│ ├── __init__.py
+│ ├── bot.py # Keyword-triggered auto-reply bot
+│ ├── dedup.py # Message deduplication
+│ └── route_builder.py # Route data construction
├── docs/
-│ ├── SOLID_ANALYSIS.md
-│ ├── TROUBLESHOOTING.md
-│ ├── MeshCore_GUI_Design.docx
+│ ├── TROUBLESHOOTING.md # BLE troubleshooting guide (Linux)
+│ ├── MeshCore_GUI_Design.docx # Design document
│ ├── ble_capture_workflow_t_1000_e_explanation.md
│ └── ble_capture_workflow_t_1000_e_uitleg.md
├── .gitattributes
@@ -337,8 +421,6 @@ meshcore-gui/
└── README.md
```
-For a SOLID principles analysis of the project structure, see [SOLID_ANALYSIS.md](docs/SOLID_ANALYSIS.md).
-
## Disclaimer
This is an **independent community project** and is not affiliated with or endorsed by the official [MeshCore](https://github.com/meshcore-dev) development team. It is built on top of the open-source `meshcore` Python library and `bleak` BLE library.
@@ -349,12 +431,13 @@ MIT License - see LICENSE file
## Author
-**PE1HVH** - [GitHub](https://github.com/pe1hvh)
+**PE1HVH** — [GitHub](https://github.com/pe1hvh)
## Acknowledgments
-- [MeshCore](https://github.com/meshcore-dev) - Mesh networking firmware and protocol
-- [meshcore_py](https://github.com/meshcore-dev/meshcore_py) - Python bindings for MeshCore
-- [meshcore-cli](https://github.com/meshcore-dev/meshcore-cli) - Command line interface
-- [NiceGUI](https://nicegui.io/) - Python GUI framework
-- [Bleak](https://github.com/hbldh/bleak) - Cross-platform Bluetooth Low Energy library
+- [MeshCore](https://github.com/meshcore-dev) — Mesh networking firmware and protocol
+- [meshcore_py](https://github.com/meshcore-dev/meshcore_py) — Python bindings for MeshCore
+- [meshcore-cli](https://github.com/meshcore-dev/meshcore-cli) — Command line interface
+- [meshcoredecoder](https://github.com/meshcore-dev/meshcoredecoder) — LoRa packet decoder and channel crypto
+- [NiceGUI](https://nicegui.io/) — Python GUI framework
+- [Bleak](https://github.com/hbldh/bleak) — Cross-platform Bluetooth Low Energy library