Fetch pre-parsed JSON events from get_pump_logs instead of decoding the
retired reportsfacade binary stream:
- page the requested range into inclusive windows of at most 28 days
(the endpoint caps each request at ~4 weeks), covering short ranges and
single days correctly
- dedupe events that span windows by (sequenceGroup, sequenceNumber)
- count but skip clockChanges (LID_TIME_CHANGED/LID_DATE_CHANGED are not
consumed by any processor)
- parse via Events_from_json
Remove the dead reportsfacade pump_events_raw() and the now-unused
pump_event_metadata()/PumpEventMetadata/LastUpload types.
Verify against real captured pump-logs events that build_from_json:
- resolves enum/dictionary fields from their raw ints (commandedRateSource,
alarmId, requestedAction, previousUserMode, glucoseValueStatus incl. 0)
- scales ratio fields (rate x0.1)
- folds bitmask arrays of set-bit indices back to the raw int the IntFlag
expects (activeSleepSchedule [0]->1, cgmDataType [0]->1,
egvInfoBitmask [0,5,6,7,8,11,12]->6625), and empty array->0
- keeps the raw.timestamp shim used by process_device_status and the raw
egvTimeStamp seconds used by ProcessCGMReading
Extend build_events.py (the codemod) so events.json stays the source of
truth: each generated event class gains build_from_json(event), mapping a
pump-logs JSON event's eventProperties onto its {field}[Raw] attrs
(matched by normalized field name), plus RawEvent.build_from_json() which
derives timestampRaw from pumpDateTime so eventTimestamp/seqNum/eventId
keep working. Add generic.Event_from_json()/Events_from_json() dispatchers
mirroring Event()/Events(); unknown eventCode -> bare RawEvent.
Enum/dictionary/ratio fields are raw ints (map directly onto {field}Raw so
existing properties resolve); bitmask fields arrive as arrays of set-bit
indices, converted to the raw int via _bitmask_arr_to_int. events.py is
regenerated; the byte-path build() is unchanged.
Tests: tests/eventparser/test_from_json.py.
Implement TandemSourceApi.get_pump_logs(device_id, ...) for GET
api/reports/bff/pump-logs/{assignmentId}?pumperId&startDate&endDate&eventIds,
the JSON events endpoint that replaces the base64 reportsfacade/pumpevents.
startDate/endDate are sent as {ymd}T00:00:00Z / {ymd}T23:59:59Z per the
captured request. Adds typed PumpLogsResponse/PumpLogEvent TypedDicts,
verified to cover every key across all captured pump-logs responses.
Tests: URL/path/param construction (order-independent parse_qs), default
vs custom vs empty eventIds, empty query dict passthrough, return
passthrough, and None-dates-default-to-today.
- tests/sync/tandemsource/test_update_profiles.py: settings sourcing from
pump_metadata() — matching deviceId with settings reaches
PumpSettings.from_dict (proven via sentinel, using the real BFF
settings.details shape); settings=None / no-match / empty return False
without parsing.
- test_tandemsource.py: adapter edge cases (availableDataRange/settings
keys absent, missing required key raises KeyError, Mobi Control-IQ+
passthrough) and DEFAULT_EVENT_IDS regression (55 ids, no dupes,
477/480/486 present).
Fixtures are inline and trimmed from the real captured responses.
Switch choose_device, check, update_profiles, process.py and cli_helpers
from the old pump_event_metadata() (reportsfacade) to the normalized
pump_metadata() (BFF): tconnectDeviceId -> deviceId (UUID), and
lastUpload.settings -> settings.
Handle the BFF returning never-uploaded pumps (maxDateWithEvents=None):
skip them in the most-recent auto-select and fall back to the first
pump; raise a clear NoDevicesFound on an empty account instead of an
opaque TypeError. Clean stale comments/docstrings in tandemsource.py.
Tests: add tests/sync/tandemsource/test_choose_device.py (11 cases:
explicit/auto/never-uploaded/empty/InvalidSerialNumber/stale-warning)
and tests/api/test_tandemsource.py (pump_metadata adapter mapping),
and update the test_process fixture to the new keys.
Since the 2.0 migration to Tandem Source, the live sync path
(api.tandemsource + sync/tandemsource/*) no longer references the
legacy t:connect APIs. This removes that now-unreachable code.
Removed modules:
- api/controliq.py, api/ws2.py, api/android.py, api/webui.py
(the legacy controliq / tconnectws2 / android / webui clients)
- process.py (old process_time_range; already broken since it
imported sync submodules that no longer exist)
- parser/ciq_therapy_events.py, parser/tconnect.py (TConnectEntry)
- domain/therapy_event.py, domain/bolus.py, domain/device_settings.py,
domain/utility.py
Trimmed dead wiring from live modules:
- api/__init__.py: dropped the controliq/ws2/android/webui properties,
keeping only the tandemsource accessor
- check.py: removed the unused TConnectEntry import
- parser/nightscout.py: removed the unused legacy profile_store() plus
the now-orphaned tandem_to_ns_time / tandem_to_ns_time_seconds helpers
and InvalidTimeException (the live path uses tandemsource_profile_store)
Tests: removed suites covering the deleted modules; pared tests/api/fake.py
down to the TConnectApi fake still used by the tandemsource tests. README
"Tandem APIs" sections updated to reflect the single Tandem Source API.
Full test suite passes (48 passed, 1 skipped).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LQNn3mBG1kXTAdQb9c2jfW