From d18b2a9da6c64aeef950afbcc6398339b05d27d0 Mon Sep 17 00:00:00 2001 From: Bas Nijholt Date: Mon, 28 Sep 2020 23:39:55 +0200 Subject: [PATCH] fix unsub sub --- .../adaptive_lighting/__init__.py | 14 ++-- custom_components/adaptive_lighting/switch.py | 67 ++++++++++++------- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/custom_components/adaptive_lighting/__init__.py b/custom_components/adaptive_lighting/__init__.py index 1e935df7..5c0aa080 100755 --- a/custom_components/adaptive_lighting/__init__.py +++ b/custom_components/adaptive_lighting/__init__.py @@ -29,6 +29,7 @@ import logging import voluptuous as vol +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry import homeassistant.helpers.config_validation as cv @@ -68,10 +69,10 @@ async def async_setup(hass, config): async def async_setup_entry(hass, config_entry: ConfigEntry): """Set up the component.""" - hass.data.setdefault(DOMAIN, {}) + data = hass.data.setdefault(DOMAIN, {}) undo_listener = config_entry.add_update_listener(async_update_options) - hass.data[DOMAIN][config_entry.entry_id] = {UNDO_UPDATE_LISTENER: undo_listener} + data[config_entry.entry_id] = {UNDO_UPDATE_LISTENER: undo_listener} for platform in PLATFORMS: hass.async_create_task( hass.config_entries.async_forward_entry_setup(config_entry, platform) @@ -95,9 +96,14 @@ async def async_unload_entry(hass, config_entry: ConfigEntry) -> bool: ] ) ) - hass.data[DOMAIN][config_entry.entry_id][UNDO_UPDATE_LISTENER]() + data = hass.data[DOMAIN] + data[config_entry.entry_id][UNDO_UPDATE_LISTENER]() + switch = data[config_entry.entry_id][SWITCH_DOMAIN] + while switch.unsub_trackers: + unsub = switch.unsub_trackers.pop() + unsub() if unload_ok: - hass.data[DOMAIN].pop(config_entry.entry_id) + data.pop(config_entry.entry_id) return unload_ok diff --git a/custom_components/adaptive_lighting/switch.py b/custom_components/adaptive_lighting/switch.py index efd19bf3..482780be 100755 --- a/custom_components/adaptive_lighting/switch.py +++ b/custom_components/adaptive_lighting/switch.py @@ -23,7 +23,7 @@ from homeassistant.components.light import ( VALID_TRANSITION, is_on, ) -from homeassistant.components.switch import SwitchEntity +from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN, SwitchEntity from homeassistant.const import ( ATTR_DOMAIN, ATTR_ENTITY_ID, @@ -130,16 +130,14 @@ async def handle_apply(switch, service_call): async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the AdaptiveLighting switch.""" - if DOMAIN not in hass.data: - hass.data[DOMAIN] = {} + data = hass.data[DOMAIN] - if ATTR_TURN_ON_OFF_LISTENER not in hass.data[DOMAIN]: - hass.data[DOMAIN][ATTR_TURN_ON_OFF_LISTENER] = TurnOnOffListener(hass) + if ATTR_TURN_ON_OFF_LISTENER not in data: + data[ATTR_TURN_ON_OFF_LISTENER] = TurnOnOffListener(hass) + turn_on_off_listener = data[ATTR_TURN_ON_OFF_LISTENER] - turn_on_off_listener = hass.data[DOMAIN][ATTR_TURN_ON_OFF_LISTENER] switch = AdaptiveSwitch(hass, config_entry, turn_on_off_listener) - name = config_entry.data[CONF_NAME] - hass.data[DOMAIN][name] = switch + data[config_entry.entry_id][SWITCH_DOMAIN] = switch # Register `apply` service platform = entity_platform.current_platform.get() @@ -185,9 +183,9 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): self._name = data[CONF_NAME] self._lights = data[CONF_LIGHTS] self._disable_brightness_adjust = data[CONF_DISABLE_BRIGHTNESS_ADJUST] - self._disable_rgb_color_adjust = data[CONF_DISABLE_RGB_COLOR_ADJUST] self._disable_color_temp_adjust = data[CONF_DISABLE_COLOR_TEMP_ADJUST] self._disable_entity = data[CONF_DISABLE_ENTITY] + self._disable_rgb_color_adjust = data[CONF_DISABLE_RGB_COLOR_ADJUST] self._disable_state = data[CONF_DISABLE_STATE] self._initial_transition = data[CONF_INITIAL_TRANSITION] self._interval = data[CONF_INTERVAL] @@ -226,7 +224,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): self._hs_color = None # Set and unset tracker in async_turn_on and async_turn_off - self.unsub_tracker = None + self.unsub_trackers = [] _LOGGER.debug( "%s: Setting up with '%s'," " config_entry.data: '%s'," @@ -251,7 +249,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): @property def is_on(self): """Return true if adaptive lighting is on.""" - return self.unsub_tracker is not None + return bool(self.unsub_trackers) def _supported_features(self, light): state = self.hass.states.get(light) @@ -271,7 +269,7 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): ) last_state = await self.async_get_last_state() if last_state and last_state.state == STATE_ON: - await self.async_turn_on(adjust_lights=False) + await self.async_turn_on(adjust_lights=False, setup_listeners=False) def _unpack_light_groups(self) -> None: all_lights = [] @@ -292,17 +290,29 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): self._unpack_light_groups() for light in self._lights: self.turn_on_off_listener.lights.add(light) - async_track_state_change_event(self.hass, self._lights, self._light_event) + self.unsub_trackers.append( + async_track_state_change_event(self.hass, self._lights, self._light_event) + ) track_kwargs = dict(hass=self.hass, action=self._state_changed) if self._sleep_entity is not None: sleep_kwargs = dict(track_kwargs, entity_ids=self._sleep_entity) - async_track_state_change(**sleep_kwargs, to_state=self._sleep_state) - async_track_state_change(**sleep_kwargs, from_state=self._sleep_state) + self.unsub_trackers.append( + async_track_state_change(**sleep_kwargs, to_state=self._sleep_state) + ) + self.unsub_trackers.append( + async_track_state_change(**sleep_kwargs, from_state=self._sleep_state) + ) if self._disable_entity is not None: disable_kwargs = dict(track_kwargs, entity_ids=self._disable_entity) - async_track_state_change(**disable_kwargs, from_state=self._disable_state) - async_track_state_change(**disable_kwargs, to_state=self._disable_state) + self.unsub_trackers.append( + async_track_state_change( + **disable_kwargs, from_state=self._disable_state + ) + ) + self.unsub_trackers.append( + async_track_state_change(**disable_kwargs, to_state=self._disable_state) + ) @property def icon(self): @@ -325,19 +335,27 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): return {key: None for key in attrs} return attrs - async def async_turn_on(self, adjust_lights=True): + async def async_turn_on(self, adjust_lights=True, setup_listeners=True): """Turn on adaptive lighting.""" - self.unsub_tracker = async_track_time_interval( - self.hass, self._async_update_at_interval, self._interval + if self.is_on: + return + self.unsub_trackers.append( + async_track_time_interval( + self.hass, self._async_update_at_interval, self._interval + ) ) + if setup_listeners: + self._setup_listeners() if adjust_lights: await self._update_lights(transition=self._initial_transition, force=True) async def async_turn_off(self, **kwargs): """Turn off adaptive lighting.""" - if self.is_on: - self.unsub_tracker() - self.unsub_tracker = None + if not self.is_on: + return + while self.unsub_trackers: + unsub = self.unsub_trackers.pop() + unsub() async def _update_attrs(self): """Update Adaptive Values.""" @@ -476,11 +494,10 @@ class AdaptiveSwitch(SwitchEntity, RestoreEntity): ): service_data[ATTR_BRIGHTNESS_PCT] = self._brightness - prefer_rgb_color = self._prefer_rgb_color if ( "color_temp" in features and not self._disable_color_temp_adjust - and not (prefer_rgb_color and "color" in features) + and not (self._prefer_rgb_color and "color" in features) ): attributes = self.hass.states.get(light).attributes min_mireds, max_mireds = attributes["min_mireds"], attributes["max_mireds"]