Skip to content

v2.5.9: two bugs found during AU validation — companion pings + /api/stats #13

Description

@fahimshariff-au

v2.5.9 AU validation — two bugs found

Context: Tested vanilla v2.5.9 (fresh bootstrap + upgrade.sh) on a SenseCAP M1
(AU Mid 915.075 MHz / SF9 / BW125 / CR4/5, sync_word 5156, lorawan_public: false).
chan_multiSF RX, Neighbours tab, and ADVERT forwarding all working correctly.
Two bugs found and fixed locally; reporting for upstream.


Bug 1 — Companion pings broken: bridge_engine._store_tx_echo_hash drops TRACE_RESP

Symptom: Companion ping (e.g. TCP companion → remote node) shows "Ping failed — timeout"
even though the TRACE reaches the target and a TRACE_RESP is received cleanly on channel_a.

Log evidence:

BridgeEngine WARNING [TX_ECHO] Dropped echo on channel_a (hash=7d53abcde0b5, age=0.3s, total=4)

The RESP arrives at −36 dBm / SNR 9.5 — strong clean signal — and is immediately discarded.

Root cause: bridge_engine._store_tx_echo_hash stores the outgoing TRACE packet's hash
with no type guard. Because TRACE_RESP shares the same stable hash as the outgoing TRACE,
the RESP is matched and dropped as a TX echo before it reaches repeater_handler / TraceHelper.

The guard exists in wm1303_backend.py at both TX storage points (committed in our fork),
but bridge_engine._store_tx_echo_hash (line ~1211 in v2.5.9) has no equivalent check.

Fix — one line at the top of _store_tx_echo_hash:

def _store_tx_echo_hash(self, data, channel_id, ...):
    if len(data) > 0 and ((data[0] >> 2) & 0x0F) == 0x09:  # skip TRACE type
        return
    # ... rest of method unchanged

Verified: After applying this guard, companion pings to all WM1303 nodes work correctly
(956a→0e, 956a→75 both confirmed with SNR/RSSI reported). 956a→1a fails as expected
(rightup build doesn't implement TRACE).


Bug 2 — /api/stats returns HTTP 500 (TypeError: bytes not JSON serializable)

Symptom: WM1303 UI "System Config" stats panel fails to load. Server log shows:

TypeError: bytes not JSON serializable
  File "api_endpoints.py", line ..., in stats
    return stats

Root cause: bridge_engine.get_stats() (and possibly other components aggregated by
stats_getter()) includes bytes values for fields like channel_id / rule identifiers.
CherryPy's json_out decorator calls json.dumps() on the return value, which raises
TypeError on bytes. The try/except in stats() doesn't catch it because the
exception is raised after return, inside the CherryPy serialisation layer.

Fix — sanitize bytes in api_endpoints.py stats() before returning:

def _b(obj):
    """Recursively convert bytes → hex string for JSON serialization."""
    if isinstance(obj, bytes):
        return obj.hex()
    if isinstance(obj, dict):
        return {_b(k): _b(v) for k, v in obj.items()}
    if isinstance(obj, (list, tuple)):
        return [_b(i) for i in obj]
    return obj

@cherrypy.expose
@cherrypy.tools.json_out()
def stats(self):
    stats = self._stats_getter()
    return _b(stats)          # wrap here; catches bytes from all aggregated components

Note: Patching bridge_engine.get_stats() alone is insufficient — bytes come from
multiple components inside stats_getter(). Wrapping at the stats() return catches all
of them in one place.

Verified: After applying this fix, the UI System Config panel loads correctly.


Note — NF shown as "unknown" with Channel E in lbt_cad_spectrum_only

Not a bug — noting for documentation. When Channel E is configured as lbt_cad_spectrum_only
(spectrum scan only, not active LoRa RX), NoiseFloorMonitor does not start and the UI
shows "unknown" for NF. This is arguably the correct behaviour — the previous behaviour on
our fork was producing −63.5 dBm spikes from RX estimation artifacts, so "unknown" is cleaner.


Overall v2.5.9 AU validation

  • chan_multiSF RX on channel_a: ✓ (ARB 0xFF fix + lorawan_public: false working)
  • Neighbours tab: ✓ (populating with full history, map, topology)
  • ADVERT forwarding: ✓ (multi-hop confirmed)
  • Companion pings: ✓ after Bug 1 fix above
  • /api/stats: ✓ after Bug 2 fix above

Thank you for the v2.5.3 attribution — much appreciated.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions