diff --git a/bridges/ach_server.py b/bridges/ach_server.py index 19b7f43..ccaff02 100644 --- a/bridges/ach_server.py +++ b/bridges/ach_server.py @@ -216,13 +216,20 @@ class AchSession: unit_key = serial or self.peer # fall back to IP if no serial last_count = state.get(unit_key, {}).get("event_count", 0) - try: - current_count = client.count_events() - log.info(" Unit has %d stored event(s); last downloaded count: %d", - current_count, last_count) - except Exception as exc: - log.error(" [FAIL] count_events failed: %s", exc) - return + # Use the event count already read from the event index during connect(). + # This is fast (no extra round-trips) and confirmed accurate (matches LCD). + # Falls back to count_events() only if connect() wasn't called. + if device_info is not None: + current_count = device_info.event_count + else: + try: + current_count = client.count_events() + except Exception as exc: + log.error(" [FAIL] count_events failed: %s", exc) + return + + log.info(" Unit has %d stored event(s); last downloaded count: %d", + current_count, last_count) if current_count <= last_count: log.info(" [OK] No new events since last call-home -- nothing to download") diff --git a/minimateplus/client.py b/minimateplus/client.py index 2538f48..47d4a20 100644 --- a/minimateplus/client.py +++ b/minimateplus/client.py @@ -910,36 +910,25 @@ def _decode_event_count(data: bytes) -> int: """ Extract stored event count from SUB F7 (EVENT_INDEX_RESPONSE) payload. - Layout per §7.4 (offsets from data section start): - +00: 00 58 09 — total index size or record count ❓ - +03: 00 00 00 01 — possibly stored event count = 1 ❓ + Confirmed 2026-04-10 from live BE11529 event index (88 bytes): + data[10:12] uint16 BE = stored event count (confirmed: 0x0006 = 6, matches LCD) + data[3:7] uint32 BE = 0x00000001 (NOT the count — meaning TBD) - We use bytes +03..+06 interpreted as uint32 BE as the event count. - This is inferred (🔶) — the exact meaning of the first 3 bytes is unclear. + Previous implementation read uint32 at offset 3, which returned 1 regardless + of how many events were stored. """ - if len(data) < 7: + if len(data) < 12: log.warning("event index payload too short (%d bytes), assuming 0 events", len(data)) return 0 - # Log the full payload so we can reverse-engineer the format - log.warning("event_index raw (%d bytes total):", len(data)) - for off in range(0, len(data), 16): - chunk = data[off:off+16] - hex_part = " ".join(f"{b:02x}" for b in chunk) - asc_part = "".join(chr(b) if 0x20 <= b < 0x7f else "." for b in chunk) - log.warning(" [%04x]: %-47s %s", off, hex_part, asc_part) + count = struct.unpack_from(">H", data, 10)[0] - # Try the uint32 at +3 first - count = struct.unpack_from(">I", data, 3)[0] - - # Sanity check: MiniMate Plus manual says max ~1000 events + # Sanity check: MiniMate Plus max storage is ~1000 events if count > 1000: - log.warning( - "event count %d looks unreasonably large — clamping to 0", count - ) + log.warning("event count %d looks unreasonably large — clamping to 0", count) return 0 - log.warning("event_index decoded count=%d (uint32 BE at offset +3)", count) + log.debug("event_index decoded count=%d (uint16 BE at offset 10)", count) return count