Meshtastic can be used as a simple mesh between devices, but it also can be used for tracking devices through a Grafana dashboard. Grafana doesn’t work with MQTT very well. MQTT is not designed for long-term storage. It is great for small messages on defined topics. Visualizing and keeping those messages over time is the TIG stack: Telegraf, InfluxDB, and Grafana.
I am not going into detail on Docker or MQTT. Follow this to get a basic stack on Ubuntu. I keep containers under /containers/tigstack.
version: "3.8"
services:
influxdb:
image: influxdb:latest
container_name: influxdb
ports:
- "8086:8086"
volumes:
- influxdb_data:/var/lib/influxdb2
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=admin
- DOCKER_INFLUXDB_INIT_PASSWORD=SecureLogonPassword
- DOCKER_INFLUXDB_INIT_ORG=YourOrganization
- DOCKER_INFLUXDB_INIT_BUCKET=meshtastic_data
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=SecureInfluxPassword
telegraf:
image: telegraf:latest
container_name: telegraf
depends_on:
- influxdb
volumes:
- ./:/etc/telegraf:ro
environment:
- MQTT_BROKER_URL=tcp://10.10.10.10:1883
- MQTT_USER=meshtastic
- MQTT_PASS=SecureMQTTPassword
- INFLUX_TOKEN=InfluxDBAdminToken
grafana:
image: grafana/grafana:latest
container_name: grafana
ports:
- "3000:3000"
depends_on:
- influxdb
volumes:
- grafana_data:/var/lib/grafana
volumes:
influxdb_data:
grafana_data:Create telegraf.conf next to the compose file. Topics must be JSON. NRF nodes need the decode bridge first.
[agent]
interval = "10s"
[[outputs.influxdb_v2]]
urls = ["http://influxdb:8086"]
token = "${INFLUX_TOKEN}"
organization = "Organization"
bucket = "meshtastic_data"
[[inputs.mqtt_consumer]]
servers = ["${MQTT_BROKER_URL}"]
topics = [
"msh/Meshtastic/2/json/Main/!9e75dbcc",
"msh/Meshtastic/2/json/Private/!9e75dbcc"
]
username = "${MQTT_USER}"
password = "${MQTT_PASS}"
client_id = "telegraf_meshtastic"
data_format = "json"
json_string_fields = ["payload_text"]Bring it up with docker compose up -d. Log into Influx at :8086, generate an all-access API token, then in Grafana (:3000, admin/admin the first time) add an InfluxDB data source using Flux, the compose org, bucket, and that token.
Message table
This Flux query pulls messages, maps node IDs to names, and keeps channel plus text.
import "regexp"
from(bucket: "meshtastic_data")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "mqtt_consumer")
|> filter(fn: (r) => r._field == "payload_text" or r._field == "from" or r._field == "payload_from")
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> map(fn: (r) => ({
r with
node_id: if exists r.from then string(v: r.from)
else if exists r.payload_from then string(v: r.payload_from)
else "unknown"
}))
|> map(fn: (r) => ({
r with
node_name: if r.node_id == "2658588132" then "Base"
else if r.node_id == "1685377223" then "Node1"
else r.node_id
}))
|> filter(fn: (r) => exists r.payload_text and r.payload_text != "")
|> keep(columns: ["_time", "node_name", "payload_text"])
|> rename(columns: {payload_text: "message", node_name: "node_id"})Last-known GPS for 30 days is the same pattern: pivot lat/lon, map names, top(n: 1) per node, divide latitude_i by 10,000,000. A second query without top gives the track over the dashboard time range.
ESP32 nodes can publish JSON and encrypted MQTT. NRF nodes do not have Wi-Fi and do not speak JSON. In my setup an ESP32 client uplinks over Wi-Fi into Home Assistant’s MQTT broker, and NRF SenseCaps stay on the mesh as trackers.
GitHub: Technolitero/Meshtastic↗