fix: update event count retrieval logic in AchSession and MiniMateClient

This commit is contained in:
2026-04-13 18:46:23 -04:00
parent e5ea17388a
commit 27db663579
2 changed files with 38 additions and 28 deletions
+23 -26
View File
@@ -257,29 +257,11 @@ class AchSession:
# Used to detect post-erase key reuse — see comment block above.
max_seen_key: str = unit_state.get("max_downloaded_key", "00000000")
# 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 or 0
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); %d key(s) previously downloaded",
current_count, len(seen_keys))
if current_count == 0:
log.info(" [OK] No events on device -- nothing to download")
log.info("Session complete (no events) -> %s", session_dir)
return
# Fast pre-check: walk the event index (browse-mode, no 5A) to get
# the current key list, then bail early if everything is already seen.
# This avoids calling get_events() at all when there's nothing new.
# Walk the event index (browse-mode, no 5A) to get the actual current
# key list. The SUB 08 event_count field is a lifetime "total events
# ever recorded" counter that does NOT decrement on erase — confirmed
# 2026-04-13. list_event_keys() via the 1E/1F chain is the only
# reliable way to know what is actually stored on the device right now.
log.info(" Checking device key list (browse walk, no waveform download)...")
try:
device_keys = client.list_event_keys()
@@ -287,6 +269,17 @@ class AchSession:
log.warning(" list_event_keys failed: %s -- falling back to full download", exc)
device_keys = None
# Use the walk result as our authoritative current count.
current_count = len(device_keys) if device_keys is not None else 0
log.info(" Unit has %d stored event(s); %d key(s) previously downloaded",
current_count, len(seen_keys))
if device_keys is not None and current_count == 0:
log.info(" [OK] No events on device -- nothing to download")
log.info("Session complete (no events) -> %s", session_dir)
return
if device_keys is not None:
# ── Post-erase detection ──────────────────────────────────────
# After the device memory is erased, new events start from key
@@ -359,10 +352,14 @@ class AchSession:
new_key_set = None # unknown; proceed with full download
# Apply max_events cap
stop_idx = current_count - 1
# stop_idx: when we know the count from list_event_keys, use it as
# an upper bound. When list_event_keys failed (device_keys is None),
# pass None — get_events will run until the null sentinel naturally.
stop_idx: Optional[int] = (current_count - 1) if device_keys is not None else None
if self.max_events is not None:
stop_idx = min(stop_idx, self.max_events - 1)
if self.max_events < current_count:
cap = self.max_events - 1
stop_idx = cap if stop_idx is None else min(stop_idx, cap)
if device_keys is not None and self.max_events < current_count:
log.warning(
" max_events=%d cap: will download events 0-%d only "
"(unit has %d total)",
+15 -2
View File
@@ -181,8 +181,21 @@ class MiniMateClient:
log.info("connect: reading event index (SUB 08)")
try:
idx_raw = proto.read_event_index()
device_info.event_count = _decode_event_count(idx_raw)
log.info("connect: device has %d stored event(s)", device_info.event_count)
# NOTE: _decode_event_count reads data[10:12] from the SUB 08 payload,
# which was believed to be the stored event count. Empirically it turns
# out to be a monotonically-increasing "total events ever recorded" counter
# that does NOT decrement when events are erased — confirmed 2026-04-13:
# device reported 6 via SUB 08 while list_event_keys() returned 0 (empty).
# We preserve the raw read here for the index data but do NOT use this
# count for logic; ach_server uses list_event_keys() as the authoritative
# source instead.
_raw_idx_count = _decode_event_count(idx_raw)
log.info(
"connect: SUB 08 index count=%d (lifetime counter, not current storage)",
_raw_idx_count,
)
# Leave device_info.event_count as None — callers should use
# list_event_keys() to get the actual current event count.
except ProtocolError as exc:
log.warning("connect: event index read failed: %s — continuing", exc)