diff --git a/findmy/accessory.py b/findmy/accessory.py index 2567d28..16f699d 100644 --- a/findmy/accessory.py +++ b/findmy/accessory.py @@ -61,9 +61,11 @@ def get_max_index(self, dt: datetime) -> int: @abstractmethod def update_alignment(self, dt: datetime, index: int) -> None: """ - Update alignment of the accessory. + Update alignment of the accessory based on a key index that was observed at a specific time. - Alignment can be updated based on a LocationReport that was observed at a specific index. + Implementations of this method should consider that this method may be called + multiple times, sometimes with seemingly conflicting data: the same index may be + observed at different times, or multiple indices may be observed at the same time. """ raise NotImplementedError @@ -222,8 +224,13 @@ def get_max_index(self, dt: datetime) -> int: @override def update_alignment(self, dt: datetime, index: int) -> None: - if dt < self._alignment_date: - # we only care about the most recent report + if dt < self._alignment_date or index < self._alignment_index: + # We only care about the most recent report and index. + # Multiple calls to this method may be made with + # possibly conflicting data, so we just ignore + # anything that seems to go backwards in time or index. + # Saving the newest data is at least likely to be stable + # over multiple fetches. return logger.info("Updating alignment based on report observed at index %i", index) diff --git a/findmy/reports/reports.py b/findmy/reports/reports.py index 607714f..14371fb 100644 --- a/findmy/reports/reports.py +++ b/findmy/reports/reports.py @@ -431,7 +431,7 @@ async def _fetch_accessory_report( # state variables cur_keys_primary: set[str] = set() cur_keys_secondary: set[str] = set() - cur_index = accessory.get_min_index(start_date) + cur_index = accessory.get_max_index(start_date) ret: set[LocationReport] = set() async def _fetch() -> set[LocationReport]: @@ -446,17 +446,15 @@ async def _fetch() -> set[LocationReport]: report.decrypt(key) # update alignment data on every report - # if a key maps to multiple indices, only feed it the maximum index, - # since apple only returns the latest reports per request. - # This makes the value more likely to be stable. - accessory.update_alignment(report.timestamp, max(key_to_ind[key])) + for i in key_to_ind[key]: + accessory.update_alignment(report.timestamp, i) cur_keys_primary.clear() cur_keys_secondary.clear() return set(new_reports) - while cur_index <= accessory.get_max_index(end_date): + while cur_index >= accessory.get_min_index(end_date): key_batch = accessory.keys_at(cur_index) # split into primary and secondary keys @@ -483,7 +481,7 @@ async def _fetch() -> set[LocationReport]: cur_keys_primary |= new_keys_primary cur_keys_secondary |= new_keys_secondary - cur_index += 1 + cur_index -= 1 if cur_keys_primary or cur_keys_secondary: # fetch remaining keys