Detect and discard stale iCloud locations - #181391
Conversation
|
Hey there @Quentame, @nzapponi, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
There was a problem hiding this comment.
🟡 Changes recommended
Mandatory PR-template sections are missing, and the new code contains avoidable maintenance overhead.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Detects stale cached iCloud locations so trackers report unknown instead of outdated coordinates.
Changes:
- Adds stale-location detection using
isOld, timestamp age, and polling interval. - Handles unavailable tracker coordinates safely.
- Adds integration-level coverage for stale, recent, and uncached locations.
File summaries
| File | Description |
|---|---|
account.py |
Detects and clears stale locations. |
const.py |
Adds location metadata constants. |
device_tracker.py |
Supports missing coordinates. |
conftest.py |
Adds mutable iCloud device fixtures. |
test_device_tracker.py |
Tests location retention and clearing. |
Review details
Suppressed comments (1)
homeassistant/components/icloud/account.py:461
- Condense this docstring to the non-obvious threshold choice; the multi-paragraph explanation duplicates the PR description and tests, making a simple predicate harder to maintain.
"""Return whether a location fix is too old to be trusted.
Both signals are needed, because neither is sufficient alone:
`isOld` says iCloud served a cached fix rather than a fresh one, but
- Files reviewed: 5/5 changed files
- Comments generated: 3
- Review effort level: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
iCloud keeps serving the last known fix for a device it cannot reach, flagged with isOld. The integration stored those fixes like any other, so a device that had left home stayed pinned to its last location indefinitely and presence automations kept treating it as home. Discard a fix only once iCloud has marked it cached and it is older than the longest gap between two fetches, by which point a fresher one should already have superseded it. Neither signal works alone: isOld does not say why a fix was cached, so a briefly unreachable device looks like one that has moved away, and a device sitting still keeps reporting the same old timestamp while iCloud still considers that fix current. The tests cover both of those cases alongside the stale one. Once a fix has been discarded the tracker has no coordinates and reports 'unknown', rather than continuing to claim the device is where it used to be.
e180e7e to
815f35a
Compare
There was a problem hiding this comment.
🟢 Approval recommended
The stale-location behavior is focused, correctly propagated to entity state, and adequately covered by integration-level tests.
Review details
- Files reviewed: 7/7 changed files
- Comments generated: 0 new
- Review effort level: Balanced
Proposed change
iCloud keeps serving the last known fix for a device it cannot reach, flagged with
isOld. The integration stored those fixes like any other, so a device that had left home stayed pinned to its last location indefinitely and presence automations kept treating it as home.A fix is now discarded only once iCloud has marked it cached and it is older than the longest gap between two fetches, by which point a fresher one should already have superseded it.
Both signals are needed because neither is sufficient alone:
isOldsays a cached fix was served, but not why. A device that was briefly unreachable looks exactly like one that has genuinely moved away, so acting on the flag alone would drop locations that are still good.test_recent_cached_location_keptandtest_old_uncached_location_keptcover those two cases, and both pass with or without the change — they exist to pin down that neither signal on its own discards a location.test_stale_location_clearedcovers the case being fixed and fails on unmodifieddev.The threshold is taken from the configured maximum interval rather than the current fetch interval, because
_fetch_intervalis recomputed after the device loop runs and drops to 15 seconds while devices are pending — a threshold that short would discard every cached fix there is.Once a fix has been discarded the tracker has no coordinates and reports
unknown, rather than continuing to claim the device is where it used to be.Type of change
Additional information
Supersedes #169004, which was closed by the stale bot. Related and independent: #181389 and #181390. That PR had review feedback from a maintainer, and both points are addressed here:
_is_stale()docstring, with the two tests above as the executable form of the argument.hass.config_entries.async_setup, advance time to let the account poll, and assert onhass.states.get(...). Nothing patches the dispatcher, and the only mock isPyiCloudServiceitself.This needs the
bugfixlabel for therequired-labelscheck to pass — I cannot add it myself.Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: