From 082f866620643f6ad5b81edda30880d2274f918d Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Wed, 30 Sep 2020 17:24:30 +0200 Subject: [PATCH] Improve deCONZ state updates (#40601) --- .../components/deconz/binary_sensor.py | 7 +- .../components/deconz/deconz_device.py | 4 +- .../components/deconz/deconz_event.py | 7 +- homeassistant/components/deconz/gateway.py | 96 +++++++++++-------- homeassistant/components/deconz/sensor.py | 14 +-- homeassistant/components/deconz/services.py | 4 +- 6 files changed, 72 insertions(+), 60 deletions(-) diff --git a/homeassistant/components/deconz/binary_sensor.py b/homeassistant/components/deconz/binary_sensor.py index eefd66778ad..f7a9c1a5217 100644 --- a/homeassistant/components/deconz/binary_sensor.py +++ b/homeassistant/components/deconz/binary_sensor.py @@ -78,14 +78,11 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorEntity): TYPE = DOMAIN @callback - def async_update_callback(self, force_update=False, ignore_update=False): + def async_update_callback(self, force_update=False): """Update the sensor's state.""" - if ignore_update: - return - keys = {"on", "reachable", "state"} if force_update or self._device.changed_keys.intersection(keys): - self.async_write_ha_state() + super().async_update_callback(force_update=force_update) @property def is_on(self): diff --git a/homeassistant/components/deconz/deconz_device.py b/homeassistant/components/deconz/deconz_device.py index 68d96aecf35..4bcd63c8fa2 100644 --- a/homeassistant/components/deconz/deconz_device.py +++ b/homeassistant/components/deconz/deconz_device.py @@ -86,9 +86,9 @@ class DeconzDevice(DeconzBase, Entity): self.gateway.entities[self.TYPE].remove(self.unique_id) @callback - def async_update_callback(self, force_update=False, ignore_update=False): + def async_update_callback(self, force_update=False): """Update the device's state.""" - if ignore_update: + if not force_update and self.gateway.ignore_state_updates: return self.async_write_ha_state() diff --git a/homeassistant/components/deconz/deconz_event.py b/homeassistant/components/deconz/deconz_event.py index 0192c55add9..968ab3cee39 100644 --- a/homeassistant/components/deconz/deconz_event.py +++ b/homeassistant/components/deconz/deconz_event.py @@ -80,9 +80,12 @@ class DeconzEvent(DeconzBase): self._device.remove_callback(self.async_update_callback) @callback - def async_update_callback(self, force_update=False, ignore_update=False): + def async_update_callback(self, force_update=False): """Fire the event if reason is that state is updated.""" - if ignore_update or "state" not in self._device.changed_keys: + if ( + self.gateway.ignore_state_updates + or "state" not in self._device.changed_keys + ): return data = { diff --git a/homeassistant/components/deconz/gateway.py b/homeassistant/components/deconz/gateway.py index ceda49e8f83..30460725a8f 100644 --- a/homeassistant/components/deconz/gateway.py +++ b/homeassistant/components/deconz/gateway.py @@ -45,14 +45,16 @@ class DeconzGateway: self.hass = hass self.config_entry = config_entry - self.available = True self.api = None + + self.available = True + self.ignore_state_updates = False + self.deconz_ids = {} + self.entities = {} self.events = [] self.listeners = [] - self.entities = {} - self._current_option_allow_clip_sensor = self.option_allow_clip_sensor self._current_option_allow_deconz_groups = self.option_allow_deconz_groups @@ -61,11 +63,18 @@ class DeconzGateway: """Return the unique identifier of the gateway.""" return self.config_entry.unique_id + @property + def host(self) -> str: + """Return the host of the gateway.""" + return self.config_entry.data[CONF_HOST] + @property def master(self) -> bool: """Gateway which is used with deCONZ services without defining id.""" return self.config_entry.options[CONF_MASTER_GATEWAY] + # Options + @property def option_allow_clip_sensor(self) -> bool: """Allow loading clip sensor from gateway.""" @@ -87,6 +96,46 @@ class DeconzGateway: CONF_ALLOW_NEW_DEVICES, DEFAULT_ALLOW_NEW_DEVICES ) + # Signals + + @property + def signal_reachable(self) -> str: + """Gateway specific event to signal a change in connection status.""" + return f"deconz-reachable-{self.bridgeid}" + + @callback + def async_signal_new_device(self, device_type) -> str: + """Gateway specific event to signal new device.""" + new_device = { + NEW_GROUP: f"deconz_new_group_{self.bridgeid}", + NEW_LIGHT: f"deconz_new_light_{self.bridgeid}", + NEW_SCENE: f"deconz_new_scene_{self.bridgeid}", + NEW_SENSOR: f"deconz_new_sensor_{self.bridgeid}", + } + return new_device[device_type] + + # Callbacks + + @callback + def async_connection_status_callback(self, available) -> None: + """Handle signals of gateway connection status.""" + self.available = available + self.ignore_state_updates = False + async_dispatcher_send(self.hass, self.signal_reachable, True) + + @callback + def async_add_device_callback(self, device_type, device) -> None: + """Handle event of new device creation in deCONZ.""" + if not self.option_allow_new_devices: + return + + if not isinstance(device, list): + device = [device] + + async_dispatcher_send( + self.hass, self.async_signal_new_device(device_type), device + ) + async def async_update_device_registry(self) -> None: """Update device registry.""" device_registry = await self.hass.helpers.device_registry.async_get_registry() @@ -140,11 +189,13 @@ class DeconzGateway: Causes for this is either discovery updating host address or config entry options changing. """ gateway = get_gateway_from_config_entry(hass, entry) + if not gateway: return - if gateway.api.host != entry.data[CONF_HOST]: + + if gateway.api.host != gateway.host: gateway.api.close() - gateway.api.host = entry.data[CONF_HOST] + gateway.api.host = gateway.host gateway.api.start() return @@ -188,41 +239,6 @@ class DeconzGateway: # from Home Assistant entity_registry.async_remove(entity_id) - @property - def signal_reachable(self) -> str: - """Gateway specific event to signal a change in connection status.""" - return f"deconz-reachable-{self.bridgeid}" - - @callback - def async_connection_status_callback(self, available) -> None: - """Handle signals of gateway connection status.""" - self.available = available - async_dispatcher_send(self.hass, self.signal_reachable, True) - - @callback - def async_signal_new_device(self, device_type) -> str: - """Gateway specific event to signal new device.""" - new_device = { - NEW_GROUP: f"deconz_new_group_{self.bridgeid}", - NEW_LIGHT: f"deconz_new_light_{self.bridgeid}", - NEW_SCENE: f"deconz_new_scene_{self.bridgeid}", - NEW_SENSOR: f"deconz_new_sensor_{self.bridgeid}", - } - return new_device[device_type] - - @callback - def async_add_device_callback(self, device_type, device) -> None: - """Handle event of new device creation in deCONZ.""" - if not self.option_allow_new_devices: - return - - if not isinstance(device, list): - device = [device] - - async_dispatcher_send( - self.hass, self.async_signal_new_device(device_type), device - ) - @callback def shutdown(self, event) -> None: """Wrap the call to deconz.close. diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index d7210b31c43..08e81d2dd3b 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -131,14 +131,11 @@ class DeconzSensor(DeconzDevice): TYPE = DOMAIN @callback - def async_update_callback(self, force_update=False, ignore_update=False): + def async_update_callback(self, force_update=False): """Update the sensor's state.""" - if ignore_update: - return - keys = {"on", "reachable", "state"} if force_update or self._device.changed_keys.intersection(keys): - self.async_write_ha_state() + super().async_update_callback(force_update=force_update) @property def state(self): @@ -198,14 +195,11 @@ class DeconzBattery(DeconzDevice): TYPE = DOMAIN @callback - def async_update_callback(self, force_update=False, ignore_update=False): + def async_update_callback(self, force_update=False): """Update the battery's state, if needed.""" - if ignore_update: - return - keys = {"battery", "reachable"} if force_update or self._device.changed_keys.intersection(keys): - self.async_write_ha_state() + super().async_update_callback(force_update=force_update) @property def unique_id(self): diff --git a/homeassistant/components/deconz/services.py b/homeassistant/components/deconz/services.py index c85fa8073a3..aafa0880109 100644 --- a/homeassistant/components/deconz/services.py +++ b/homeassistant/components/deconz/services.py @@ -127,7 +127,9 @@ async def async_refresh_devices_service(hass, data): scenes = set(gateway.api.scenes.keys()) sensors = set(gateway.api.sensors.keys()) - await gateway.api.refresh_state(ignore_update=True) + gateway.ignore_state_updates = True + await gateway.api.refresh_state() + gateway.ignore_state_updates = False gateway.async_add_device_callback( NEW_GROUP,