From 5cf8150146219eecd8ed937c81d7728fc769357e Mon Sep 17 00:00:00 2001 From: Jack Kingsman Date: Wed, 22 Apr 2026 17:31:18 -0700 Subject: [PATCH] Add repeater error count delivery in telemetry --- src/meshcore/parsing.py | 8 +- tests/unit/test_parse_status.py | 146 ++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_parse_status.py diff --git a/src/meshcore/parsing.py b/src/meshcore/parsing.py index e1e0b2f..1d25d84 100644 --- a/src/meshcore/parsing.py +++ b/src/meshcore/parsing.py @@ -105,5 +105,11 @@ def parse_status(data, pubkey_prefix=None, offset=0): res["direct_dups"] = int.from_bytes(data[offset+44:offset+46], byteorder="little") res["flood_dups"] = int.from_bytes(data[offset+46:offset+48], byteorder="little") res["rx_airtime"] = int.from_bytes(data[offset+48:offset+52], byteorder="little") - + + # n_recv_errors: uint32_t appended in firmware v1.12.0 (56-byte frame) + if len(data) >= offset + 56: + res["recv_errors"] = int.from_bytes(data[offset+52:offset+56], byteorder="little") + else: + res["recv_errors"] = None + return res \ No newline at end of file diff --git a/tests/unit/test_parse_status.py b/tests/unit/test_parse_status.py new file mode 100644 index 0000000..4a7e62f --- /dev/null +++ b/tests/unit/test_parse_status.py @@ -0,0 +1,146 @@ +"""Tests for meshcore.parsing.parse_status covering the RepeaterStats binary frame. + +The firmware struct (MeshCore/examples/simple_repeater/MyMesh.h) is: + + struct RepeaterStats { + uint16_t batt_milli_volts; // offset 0 (2) + uint16_t curr_tx_queue_len; // offset 2 (2) + int16_t noise_floor; // offset 4 (2) + int16_t last_rssi; // offset 6 (2) + uint32_t n_packets_recv; // offset 8 (4) + uint32_t n_packets_sent; // offset 12 (4) + uint32_t total_air_time_secs; // offset 16 (4) + uint32_t total_up_time_secs; // offset 20 (4) + uint32_t n_sent_flood; // offset 24 (4) + uint32_t n_sent_direct; // offset 28 (4) + uint32_t n_recv_flood; // offset 32 (4) + uint32_t n_recv_direct; // offset 36 (4) + uint16_t err_events; // offset 40 (2) + int16_t last_snr; // x4 // offset 42 (2) + uint16_t n_direct_dups; // offset 44 (2) + uint16_t n_flood_dups; // offset 46 (2) + uint32_t total_rx_air_time_secs; // offset 48 (4) + uint32_t n_recv_errors; // offset 52 (4) -- 56-byte frame + }; +""" +import struct +from meshcore.parsing import parse_status + + +def _build_frame( + *, + bat=4200, + tx_queue_len=3, + noise_floor=-118, + last_rssi=-85, + nb_recv=1000, + nb_sent=500, + airtime=3600, + uptime=86400, + sent_flood=100, + sent_direct=400, + recv_flood=300, + recv_direct=700, + err_events=0, + last_snr_x4=30, # 7.5 dB * 4 + direct_dups=5, + flood_dups=10, + rx_airtime=7200, + recv_errors=None, +): + """Build a RepeaterStats binary frame (52 or 56 bytes).""" + frame = struct.pack( + "