Repository navigation
v2.9.0: honest traffic stats and remote admin
Two things in this release. Stats used to answer one question badly: how
much traffic is there? It counted four kinds of packet, kept three days of them,
and called the result "total packets". On a real mesh (Pimesh1, Luboń) the node's
own radio decoded about 16,000 unique frames a day while Stats showed about 6,000.
2.9.0 makes that number honest and keeps it long enough to see a trend.
And remote admin: read and change another node's settings over the mesh,
straight from its popup on the map.
Traffic History
A new card at the top of Stats, with 24h / 7d / 30d / 1y ranges:
- Logged vs heard. Bars show what MeshPulse decoded and stored (RF and MQTT
apart); the line shows what the radio actually received, from the node's own
firmware counters with duplicates removed. The gap between them is traffic
MeshPulse cannot decode. - Channel utilisation, average and peak, duplicate and bad-CRC rates, and
the packet type mix, with range totals on top and a CSV export. - Hours with no data stay gaps instead of turning into quiet hours, and days with
fewer than 24 recorded hours are drawn lighter and starred, so a short bar is
not mistaken for a quiet day.
History that survives
Every complete hour is folded into a small rollup table that is never pruned
(about 9,000 rows a year). The first start after the update backfills it from
whatever raw data is still there. Raw packet history is now kept 30 days
instead of 3, configurable as stats_retention_days in config.json (1 to 365).
Every packet counts
Until now only NODEINFO, POSITION, TELEMETRY and TEXT reached the stats database.
Every other port the radio hands over is now counted too, including packets on
channels this node has no key for (ENCRYPTED) and ports the Meshtastic library
does not know (PORT_<n>). Expect your Stats totals to jump: the mesh did
not get busier, the counter got honest.
Remote admin
A 🛠 Admin button in a Meshtastic node's popup (and 🛠 in the No GPS list) opens
a window that talks to that node over the mesh, through the radio MeshPulse is
already connected to. No port juggling, no CLI.
- Read 15 sections: owner, firmware, device, LoRa, position, power, network,
display, Bluetooth, security, MQTT, telemetry, neighbor info, store & forward,
range test. A console shows every step and its round trip, typically 1 to 2 s
per section on a direct neighbour. - Write: ✏️ Edit turns a section into a form built from the firmware's own
protobuf definitions. Review shows old → new for every changed field, Apply
sends it, and 20 s later MeshPulse reads the section back and marks each field
✓ or ✗ (so you see it when the firmware quietly clamps a value). Reboot is a
two-click button. - Off by default. Writes are armed from Config > 🛠 Remote Admin for 15,
30, 60 or 120 minutes and switch off by themselves;remote_admin_write: true
inconfig.jsonenables them permanently. Every write, reboot, arm and disarm
is recorded with the client address and listed on that tab. - Guard rails. Fields that can cut a node off the mesh are locked, with the
reason shown: LoRa radio parameters, Security, Network, Bluetooth, MQTT, device
role, licensed mode, power saving. - Requirements. The target node must list this node's public key as an
Admin Key (Security settings), and both must run firmware with PKC (2.5+).
MeshPulse now keeps every public key it hears (node_keysinstats.db) and
hands a key back to its own radio when the radio has dropped it from a full
NodeDB, so admin keeps working on a busy mesh.
Fixes
- TELEMETRY and TEXT were logged with
via_mqtthardcoded to false and no hops or
SNR, so MQTT telemetry counted as radio traffic and could raise "too frequent
telemetry" anomalies against nodes that are not even in range. - A packet that arrived with its hop limit used up lost its hop count: protobuf
leaves zero-valued fields out, sohopLimitwas simply missing. install.shreported "web server NOT FOUND" when run over ssh, because lighttpd
lives in/usr/sbin.
Performance
Measured on a Raspberry Pi 2 before shipping. With 30 days of traffic, one query
of the Stats summary took 4.95 s, every minute, holding the lock that packet
logging waits on; a new index brings it to 0.47 s. Pruning now deletes in small
chunks, so lowering the retention cannot freeze packet logging. The history card
reads only the rollup: 18 to 40 ms per request on the same Pi.
Updating
cd ~/meshpulse && git pull origin main && ./install.sh && sudo systemctl restart meshpulse
Docker
docker compose pull && docker compose up -d
Fresh Install
git clone https://github.com/maxg10/meshpulse.git
cd meshpulse
./install.sh