The meshtastic-metrics-exporter is a tool designed to collect and store comprehensive data from Meshtastic MQTT servers into TimescaleDB, with pre-configured Grafana dashboards for visualization and analysis.
You can explore these public instances to see the exporter in action:
- Canadaverse Dashboard: dash.mt.gt (Guest access: username:
guest, password:guest)This instance demonstrates the metrics exporter's capabilities in a production environment, maintained by @tb0hdan.
- Ingests nearly all packet types from Meshtastic MQTT servers
- Stores time-series metrics in TimescaleDB hypertables for efficient querying
- Tracks node details, telemetry, and network topology in PostgreSQL tables
- Comes with pre-configured Grafana dashboards for immediate visualization
- Automatic data retention policies and continuous aggregations
- Configuration via
.envfile
For affordable and reliable hosting, I personally use Hetzner Cloud for running this project. Their VPS offerings provide excellent performance for TimescaleDB and Grafana workloads at competitive prices.
Note: This is a referral link - using it supports the project at no extra cost to you. Plus you should get free 20$ for use
The system uses PostgreSQL with TimescaleDB extension:
- messages - Deduplication table with auto-expiry
- node_details - Node information (ID, names, hardware, location, MQTT status, last-heard MQTT topic/channel, direct MQTT topic)
- node_neighbors - Network topology from NeighborInfo packets
- node_configurations - Module configurations and update intervals
- device_metrics - Battery, voltage, channel utilization, uptime
- environment_metrics - Temperature, humidity, pressure, air quality sensors
- air_quality_metrics - Particulate matter measurements
- power_metrics - Multi-channel voltage/current measurements
- pax_counter_metrics - WiFi and BLE device counts
- mesh_packet_metrics - Packet routing and network statistics
- position_metrics - Historical GPS coordinates for recent location analysis
All hypertables have:
- Automatic retention policies
- Indexes optimized for time-series queries
- Continuous aggregation support
Default retention is 3 months for non-location hypertables and 30 days for
position_metrics. The shorter location window is intentional:
node_details stores the latest coordinate for dashboard maps, so run the
location pruning script below if you also want stale latest-location fields
cleared.
The project includes several pre-configured dashboards:
Shows network overview, active nodes, packet statistics, and channel utilization.
Note: Dashboard links target localhost:3000. Update panel configurations to match your Grafana server address.
Detailed view per node with telemetry, battery metrics, and configuration details.
Visualizes mesh topology from NeighborInfo packets with SNR-based coloring:
- Green nodes: Connected to MQTT
- Red nodes: Disconnected from MQTT
- Gray nodes: Unknown status (never connected)
- Line colors: Signal strength (SNR)
Recommendation: Allow 24 hours for data collection before expecting meaningful insights.
Configure the exporter using a .env file:
# TimescaleDB connection
DATABASE_URL=postgres://postgres:postgres@timescaledb:5432/meshtastic
# MQTT connection
MQTT_HOST=mqtt.meshtastic.org
MQTT_PORT=1883
MQTT_USERNAME=meshdev
MQTT_PASSWORD=large4cats
MQTT_KEEPALIVE=60
MQTT_TOPIC='msh/US/#'
MQTT_IS_TLS=false
# MQTT protocol version (MQTTv311 for public server)
# Options: MQTTv311, MQTTv31, MQTTv5
MQTT_PROTOCOL=MQTTv311
# MQTT callback API version
# Options: VERSION1, VERSION2
MQTT_CALLBACK_API_VERSION=VERSION2
# Exporter configuration
MESH_HIDE_SOURCE_DATA=false
MESH_HIDE_DESTINATION_DATA=false
MQTT_SERVER_KEY=1PG7OiApB1nwvP+rz05pAQ==
# Message types to filter (comma-separated)
# Full list: https://buf.build/meshtastic/protobufs/docs/main:meshtastic#meshtastic.PortNum
EXPORTER_MESSAGE_TYPES_TO_FILTER=TEXT_MESSAGE_APP
# Enable node configurations report
REPORT_NODE_CONFIGURATIONS=true
# Logging configuration
ENABLE_STREAM_HANDLER=true
LOG_LEVEL=INFO
LOG_FILE_MAX_SIZE=10MB
LOG_FILE_BACKUP_COUNT=5Start all services with Docker Compose:
docker compose up -dThis starts:
- Exporter: Python service processing MQTT messages
- TimescaleDB: PostgreSQL with TimescaleDB extension
- Grafana: Visualization platform (accessible at
http://localhost:3000)
MQTT Server → Exporter (Python) → TimescaleDB → Grafana
The exporter:
- Subscribes to Meshtastic MQTT topics
- Decrypts encrypted packets (if key provided)
- Parses Protocol Buffer messages
- Stores metrics in TimescaleDB hypertables
- Updates node details and topology in PostgreSQL tables
To re-roll the exporter container with updated files (copy new files over old, remove old container/images, rebuild, recreate, then run DB migration):
./scripts/patch_node_topic_channel_tracking.shYou can also target another compose project directory:
./scripts/patch_node_topic_channel_tracking.sh /path/to/meshtastic-metrics-exporterIf you only need to apply the schema update manually, run:
docker exec -i <timescaledb_container> psql -U postgres -d meshtastic \
-f /dev/stdin < docker/timescaledb/008_retention_and_location_privacy.sqlTo verify:
docker exec -it <timescaledb_container> psql -U postgres -d meshtastic \
-c "SELECT hypertable_name, config FROM timescaledb_information.jobs WHERE proc_name = 'policy_retention' ORDER BY hypertable_name"TimescaleDB retention automatically removes old position_metrics chunks, but
the latest location stored in node_details lingers so dashboard maps still
have something to render. To clear location data older than 30 days, run:
python scripts/prune_location_data.py --dry-run
python scripts/prune_location_data.pyThe script uses node_details.location_updated_at (added in migration 008) to
decide which cached locations are stale, so apply the migration first. Rows
that predate the migration without a backfilled timestamp are left alone by
default; pass --force-legacy to clear them too.
Install the project requirements first if psycopg is not available. For
host-based runs, set PG_HOST, PG_PORT, PG_DB, PG_USER, and
PG_PASSWORD as needed. To keep a different window, pass --retention-days 90.
Contributions are welcome! Please open an issue or submit a pull request on GitHub.
This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details.
