From 6f3eb0bbe4d58578c2c4c3b3af8e8ea50e9b5161 Mon Sep 17 00:00:00 2001 From: Radek Piekarz Date: Sat, 19 Sep 2026 09:19:23 +0200 Subject: [PATCH] Fix iCloud device tracker stale location by requesting an active locate on each poll (#181731) --- homeassistant/components/icloud/account.py | 5 +++++ tests/components/icloud/test_account.py | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/homeassistant/components/icloud/account.py b/homeassistant/components/icloud/account.py index 0433ca936c21..189da4b39ff4 100644 --- a/homeassistant/components/icloud/account.py +++ b/homeassistant/components/icloud/account.py @@ -175,6 +175,11 @@ class IcloudAccount: api_devices = {} try: api_devices = self.api.devices + # Since pyicloud 2.3.0 device reads are cache-only and the library + # requests an active locate from Apple only at service creation, so + # explicitly refresh with locate=True to get a fresh GPS fix on + # every poll instead of Apple's cached location. + api_devices.refresh(locate=True) except Exception as err: # noqa: BLE001 _LOGGER.error("Unknown iCloud error: %s", err) self._fetch_interval = 2 diff --git a/tests/components/icloud/test_account.py b/tests/components/icloud/test_account.py index 3ddc13b5d699..7ba37caa6650 100644 --- a/tests/components/icloud/test_account.py +++ b/tests/components/icloud/test_account.py @@ -99,6 +99,11 @@ class MockDevicesContainer: """Initialize with userinfo and list of device objects.""" self.user_info = userinfo self._devices = devices + self.refresh_calls: list[bool] = [] + + def refresh(self, locate: bool = False) -> None: + """Record refresh calls made by the account.""" + self.refresh_calls.append(locate) def __iter__(self): """Iterate returns device objects (each must have .status(...)).""" @@ -165,3 +170,7 @@ async def test_setup_success_with_devices( assert account.owner_fullname == "user name" assert "johntravolta" in account.family_members_fullname assert account.family_members_fullname["johntravolta"] == "John TRAVOLTA" + # An active locate must be requested on every poll (pyicloud >= 2.3.0 + # only locates at service creation, so the account has to ask for it) + assert mock_icloud_service.devices.refresh_calls == [True] + assert "device1" in account.devices