From a28e0f1ee0ab577ff3d4e1b08ce9cc6a19111bf9 Mon Sep 17 00:00:00 2001 From: James Woglom Date: Wed, 1 Jul 2026 04:40:53 +0000 Subject: [PATCH] Add pump_clock_changes() to fetch parsed clock-change events Mirrors pump_events(): pages get_pump_logs across date windows and dedupes clockChanges (LID_TIME_CHANGED/LID_DATE_CHANGED, codes 13/14) by (sequenceGroup, sequenceNumber), returning them parsed via Events(). --- tconnectsync/api/tandemsource.py | 18 ++++++++++++++++++ tests/api/test_tandemsource.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/tconnectsync/api/tandemsource.py b/tconnectsync/api/tandemsource.py index 4051c63..39df955 100644 --- a/tconnectsync/api/tandemsource.py +++ b/tconnectsync/api/tandemsource.py @@ -674,4 +674,22 @@ class TandemSourceApi: logger.info(f"Read {len(events)} events ({clock_change_count} clock changes skipped)") return Events(events) + def pump_clock_changes(self, tconnect_device_id: str, min_date: Optional[str] = None, max_date: Optional[str] = None) -> Iterator: + """Fetch the pump-logs clockChanges (LID_TIME_CHANGED/LID_DATE_CHANGED) + across the date range, deduplicated by (sequenceGroup, sequenceNumber). + tconnect_device_id is the UUID assignmentId from get_pumper() pumps.""" + seen = set() + clock_changes = [] + for window_start, window_end in self._pump_log_windows(min_date, max_date): + resp = self.get_pump_logs(tconnect_device_id, window_start, window_end) + for event in resp.get('clockChanges') or []: + key = (event.get('sequenceGroup'), event.get('sequenceNumber')) + if key in seen: + continue + seen.add(key) + clock_changes.append(event) + + logger.info(f"Read {len(clock_changes)} clock changes") + return Events(clock_changes) + diff --git a/tests/api/test_tandemsource.py b/tests/api/test_tandemsource.py index 797f5fc..004ccd9 100644 --- a/tests/api/test_tandemsource.py +++ b/tests/api/test_tandemsource.py @@ -421,6 +421,36 @@ class TestPumpEventsRealEventTypes(unittest.TestCase): eventtypes.LidAlarmActivated.AlarmidEnum.OcclusionAlarm) +def _cc(num, code): + return {"eventCode": code, "sequenceGroup": 0, "sequenceNumber": num, + "pumpDateTime": "2024-01-01T00:00:00", "eventProperties": {}} + + +class TestPumpClockChanges(unittest.TestCase): + def _api(self): + api = TandemSourceApi.__new__(TandemSourceApi) + api.pumperId = "P" + return api + + def test_parses_clock_changes(self): + with patch.object(TandemSourceApi, "get_pump_logs", + return_value={"clockChanges": [_cc(5, 13), _cc(6, 14)]}): + out = list(self._api().pump_clock_changes("dev", "2024-01-01", "2024-01-10")) + self.assertEqual([(type(e).__name__, e.seqNum) for e in out], + [("LidTimeChanged", 5), ("LidDateChanged", 6)]) + + def test_dedupes_across_windows(self): + responses = [{"clockChanges": [_cc(5, 13)]}, {"clockChanges": [_cc(5, 13), _cc(7, 14)]}] + with patch.object(TandemSourceApi, "get_pump_logs", side_effect=responses): + out = list(self._api().pump_clock_changes("dev", "2024-01-01", "2024-02-15")) + self.assertEqual([e.seqNum for e in out], [5, 7]) + + def test_missing_clock_changes_key_is_tolerated(self): + with patch.object(TandemSourceApi, "get_pump_logs", return_value={}): + out = list(self._api().pump_clock_changes("dev", "2024-01-01", "2024-01-10")) + self.assertEqual(out, []) + + class TestGetRetry(unittest.TestCase): """get() retries once on 500, re-logs-in and retries once on 401, and raises immediately on other statuses; after one retry it gives up."""