v0.10.0 — monitor log entry support (SUB 0x0A partial records)

Add full decode pipeline for 0x2C partial records from the device's event
list, representing continuous monitoring intervals where no threshold was
crossed.  These records appear interleaved with full triggered events in the
browse walk and were previously ignored.

minimateplus/models.py
- Add MonitorLogEntry dataclass: key, start_time, stop_time, serial,
  geo_threshold_ips, raw_header, duration_seconds property

minimateplus/protocol.py
- read_waveform_header() now returns (data_rsp.data, length) — full payload
  including the record-type byte at position 0 — instead of the sliced header.
  Callers that need the old slice use raw_data[11:11+length] as before.

minimateplus/client.py
- Add _decode_0a_partial_header(): auto-detects 9-byte (sub_code=0x10) vs
  10-byte (sub_code=0x03) timestamp format, handles 1-byte inter-timestamp
  gap, extracts serial via BE anchor and geo threshold via Geo: anchor.
- Add get_monitor_log_entries(skip_keys=None): browse walk (1E → 0A → 1F),
  decodes partial records, skips full records and already-seen keys.

minimateplus/__init__.py
- Export MonitorLogEntry

bridges/ach_server.py
- After get_events(), call get_monitor_log_entries(skip_keys=seen_keys) and
  save new entries to monitor_log.json in the session directory.
- Add _monitor_log_entry_to_dict() helper.
- Include monitor log keys in downloaded_keys for state persistence.

CLAUDE.md / CHANGELOG.md
- Document 0x2C partial record layout (timestamp format, ASCII metadata
  region, 1-byte gap edge case) confirmed from 4-11-26 MITM capture.
- Version bump to v0.10.0; update What's next.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-11 02:59:40 -04:00
committed by serversdown
parent 6acb419ebd
commit b241da970d
7 changed files with 525 additions and 19 deletions
+51
View File
@@ -4,6 +4,57 @@ All notable changes to seismo-relay are documented here.
---
## v0.10.0 — 2026-04-11
### Added
- **`MiniMateClient.get_monitor_log_entries(skip_keys=None)`** — browse-mode walk
(`1E → 0A → 1F`) that collects partial records (`0x2C` record type) from the device's
event list without triggering a full waveform download (no 0C or 5A). Returns
`list[MonitorLogEntry]`. Each entry represents one continuous monitoring interval where
no threshold was exceeded.
- **`_decode_0a_partial_header(raw_data, index, key4)`** in `client.py` — decodes a SUB
0x0A response payload whose record type is `0x2C`. Extracts:
- `start_time` / `stop_time` — two consecutive timestamps; auto-detects 9-byte
(sub_code=0x10, single-shot) vs 10-byte (sub_code=0x03, continuous) format from
`raw_data[11]`. Handles a 1-byte gap between the two timestamps that occurs when
ts1 and ts2 share the same minute:second.
- `serial` — device serial string found via `b"BE"` anchor scan.
- `geo_threshold_ips` — trigger level found via `b"Geo: "` anchor scan.
- **`MonitorLogEntry` dataclass** in `models.py` — new model for partial records:
`index`, `key`, `start_time`, `stop_time`, `serial`, `geo_threshold_ips`,
`raw_header`, and a `duration_seconds` property.
- **`read_waveform_header()` return value extended** — now returns `(data_rsp.data, length)`
(full payload) instead of `(data_rsp.data[11:11+length], length)`. Callers get the
complete payload including the record-type byte at position 0. Full records use
`raw_data[11:11+length]` as before; partial records are detected by `raw_data[0] == 0x2C`.
- **ACH server: monitor log collection** — after `get_events()`, calls
`get_monitor_log_entries(skip_keys=seen_keys)` and saves new entries to
`monitor_log.json` in the session directory. Monitor log keys are included in
`downloaded_keys` for state persistence (no re-processing on next call-home).
- **`_monitor_log_entry_to_dict()`** in `ach_server.py` — serialises a `MonitorLogEntry`
to a JSON-compatible dict with ISO-format timestamps.
### Protocol / Documentation
- **SUB 0x0A partial record (0x2C) format confirmed** (✅ 4-11-26 MITM capture, 12 frames):
- Record type `0x2C` at `raw_data[0]`; length < 64 bytes.
- Two timestamps at `raw_data[11:]` — start and stop of the monitoring interval.
- ASCII metadata region after timestamps: `BE<serial>\x00Geo: <float> in/s`.
- Edge case: 1-byte separator between timestamps when ts1 and ts2 share minute:second.
- 10-byte timestamp format (sub_code=0x03) signalled by `raw_data[11] == 0x10`.
- **Key reuse detection for monitor log entries** — monitor log keys are tracked alongside
event keys in `ach_state.json` so the ACH server does not re-process them after a
call-home cycle.
---
## v0.9.0 — 2026-04-11
### Added