Files
meshcore-stats/docs/firmware-responses.md
T
Jorijn Schrijvershof 0f8b0a3492 Initial release: MeshCore Stats monitoring system
A Python-based monitoring system for MeshCore LoRa mesh networks.
Collects metrics from companion and repeater nodes, stores them in
a SQLite database, and generates a static website with interactive
SVG charts and statistics.

Features:
- Data collection from local companion and remote repeater nodes
- SQLite database with EAV schema for flexible metric storage
- Interactive SVG chart generation with matplotlib
- Static HTML site with day/week/month/year views
- Monthly and yearly statistics reports (HTML, TXT, JSON)
- Light and dark theme support
- Circuit breaker for unreliable LoRa connections
- Battery percentage calculation from 18650 discharge curves
- Automated releases via release-please

Live demo: https://meshcore.jorijn.com
2026-01-04 19:37:57 +01:00

3.4 KiB

MeshCore Firmware Response Reference

This document captures the actual response structures from MeshCore firmware commands. Use this as a reference when updating collectors or adding new metrics.

Last verified: 2025-12-29


Companion Node

The companion node is queried via USB serial using multiple commands.

get_stats_core()

Core system statistics.

{
    'battery_mv': 3895,      # Battery voltage in millivolts
    'uptime_secs': 126,      # Uptime in seconds
    'errors': 0,             # Error count
    'queue_len': 0           # Message queue length
}

get_stats_packets()

Packet counters (cumulative since boot).

{
    'recv': 20,              # Total packets received
    'sent': 0,               # Total packets sent
    'flood_tx': 0,           # Flood packets transmitted
    'direct_tx': 0,          # Direct packets transmitted
    'flood_rx': 20,          # Flood packets received
    'direct_rx': 0           # Direct packets received
}

get_stats_radio()

Radio/RF statistics.

{
    'noise_floor': -113,     # Noise floor in dBm
    'last_rssi': -123,       # RSSI of last received packet (dBm)
    'last_snr': -8.5,        # SNR of last received packet (dB)
    'tx_air_secs': 0,        # Cumulative TX airtime in seconds
    'rx_air_secs': 11        # Cumulative RX airtime in seconds
}

get_bat()

Battery/storage info (note: not the main battery source for metrics).

{
    'level': 4436,           # Battery level (unclear unit)
    'used_kb': 256,          # Used storage in KB
    'total_kb': 1404         # Total storage in KB
}

get_contacts()

Returns a dict keyed by public key. Count via len(payload).


Repeater Node

The repeater is queried over LoRa using the binary protocol command req_status_sync().

req_status_sync(contact)

Returns a single dict with all status fields.

{
    'bat': 4047,             # Battery voltage in millivolts
    'uptime': 1441998,       # Uptime in seconds
    'last_rssi': -63,        # RSSI of last received packet (dBm)
    'last_snr': 12.5,        # SNR of last received packet (dB)
    'noise_floor': -118,     # Noise floor in dBm
    'tx_queue_len': 0,       # TX queue depth
    'nb_recv': 221311,       # Total packets received (counter)
    'nb_sent': 93993,        # Total packets sent (counter)
    'airtime': 64461,        # TX airtime in seconds (counter)
    'rx_airtime': 146626,    # RX airtime in seconds (counter)
    'flood_dups': 59799,     # Duplicate flood packets (counter)
    'direct_dups': 8,        # Duplicate direct packets (counter)
    'sent_flood': 92207,     # Flood packets transmitted (counter)
    'recv_flood': 216960,    # Flood packets received (counter)
    'sent_direct': 1786,     # Direct packets transmitted (counter)
    'recv_direct': 4328      # Direct packets received (counter)
}

Derived Metrics

These are computed at query time, not stored:

Metric Source Computation
bat_pct bat or battery_mv voltage_to_percentage(mv / 1000) using 18650 Li-ion discharge curve

Notes

  • Counters reset to 0 on device reboot
  • Millivolts to volts: Divide by 1000 (e.g., bat: 40474.047V)
  • Repeater fields come from a single req_status_sync() call
  • Companion fields are spread across multiple get_stats_*() calls