- Python 72.5%
- HTML 15.8%
- JavaScript 9.7%
- Shell 1.6%
- Nix 0.4%
- backup_database.py: SQLite-Backup ersetzt durch pg_dump - services_api.py: tote _get_telemetry_db_path/_telemetry_db_ready entfernt, _get_telemetry_db vereinfacht - channel_manager, message_handler, integration: lokale pg_adapter-Imports nach oben verschoben Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|---|---|---|
| .github/workflows | ||
| configs | ||
| docs | ||
| modules | ||
| nix | ||
| scripts | ||
| tests | ||
| translations | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| backup_database.py | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| com.meshcore.bot.plist | ||
| config.hbmesh.ini | ||
| config.ini | ||
| docker-compose.yml | ||
| docker-setup.sh | ||
| Dockerfile | ||
| fix-serial-device.sh | ||
| flake.lock | ||
| flake.nix | ||
| generate_website.py | ||
| install-service.sh | ||
| meshcore-bot.service | ||
| meshcore_bot.py | ||
| migrate_webviewer_db.py | ||
| mkdocs.yml | ||
| pyproject.toml | ||
| pytest.ini | ||
| README.md | ||
| requirements.txt | ||
| restart_viewer.sh | ||
| uninstall-service.sh | ||
| validate_config.py | ||
MeshCore Bot
A Python bot that connects to MeshCore mesh networks via serial port, BLE, or TCP/IP. The bot responds to messages containing configured keywords, executes commands, and provides various data services including weather, solar conditions, and satellite pass information.
This is the BreMesh fork — maintained by Bartzi with additional features for packet analysis, MQTT Decryption, and HBME-BIA integration. See Fork Changes below.
Features
- Connection Methods: Serial port, BLE (Bluetooth Low Energy), or TCP/IP
- Keyword Responses: Configurable keyword-response pairs with template variables
- Command System: Plugin-based command architecture with built-in commands
- Rate Limiting: Global, per-user (by pubkey or name), and bot transmission rate limits to prevent spam
- User Management: Ban/unban users with persistent storage
- Scheduled Messages: Send messages at configured times
- Direct Message Support: Respond to private messages
- Logging: Console and file logging with configurable levels
Service Plugins
- Packet Capture: Capture and publish packets to MQTT brokers with deep payload decoding (docs)
- HBME Ingestor: Forward packets to the HBME API for centralized mesh analysis (docs)
- Map Uploader(wtf why?): Upload node adverts to map.meshcore.dev (docs)
- Telemetry Monitor: Poll repeater battery/environment data via MQTT with web UI (docs)
- Weather Service: Scheduled forecasts, alerts, and lightning detection (docs)
Requirements
- Python 3.7+
- MeshCore-compatible device (Heltec V3, RAK Wireless, etc.)
- USB cable or BLE capability
Installation
Quick Start (Development)
- Clone the repository:
git clone <repository-url>
cd meshcore-bot
- Install dependencies:
pip install -r requirements.txt
- Copy and configure the bot:
BreMesh Configuration: Copy the pre-configured BreMesh config as your starting point:
cp config.hbmesh.ini config.ini
# Edit config.ini with your settings
- Run the bot:
python3 meshcore_bot.py
Production Installation (Systemd Service)
For production deployment as a system service:
- Install as systemd service:
sudo ./install-service.sh
- Configure the bot:
sudo nano /opt/meshcore-bot/config.ini
- Start the service:
sudo systemctl start meshcore-bot
- Check status:
sudo systemctl status meshcore-bot
See Service installation for detailed service installation instructions.
Docker Deployment
For containerized deployment using Docker:
-
Create data directories and configuration:
mkdir -p data/{config,databases,logs,backups} cp config.ini.example data/config/config.ini # Edit data/config/config.ini with your settings -
Update paths in config.ini to use
/data/directories:[Bot] db_path = /data/databases/meshcore_bot.db [Logging] log_file = /data/logs/meshcore_bot.log -
Build and start with Docker Compose:
docker compose build docker compose up -dOr build and start in one command:
docker compose up -d --build -
View logs:
docker-compose logs -f
See Docker deployment for detailed Docker deployment instructions, including serial port access, web viewer configuration, and troubleshooting.
NixOS
Use the Nix flake via flake.nix
meshcore-bot.url = "github:agessaman/meshcore-bot/";
And in your system config
{
imports = [inputs.meshcore-bot.nixosModules.default];
services.meshcore-bot = {
enable = true;
webviewer.enable = true;
settings = {
Connection.connection_type = "serial";
Connection.serial_port = "/dev/ttyUSB0";
Bot.bot_name = "MyBot";
};
};
}
Configuration
The bot uses config.ini for all settings. Key configuration sections:
Connection
[Connection]
connection_type = serial # serial, ble, or tcp
serial_port = /dev/ttyUSB0 # Serial port path (for serial)
#hostname = 192.168.1.60 # TCP hostname/IP (for TCP)
#tcp_port = 5000 # TCP port (for TCP)
#ble_device_name = MeshCore # BLE device name (for BLE)
timeout = 30 # Connection timeout
Bot Settings
[Bot]
bot_name = MeshCoreBot # Bot identification name
enabled = true # Enable/disable bot
rate_limit_seconds = 2 # Global: min seconds between any bot reply
bot_tx_rate_limit_seconds = 1.0 # Min seconds between bot transmissions
per_user_rate_limit_seconds = 5 # Per-user: min seconds between replies to same user (pubkey or name)
per_user_rate_limit_enabled = true
startup_advert = flood # Send advert on startup
Keywords
[Keywords]
# Format: keyword = response_template
# Variables: {sender}, {connection_info}, {snr}, {timestamp}, {path}
test = "Message received from {sender} | {connection_info}"
help = "Bot Help: test, ping, help, hello, cmd, wx, aqi, sun, moon, solar, hfcond, satpass, dice, roll, joke, dadjoke, sports, channels, path, prefix, repeater, stats, alert"
Channels
[Channels]
monitor_channels = general,test,emergency # Channels to monitor
respond_to_dms = true # Enable DM responses
# Optional: limit channel responses to certain keywords (DM gets all triggers)
# channel_keywords = help,ping,test,hello
External Data APIs
[External_Data]
# API keys for external services
n2yo_api_key = # Satellite pass data
airnow_api_key = # Air quality data
Alert Command
[Alert_Command]
enabled = true # Enable/disable alert command
max_incident_age_hours = 24 # Maximum age for incidents (hours)
max_distance_km = 20.0 # Maximum distance for proximity queries (km)
agency.city.<city_name> = <agency_ids> # City-specific agency IDs (e.g., agency.city.seattle = 17D20,17M15)
agency.county.<county_name> = <agency_ids> # County-specific agency IDs (aggregates all city agencies)
Logging
[Logging]
log_level = INFO # DEBUG, INFO, WARNING, ERROR, CRITICAL
log_file = meshcore_bot.log # Log file path
colored_output = true # Enable colored console output
Usage
Running the Bot
python meshcore_bot.py
Available Commands
For a comprehensive list of all available commands with examples and detailed explanations, see Command reference.
Quick reference:
- Basic:
test,ping,help,hello,cmd - Information:
wx,gwx,aqi,sun,moon,solar,solarforecast,hfcond,satpass,channels - Emergency:
alert - Gaming:
dice,roll,magic8 - Entertainment:
joke,dadjoke,hacker,catfact - Sports:
sports - MeshCore Utility:
path,prefix,stats,multitest,webviewer - Management (DM only):
repeater,advert,feed,announcements,greeter
Message Response Templates
Keyword responses support these template variables:
{sender}- Sender's node ID{connection_info}- Connection details (direct/routed){snr}- Signal-to-noise ratio{timestamp}- Message timestamp{path}- Message routing path
Adding Newlines
To add newlines in keyword responses, use \n (single backslash + n):
[Keywords]
test = "Line 1\nLine 2\nLine 3"
This will output:
Line 1
Line 2
Line 3
To use a literal backslash + n, use \\n (double backslash + n).
Other escape sequences: \t (tab), \r (carriage return), \\ (literal backslash)
Example:
[Keywords]
test = "Message received from {sender} | {connection_info}"
ping = "Pong!"
help = "Bot Help: test, ping, help, hello, cmd, wx, gwx, aqi, sun, moon, solar, solarforecast, hfcond, satpass, dice, roll, joke, dadjoke, sports, channels, path, prefix, repeater, stats, multitest, alert, webviewer"
Hardware Setup
Serial Connection
- Flash MeshCore firmware to your device
- Connect via USB
- Configure serial port in
config.ini:[Connection] connection_type = serial serial_port = /dev/ttyUSB0 # Linux # serial_port = COM3 # Windows # serial_port = /dev/tty.usbserial-* # macOS
BLE Connection
- Ensure your MeshCore device supports BLE
- Configure BLE in
config.ini:[Connection] connection_type = ble ble_device_name = MeshCore
TCP Connection
- Ensure your MeshCore device has TCP/IP connectivity (e.g., via gateway or bridge)
- Configure TCP in
config.ini:[Connection] connection_type = tcp hostname = 192.168.1.60 # IP address or hostname tcp_port = 5000 # TCP port (default: 5000)
Troubleshooting
Common Issues
-
Serial Port Not Found:
- Check device connection
- Verify port name in config
- List available ports:
python -c "import serial.tools.list_ports; print([p.device for p in serial.tools.list_ports.comports()])"
-
BLE Connection Issues:
- Ensure device is discoverable
- Check device name in config
- Verify BLE permissions
-
TCP Connection Issues:
- Verify hostname/IP address is correct
- Check that TCP port is open and accessible
- Ensure network connectivity to the device
- Verify the MeshCore device supports TCP connections
- Check firewall settings if connection fails
-
Message Parsing Errors:
- Enable DEBUG logging for detailed information
- Check meshcore library documentation for protocol details
-
Rate Limiting:
- Global:
rate_limit_seconds— minimum time between any two bot replies - Per-user:
per_user_rate_limit_secondsandper_user_rate_limit_enabled— minimum time between replies to the same user (user identified by public key when available, else sender name; channel senders often matched by name) - Bot TX:
bot_tx_rate_limit_seconds— minimum time between bot transmissions on the mesh - Check logs for rate limiting messages
- Global:
Debug Mode
Enable debug logging:
[Logging]
log_level = DEBUG
Architecture
The bot uses a modular plugin architecture:
- Core modules (
modules/): Shared utilities and core functionality - Command plugins (
modules/commands/): Individual command implementations - Service plugins (
modules/service_plugins/): Background services (packet capture, HBME ingestor, weather, telemetry, etc.) - Plugin loaders: Dynamic discovery and loading of command and service plugins
- Message handler: Processes incoming messages and routes to appropriate handlers
Adding New Plugins
Command Plugin:
- Create a new file in
modules/commands/ - Inherit from
BaseCommand - Implement the
execute()method - The plugin loader will automatically discover and load it
from .base_command import BaseCommand
from ..models import MeshMessage
class MyCommand(BaseCommand):
name = "mycommand"
keywords = ['mycommand']
description = "My custom command"
async def execute(self, message: MeshMessage) -> bool:
await self.send_response(message, "Hello from my command!")
return True
Service Plugin:
- Create a new file in
modules/service_plugins/ - Inherit from
BaseServicePlugin - Implement
start()andstop()methods - Add configuration section to
config.ini.example
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request against the dev branch
License
This project is licensed under the MIT License.
BreMesh Fork Changes
This fork adds the following features on top of upstream meshcore-bot:
Enriched MQTT Payloads (Packet Capture)
Every packet published to MQTT now includes a decoded field with structured, human-readable data extracted from the raw packet bytes:
- Header: route type, payload type, version, path nodes
- ADVERT: public key, device name, role (Companion/Repeater/RoomServer/Sensor), GPS coordinates, advert timestamp
- TXT_MSG: decoded plain text content
- GRP_TXT: decrypted channel messages for public hashtag channels (AES-128-ECB + HMAC verification)
- ACK: ack hash
- REQ/RESPONSE/PATH/TRACE: payload size summaries
Example decoded MQTT message:
{
"origin": "6EF10422",
"SNR": "13.5",
"RSSI": "-51",
"decoded": {
"route_type_name": "FLOOD",
"payload_type_name": "GRP_TXT",
"path_nodes": ["ef", "fc", "17", "b0"],
"group_text": {
"encrypted": false,
"channel_name": "#ping",
"sender": "Ritter Fips",
"message": "ping",
"timestamp_iso": "2026-03-01T19:09:00Z"
}
}
}
See Packet Capture docs for configuration.
MQTT Subscribe: Nachrichten ins Mesh senden
Der Bot kann Nachrichten via MQTT empfangen und ins Mesh-Netzwerk senden. So lässt sich der Bot z.B. aus Node-RED, Home Assistant oder eigenen Skripten steuern.
Konfiguration in config.ini unter [PacketCapture]:
mqtt_subscribe_enabled = true
mqtt1_topic_send_dm = meshcore/send/dm
mqtt1_topic_send_channel = meshcore/send/channel
DM senden (Topic: meshcore/send/dm):
{"destination": "NodeName", "message": "Hallo!"}
Channel-Nachricht senden (Topic: meshcore/send/channel):
{"channel": "#ping", "message": "Pong! Test via MQTT"}
Test via Kommandozeile:
# Channel-Nachricht
mosquitto_pub -h localhost -t meshcore/send/channel -m '{"channel": "#ping", "message": "Test via MQTT"}'
# Direktnachricht
mosquitto_pub -h localhost -t meshcore/send/dm -m '{"destination": "MeinNode", "message": "Hallo!"}'
Node-RED Demo Flows
Die folgenden Flows zeigen, wie man den Bot aus Node-RED heraus steuert. Importiere sie über Menu → Import → Clipboard in Node-RED.
Flow 1: Channel-Nachricht senden (Inject → MQTT)
Sendet eine Nachricht auf einen MeshCore-Channel per Knopfdruck.
[
{
"id": "mesh_channel_flow",
"type": "tab",
"label": "MeshCore Channel",
"disabled": false
},
{
"id": "inject_channel",
"type": "inject",
"z": "mesh_channel_flow",
"name": "Sende #ping",
"props": [{"p": "payload", "vt": "json"}],
"repeat": "",
"once": false,
"payload": "{\"channel\":\"#ping\",\"message\":\"Pong! Gesendet via Node-RED\"}",
"payloadType": "json",
"x": 170,
"y": 100,
"wires": [["mqtt_out_channel"]]
},
{
"id": "mqtt_out_channel",
"type": "mqtt out",
"z": "mesh_channel_flow",
"name": "MeshCore Channel",
"topic": "meshcore/send/channel",
"qos": "1",
"retain": "",
"broker": "mqtt_broker_local",
"x": 420,
"y": 100,
"wires": []
},
{
"id": "mqtt_broker_local",
"type": "mqtt-broker",
"name": "Mosquitto Lokal",
"broker": "localhost",
"port": "1883",
"clientid": "nodered-meshcore",
"autoConnect": true,
"keepalive": "60",
"cleansession": true
}
]
Flow 2: Direktnachricht (DM) senden
Sendet eine DM an einen bestimmten Node im Mesh-Netzwerk.
[
{
"id": "mesh_dm_flow",
"type": "tab",
"label": "MeshCore DM",
"disabled": false
},
{
"id": "inject_dm",
"type": "inject",
"z": "mesh_dm_flow",
"name": "Sende DM",
"props": [{"p": "payload", "vt": "json"}],
"repeat": "",
"once": false,
"payload": "{\"destination\":\"MeinNode\",\"message\":\"Hallo aus Node-RED!\"}",
"payloadType": "json",
"x": 170,
"y": 100,
"wires": [["mqtt_out_dm"]]
},
{
"id": "mqtt_out_dm",
"type": "mqtt out",
"z": "mesh_dm_flow",
"name": "MeshCore DM",
"topic": "meshcore/send/dm",
"qos": "1",
"retain": "",
"broker": "mqtt_broker_local_dm",
"x": 400,
"y": 100,
"wires": []
},
{
"id": "mqtt_broker_local_dm",
"type": "mqtt-broker",
"name": "Mosquitto Lokal",
"broker": "localhost",
"port": "1883",
"clientid": "nodered-meshcore-dm",
"autoConnect": true,
"keepalive": "60",
"cleansession": true
}
]
Flow 3: Dashboard-Formular → Mesh senden
Ein Node-RED Dashboard-Formular zum freien Eingeben von Channel, Empfänger und Nachricht. Wähle zwischen DM und Channel-Nachricht.
[
{
"id": "mesh_dashboard_flow",
"type": "tab",
"label": "MeshCore Dashboard",
"disabled": false
},
{
"id": "inject_form",
"type": "inject",
"z": "mesh_dashboard_flow",
"name": "Channel: #bremesh",
"props": [{"p": "payload", "vt": "json"}, {"p": "topic", "vt": "str"}],
"repeat": "",
"once": false,
"topic": "meshcore/send/channel",
"payload": "{\"channel\":\"#bremesh\",\"message\":\"Moin aus Node-RED! 73\"}",
"payloadType": "json",
"x": 190,
"y": 100,
"wires": [["mqtt_out_dashboard"]]
},
{
"id": "inject_form_dm",
"type": "inject",
"z": "mesh_dashboard_flow",
"name": "DM: kleinBartzi",
"props": [{"p": "payload", "vt": "json"}, {"p": "topic", "vt": "str"}],
"repeat": "",
"once": false,
"topic": "meshcore/send/dm",
"payload": "{\"destination\":\"kleinBartzi\",\"message\":\"Moin Bartzi, Grüße via Node-RED!\"}",
"payloadType": "json",
"x": 190,
"y": 180,
"wires": [["mqtt_out_dashboard"]]
},
{
"id": "mqtt_out_dashboard",
"type": "mqtt out",
"z": "mesh_dashboard_flow",
"name": "MeshCore Send",
"topic": "",
"qos": "1",
"retain": "",
"broker": "mqtt_broker_dashboard",
"x": 450,
"y": 140,
"wires": []
},
{
"id": "mqtt_broker_dashboard",
"type": "mqtt-broker",
"name": "Mosquitto Lokal",
"broker": "localhost",
"port": "1883",
"clientid": "nodered-meshcore-dashboard",
"autoConnect": true,
"keepalive": "60",
"cleansession": true
}
]
Flow 4: Empfangene Pakete mitlesen (MQTT → Debug)
Empfängt alle Pakete vom Bot und zeigt sie im Debug-Panel an.
[
{
"id": "mesh_monitor_flow",
"type": "tab",
"label": "MeshCore Monitor",
"disabled": false
},
{
"id": "mqtt_in_packets",
"type": "mqtt in",
"z": "mesh_monitor_flow",
"name": "Mesh Pakete",
"topic": "meshcore/loc/packets",
"qos": "0",
"datatype": "json",
"broker": "mqtt_broker_monitor",
"x": 170,
"y": 100,
"wires": [["debug_packets"]]
},
{
"id": "mqtt_in_status",
"type": "mqtt in",
"z": "mesh_monitor_flow",
"name": "Mesh Status",
"topic": "meshcore/loc/status",
"qos": "0",
"datatype": "json",
"broker": "mqtt_broker_monitor",
"x": 170,
"y": 180,
"wires": [["debug_status"]]
},
{
"id": "debug_packets",
"type": "debug",
"z": "mesh_monitor_flow",
"name": "Pakete",
"active": true,
"tosidebar": true,
"complete": "payload",
"x": 390,
"y": 100,
"wires": []
},
{
"id": "debug_status",
"type": "debug",
"z": "mesh_monitor_flow",
"name": "Status",
"active": true,
"tosidebar": true,
"complete": "payload",
"x": 390,
"y": 180,
"wires": []
},
{
"id": "mqtt_broker_monitor",
"type": "mqtt-broker",
"name": "Mosquitto Lokal",
"broker": "localhost",
"port": "1883",
"clientid": "nodered-meshcore-monitor",
"autoConnect": true,
"keepalive": "60",
"cleansession": true
}
]
GRP_TXT Channel Decryption
Public hashtag channels (e.g. #ping, #CQ, Public) use deterministic keys derived from the channel name. The packet capture service can decrypt these on the fly:
[PacketCapture]
decode_hashtag_channels = Public,#ping,#test,#emergency
Public— the default MeshCore channel (case-sensitive, no#prefix)#channelname— hashtag channels with#prefix- Key derivation:
SHA256(channel_name_as_bytes)[:16]
HBME Ingestor Service
Forwards captured packets to the HBME API for centralized mesh network analysis. Features:
- Authelia SSO authentication
- Preview mode with packet queue (viewable in web UI)
- Live mode for production forwarding
- Real-time WebSocket updates in the services page
Zugang erhalten: Kontaktiere @bartzi:hbme.sh via Matrix, um deinen Token für die Registrierung auf register.hbme.sh zu bekommen.
See HBME Ingestor docs.
Telemetry Monitor Service
Der Telemetry Monitor fragt die Batterie- und Umgebungsdaten (Temperatur, Luftfeuchtigkeit, Luftdruck, GPS) von Repeatern im Mesh-Netzwerk ab und speichert sie in einer SQLite-Datenbank. Ergebnisse werden auch via MQTT publiziert, sodass externe Systeme (Node-RED, Home Assistant, Grafana, etc.) die Daten in Echtzeit verarbeiten können.
⚠️ WICHTIG: Repeater ACL-Berechtigung erforderlich!
Der Bot kann nur dann Telemetriedaten von einem Repeater abfragen, wenn er in der Access Control List (ACL) des Repeaters als Read/Write oder Admin eingetragen ist!
Ohne diese Berechtigung wird der Telemetrie-Request vom Repeater ignoriert und der Bot erhält keine Antwort (Timeout).
So fügst du den Bot zur Repeater-ACL hinzu:
- Verbinde dich mit dem Repeater über die MeshCore Companion App
- Öffne die Kontaktliste des Repeaters
- Suche den Bot-Kontakt (z.B. "TestBot")
- Setze die Berechtigung auf Read/Write oder Admin
Konfiguration
[MQTT]
server = localhost
port = 1883
transport = tcp
use_tls = false
use_auth_token = false
[TelemetryMonitor]
enabled = true
poll_interval_minutes = 180
request_timeout = 60
max_retries = 3
default_path_mode = flood
database_path = telemetry_data.db
# MQTT aktivieren für externe Systeme
mqtt_enabled = true
mqtt_topic_request = meshcore/telemetry/request
mqtt_topic_response = meshcore/telemetry/response
MQTT Telemetrie-Request senden
Sende eine JSON-Nachricht an das Request-Topic, um eine Telemetrie-Abfrage auszulösen:
Topic: meshcore/telemetry/request
{"repeater": "RepeaterName", "path": "flood"}
| Feld | Pflicht | Beschreibung |
|---|---|---|
repeater |
✅ | Name des Repeaters (exakt wie in der Kontaktliste) |
path |
❌ | Routing-Modus: flood (Default), direct, oder Hex-Path z.B. ef,10 |
Beispiele:
# Flood-Routing (Default)
mosquitto_pub -h localhost -t meshcore/telemetry/request \
-m '{"repeater": "Mitte @BreMesh", "path": "flood"}'
# Direct-Path (bekannter Pfad)
mosquitto_pub -h localhost -t meshcore/telemetry/request \
-m '{"repeater": "Mitte @BreMesh", "path": "direct"}'
# Custom Hex-Path
mosquitto_pub -h localhost -t meshcore/telemetry/request \
-m '{"repeater": "Mitte @BreMesh", "path": "ef,10"}'
# Minimal (ohne path, nutzt flood)
mosquitto_pub -h localhost -t meshcore/telemetry/request \
-m '{"repeater": "Mitte @BreMesh"}'
MQTT Telemetrie-Response
Der Bot publiziert die Telemetriedaten auf dem Response-Topic. Jede Abfrage (automatisch oder via MQTT-Request) wird hier veröffentlicht – auch fehlgeschlagene Versuche, sodass man den Fortschritt in Echtzeit mitlesen kann.
Topic: meshcore/telemetry/response
Erfolgreiche Abfrage:
{
"repeater": "Mitte🔌 @BreMesh",
"success": true,
"path": "flood",
"attempt": "1/3",
"duration_ms": 2341,
"temperature": 23.0,
"humidity": null,
"pressure": null,
"battery_voltage": 4.34,
"battery_percent": 100.0,
"latitude": null,
"longitude": null,
"altitude": null
}
Fehlgeschlagener Versuch (Retry):
{
"repeater": "Mitte🔌 @BreMesh",
"success": false,
"path": "flood",
"attempt": "1/3",
"duration_ms": 60012,
"error": "No telemetry response (timeout)"
}
Automatischer Poll (Telemetrie-Reading):
{
"repeater": "Mitte🔌 @BreMesh",
"timestamp": "2026-03-08T17:18:52",
"duration_ms": 2341,
"temperature": 23.0,
"humidity": null,
"pressure": null,
"battery_voltage": 4.34,
"battery_percent": 100.0,
"latitude": null,
"longitude": null,
"altitude": null,
"raw_data": [
{"channel": 1, "type": "voltage", "value": 4.34},
{"channel": 1, "type": "temperature", "value": 23.0}
]
}
| Feld | Typ | Beschreibung |
|---|---|---|
repeater |
string | Name des abgefragten Repeaters |
success |
bool | true bei Erfolg, false bei Timeout (nur bei MQTT-Request) |
attempt |
string | Aktueller Versuch, z.B. "1/3", "2/3" (nur bei MQTT-Request) |
path |
string | Verwendeter Routing-Modus (nur bei MQTT-Request) |
timestamp |
string | ISO-Zeitstempel der Abfrage |
duration_ms |
int | Dauer der Abfrage in Millisekunden |
temperature |
float/null | Temperatur in °C |
humidity |
float/null | Luftfeuchtigkeit in % |
pressure |
float/null | Luftdruck in hPa |
battery_voltage |
float/null | Batteriespannung in V |
battery_percent |
float/null | Batteriestand in % (berechnet: 3.0V=0%, 4.2V=100%) |
latitude |
float/null | GPS Breitengrad |
longitude |
float/null | GPS Längengrad |
altitude |
float/null | Höhe in m |
raw_data |
array | Rohe LPP-Telemetriedaten vom Device (nur bei automatischem Poll) |
error |
string | Fehlermeldung (nur bei success: false) |
Test via Kommandozeile:
# Telemetrie-Responses mitlesen
mosquitto_sub -h localhost -t meshcore/telemetry/response -v
# Request senden und auf Antwort warten
mosquitto_sub -h localhost -t meshcore/telemetry/response &
mosquitto_pub -h localhost -t meshcore/telemetry/request \
-m '{"repeater": "Mitte @BreMesh"}'
WebSocket Telemetrie-Stream
Die Telemetriedaten werden auch über den WebSocket des Web Viewers gestreamt (gleiche Datenstruktur wie MQTT). Clients können sich auf den telemetry_data-Event subscriben, um Echtzeit-Updates zu erhalten.
Verbindung (JavaScript/Socket.IO):
const socket = io('http://localhost:8080');
// Telemetrie-Stream abonnieren
socket.emit('subscribe_telemetry');
// Telemetrie-Events empfangen
socket.on('telemetry_data', (data) => {
console.log('Telemetrie:', data);
});
Event: telemetry_data
Es gibt zwei Typen von Events:
type: "reading" — Erfolgreiche Messung:
{
"type": "reading",
"repeater": "Mitte🔌 @BreMesh",
"timestamp": "2026-03-08 17:18:52",
"duration_ms": 2341,
"temperature": 23.0,
"humidity": null,
"pressure": null,
"battery_voltage": 4.34,
"battery_percent": 100.0,
"latitude": null,
"longitude": null,
"altitude": null,
"raw_data": [
{"channel": 1, "type": "voltage", "value": 4.34},
{"channel": 1, "type": "temperature", "value": 23.0}
]
}
type: "poll_attempt" — Poll-Versuch (Erfolg oder Fehler):
{
"type": "poll_attempt",
"repeater": "Mitte🔌 @BreMesh",
"timestamp": "2026-03-08 17:19:52",
"success": false,
"attempt": "1/3",
"duration_ms": 60012,
"path": "flood",
"error": "No telemetry response (timeout)"
}
Services Page (Web Viewer)
New /services page in the web viewer for managing service plugins:
- HBME Ingestor management (credentials, mode toggle, packet monitor)
- Real-time packet feed via WebSocket with HTTP polling fallback
- Dark theme support
See Web Viewer docs.
Acknowledgments
- MeshCore Project for the mesh networking protocol
- Some commands adapted from MeshingAround bot by K7MHI Kelly Keeton 2024
- Packet capture service based on meshcore-packet-capture by agessaman
- meshcore-decoder by Michael Hart for client-side packet decoding and decryption in the web viewer
- SWB sonst wäre es dunkel hier.