From 9d578bdf3b7e1e5553c042f747011aa5f7ca51ae Mon Sep 17 00:00:00 2001 From: Andreas Lindroos Date: Sat, 3 Oct 2026 16:52:20 +0300 Subject: [PATCH] Cleans up sensors on Nordpool entry reload in HA --- custom_components/nordpool/__init__.py | 9 ++++++--- custom_components/nordpool/sensor.py | 22 ++++++++++++++++++---- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/custom_components/nordpool/__init__.py b/custom_components/nordpool/__init__.py index f9a7dca..90386e0 100644 --- a/custom_components/nordpool/__init__.py +++ b/custom_components/nordpool/__init__.py @@ -210,7 +210,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: res = await _dry_setup(hass, entry.data) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - entry.add_update_listener(async_reload_entry) + # async_on_unload removes the listener on unload, so reloads don't stack + # up extra update listeners (each one triggers another reload). + entry.async_on_unload(entry.add_update_listener(async_reload_entry)) return res @@ -234,5 +236,6 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None: """Reload config entry.""" - await async_unload_entry(hass, entry) - await async_setup_entry(hass, entry) + # Go through HA's own reload so the entry's async_on_unload callbacks + # (the update listener above) actually run before setup adds new ones. + await hass.config_entries.async_reload(entry.entry_id) diff --git a/custom_components/nordpool/sensor.py b/custom_components/nordpool/sensor.py index f4efb8e..77e17c8 100644 --- a/custom_components/nordpool/sensor.py +++ b/custom_components/nordpool/sensor.py @@ -484,9 +484,23 @@ async def async_added_to_hass(self): await super().async_added_to_hass() _LOGGER.debug("called async_added_to_hass %s", self.name) - async_dispatcher_connect(self._api._hass, EVENT_NEW_DAY, self.handle_new_day) - async_dispatcher_connect( - self._api._hass, EVENT_NEW_PRICE, self.handle_new_price + # async_on_remove disconnects these when the entity is removed (e.g. on + # a config entry reload). Without it the removed sensor objects stay + # subscribed and keep recalculating every 15 min, piling up on each + # reload until EVENT_NEW_HOUR blocks the event loop for minutes. + self.async_on_remove( + async_dispatcher_connect( + self._api._hass, EVENT_NEW_DAY, self.handle_new_day + ) + ) + self.async_on_remove( + async_dispatcher_connect( + self._api._hass, EVENT_NEW_PRICE, self.handle_new_price + ) + ) + self.async_on_remove( + async_dispatcher_connect( + self._api._hass, EVENT_NEW_HOUR, self.handle_new_hr + ) ) - async_dispatcher_connect(self._api._hass, EVENT_NEW_HOUR, self.handle_new_hr) await self.handle_new_hr()