From 7457a8284b3f557dc5873cf67c574f9ae08d88e7 Mon Sep 17 00:00:00 2001 From: Jeena Date: Tue, 5 May 2026 02:01:05 +0000 Subject: [PATCH] Fix coordinator wiring after refactor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two bugs left from the hass.data move that surfaced as soon as the integration ran on the live HA: * In async_setup_entry, devices were stored in hass.data AFTER coordinator.async_config_entry_first_refresh(), but _async_update_data reads them from hass.data — so the very first refresh raised KeyError 'devices' and the entry stayed in setup_retry. Move the hass.data update before first_refresh. * SmartThingsDeviceTracker called self.async_on_update(...) which isn't a method on TrackerEntity. Without a working listener registration the tracker stayed restored=true / unavailable forever. Subscribe in async_added_to_hass and use async_on_remove for cleanup, which is the documented pattern. Verified end-to-end on a live HA: phones/watch produce GPS, battery sensors populate, and the Ring button triggers a SmartTag. Co-Authored-By: Claude Opus 4.7 (1M context) --- custom_components/smartthings_find/__init__.py | 16 +++++++++------- .../smartthings_find/device_tracker.py | 10 ++++++++-- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/custom_components/smartthings_find/__init__.py b/custom_components/smartthings_find/__init__.py index 375747e..03ea8be 100644 --- a/custom_components/smartthings_find/__init__.py +++ b/custom_components/smartthings_find/__init__.py @@ -55,25 +55,27 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Load all SmartThings-Find devices from the users account devices = await get_devices(hass, session, entry.entry_id) - + # Create an update coordinator. This is responsible to regularly # fetch data from STF and update the device_tracker and sensor # entities update_interval = entry.options.get(CONF_UPDATE_INTERVAL, CONF_UPDATE_INTERVAL_DEFAULT) coordinator = SmartThingsFindCoordinator(hass, session, entry.entry_id, update_interval) - # This is what makes the whole integration slow to load (around 10-15 - # seconds for my 15 devices) but it is the right way to do it. Only if - # it succeeds, the integration will be marked as successfully loaded. - await coordinator.async_config_entry_first_refresh() - + # Store everything the coordinator needs BEFORE the first refresh, + # because _async_update_data reads `devices` out of hass.data. hass.data[DOMAIN][entry.entry_id].update({ CONF_JSESSIONID: jsessionid, "session": session, "coordinator": coordinator, - "devices": devices + "devices": devices, }) + # This is what makes the whole integration slow to load (around 10-15 + # seconds for my 15 devices) but it is the right way to do it. Only if + # it succeeds, the integration will be marked as successfully loaded. + await coordinator.async_config_entry_first_refresh() + hass.async_create_task( hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) ) diff --git a/custom_components/smartthings_find/device_tracker.py b/custom_components/smartthings_find/device_tracker.py index d47a230..83e4f16 100644 --- a/custom_components/smartthings_find/device_tracker.py +++ b/custom_components/smartthings_find/device_tracker.py @@ -43,8 +43,14 @@ class SmartThingsDeviceTracker(DeviceTrackerEntity): if 'icons' in device['data'] and 'coloredIcon' in device['data']['icons']: self._attr_entity_picture = device['data']['icons']['coloredIcon'] - self.async_on_update(coordinator.async_add_listener(self.async_write_ha_state)) - + + async def async_added_to_hass(self) -> None: + """Subscribe to coordinator updates once added to HA.""" + await super().async_added_to_hass() + self.async_on_remove( + self.coordinator.async_add_listener(self.async_write_ha_state) + ) + def async_write_ha_state(self): if not self.enabled: _LOGGER.debug(f"Ignoring state write request for disabled entity '{self.entity_id}'")