Building a Mesh Network Dashboard A community mesh network dashboard gives operators a real-time view of network health - which nodes are online, battery levels, channel utilization, and connectivity maps. This page covers building a monitoring stack for a Meshtastic network. Architecture Overview The standard monitoring stack for Meshtastic: Meshtastic nodes ↓ (MQTT uplink) MQTT Broker (Mosquitto) ↓ Telegraf (or Python consumer) ↓ InfluxDB (time-series database) ↓ Grafana (dashboard and alerting) This stack can run on a Raspberry Pi 4 or any small Linux server. As a rough guide, budget at least 1 - 2 GB RAM (InfluxDB 2.x is memory-hungry and can exceed 500 MB under load) and on the order of 10 GB of storage per month of retained data for a ~50-node network. Actual usage varies with telemetry rate and retention - test on your own hardware before committing to a Pi. Step 1: MQTT Broker Setup Install Mosquitto on your monitoring server: sudo apt install mosquitto mosquitto-clients sudo systemctl enable mosquitto Minimal config at /etc/mosquitto/mosquitto.conf: listener 1883 allow_anonymous true persistence true persistence_location /var/lib/mosquitto/ For production, add TLS and password authentication. Step 2: Configure Nodes to Uplink On each node you want to monitor. Note that uplink_enabled is a per-channel setting, not an mqtt.* module key - there is no mqtt.uplink_enabled. Set the module-level keys first, then enable uplink on the channel: # Module-level MQTT settings meshtastic --set mqtt.enabled true meshtastic --set mqtt.address "YOUR_SERVER_IP" meshtastic --set mqtt.json_enabled true # Per-channel: enable uplink on channel index 0 (repeat for other channels) meshtastic --ch-index 0 --ch-set uplink_enabled true JSON mode outputs human-readable JSON instead of protobuf binary - easier for custom consumers but includes less data. For full data including all telemetry, use protobuf mode and decode with the meshtastic Python library. Step 3: InfluxDB Install InfluxDB 2.x via the official InfluxData apt repository (the snippet below is abbreviated - follow the full add-key + add-repo steps in the InfluxData install guide at docs.influxdata.com/influxdb/v2/install/ before running apt install): # Abbreviated - see docs.influxdata.com/influxdb/v2/install/ for the # complete key import and repository setup steps wget -q https://repos.influxdata.com/influxdata-archive_compat.key # ... import the key and add the influxdata apt source, then: sudo apt install influxdb2 sudo systemctl enable --now influxdb Create a bucket named "meshtastic" via the InfluxDB UI at http://localhost:8086. Set the retention period to match your storage budget - the ~10 GB/month figure above assumes roughly 30-day retention, so a 90-day retention would store about three times as much. Step 4: Python MQTT-to-InfluxDB Bridge Note: the bridge below subscribes to msh/+/2/json/#, the JSON subtopic, so that json.loads() only ever sees JSON payloads. If you instead subscribe to msh/# you will also receive raw protobuf topics, and json.loads() will throw on those binary payloads - the try/except simply skips anything that is not valid JSON. pip install paho-mqtt influxdb-client meshtastic # bridge.py - subscribe to Meshtastic MQTT, write metrics to InfluxDB import paho.mqtt.client as mqtt from influxdb_client import InfluxDBClient, Point from influxdb_client.client.write_api import SYNCHRONOUS import json, time INFLUX_URL = "http://localhost:8086" INFLUX_TOKEN = "YOUR_TOKEN" INFLUX_ORG = "meshamerica" INFLUX_BUCKET = "meshtastic" client = InfluxDBClient(url=INFLUX_URL, token=INFLUX_TOKEN, org=INFLUX_ORG) write_api = client.write_api(write_options=SYNCHRONOUS) def on_message(mqttc, userdata, msg): try: data = json.loads(msg.payload) except (ValueError, UnicodeDecodeError): # Non-JSON (raw protobuf) payload - skip it return try: node_id = data.get("from", "unknown") if "payload" in data: p = data["payload"] pt = Point("node_telemetry").tag("node_id", node_id) if "battery_level" in p: pt = pt.field("battery_pct", p["battery_level"]) if "voltage" in p: pt = pt.field("voltage", p["voltage"]) if "channel_utilization" in p: pt = pt.field("channel_util", p["channel_utilization"]) write_api.write(INFLUX_BUCKET, record=pt) except Exception as e: print(f"Error: {e}") mqttc = mqtt.Client() mqttc.on_message = on_message mqttc.connect("localhost", 1883) # Subscribe only to the JSON subtopic so json.loads never sees protobuf mqttc.subscribe("msh/+/2/json/#") mqttc.loop_forever() The telemetry JSON keys used above ( battery_level, voltage, channel_utilization) correspond to the device-metrics telemetry fields; verify the exact key names and nesting against a live TELEMETRY_APP JSON sample from your firmware version, as the serializer can change. Step 5: Grafana Dashboard Install Grafana and add InfluxDB as a data source. Useful panels: Battery Voltage by Node - Time series, grouped by node_id tag Online Node Count - Count distinct nodes seen in last 30 minutes Channel Utilization Heatmap - Spot congestion patterns over time Last Seen Table - Node name and minutes since last packet Alerting Configure Grafana alerts to notify via email, Slack, or Telegram: Battery below 20% - node needs attention Node offline (no data in 2 hours) - repeater may be down Channel utilization above 30% - network congestion warning