Improve deCONZ state updates (#40601)

This commit is contained in:
Robert Svensson 2020-09-30 17:24:30 +02:00 committed by GitHub
parent ac71641c18
commit 082f866620
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 72 additions and 60 deletions

View File

@ -78,14 +78,11 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorEntity):
TYPE = DOMAIN TYPE = DOMAIN
@callback @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.""" """Update the sensor's state."""
if ignore_update:
return
keys = {"on", "reachable", "state"} keys = {"on", "reachable", "state"}
if force_update or self._device.changed_keys.intersection(keys): if force_update or self._device.changed_keys.intersection(keys):
self.async_write_ha_state() super().async_update_callback(force_update=force_update)
@property @property
def is_on(self): def is_on(self):

View File

@ -86,9 +86,9 @@ class DeconzDevice(DeconzBase, Entity):
self.gateway.entities[self.TYPE].remove(self.unique_id) self.gateway.entities[self.TYPE].remove(self.unique_id)
@callback @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.""" """Update the device's state."""
if ignore_update: if not force_update and self.gateway.ignore_state_updates:
return return
self.async_write_ha_state() self.async_write_ha_state()

View File

@ -80,9 +80,12 @@ class DeconzEvent(DeconzBase):
self._device.remove_callback(self.async_update_callback) self._device.remove_callback(self.async_update_callback)
@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.""" """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 return
data = { data = {

View File

@ -45,14 +45,16 @@ class DeconzGateway:
self.hass = hass self.hass = hass
self.config_entry = config_entry self.config_entry = config_entry
self.available = True
self.api = None self.api = None
self.available = True
self.ignore_state_updates = False
self.deconz_ids = {} self.deconz_ids = {}
self.entities = {}
self.events = [] self.events = []
self.listeners = [] self.listeners = []
self.entities = {}
self._current_option_allow_clip_sensor = self.option_allow_clip_sensor self._current_option_allow_clip_sensor = self.option_allow_clip_sensor
self._current_option_allow_deconz_groups = self.option_allow_deconz_groups 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 the unique identifier of the gateway."""
return self.config_entry.unique_id 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 @property
def master(self) -> bool: def master(self) -> bool:
"""Gateway which is used with deCONZ services without defining id.""" """Gateway which is used with deCONZ services without defining id."""
return self.config_entry.options[CONF_MASTER_GATEWAY] return self.config_entry.options[CONF_MASTER_GATEWAY]
# Options
@property @property
def option_allow_clip_sensor(self) -> bool: def option_allow_clip_sensor(self) -> bool:
"""Allow loading clip sensor from gateway.""" """Allow loading clip sensor from gateway."""
@ -87,6 +96,46 @@ class DeconzGateway:
CONF_ALLOW_NEW_DEVICES, DEFAULT_ALLOW_NEW_DEVICES 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: async def async_update_device_registry(self) -> None:
"""Update device registry.""" """Update device registry."""
device_registry = await self.hass.helpers.device_registry.async_get_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. Causes for this is either discovery updating host address or config entry options changing.
""" """
gateway = get_gateway_from_config_entry(hass, entry) gateway = get_gateway_from_config_entry(hass, entry)
if not gateway: if not gateway:
return return
if gateway.api.host != entry.data[CONF_HOST]:
if gateway.api.host != gateway.host:
gateway.api.close() gateway.api.close()
gateway.api.host = entry.data[CONF_HOST] gateway.api.host = gateway.host
gateway.api.start() gateway.api.start()
return return
@ -188,41 +239,6 @@ class DeconzGateway:
# from Home Assistant # from Home Assistant
entity_registry.async_remove(entity_id) 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 @callback
def shutdown(self, event) -> None: def shutdown(self, event) -> None:
"""Wrap the call to deconz.close. """Wrap the call to deconz.close.

View File

@ -131,14 +131,11 @@ class DeconzSensor(DeconzDevice):
TYPE = DOMAIN TYPE = DOMAIN
@callback @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.""" """Update the sensor's state."""
if ignore_update:
return
keys = {"on", "reachable", "state"} keys = {"on", "reachable", "state"}
if force_update or self._device.changed_keys.intersection(keys): if force_update or self._device.changed_keys.intersection(keys):
self.async_write_ha_state() super().async_update_callback(force_update=force_update)
@property @property
def state(self): def state(self):
@ -198,14 +195,11 @@ class DeconzBattery(DeconzDevice):
TYPE = DOMAIN TYPE = DOMAIN
@callback @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.""" """Update the battery's state, if needed."""
if ignore_update:
return
keys = {"battery", "reachable"} keys = {"battery", "reachable"}
if force_update or self._device.changed_keys.intersection(keys): if force_update or self._device.changed_keys.intersection(keys):
self.async_write_ha_state() super().async_update_callback(force_update=force_update)
@property @property
def unique_id(self): def unique_id(self):

View File

@ -127,7 +127,9 @@ async def async_refresh_devices_service(hass, data):
scenes = set(gateway.api.scenes.keys()) scenes = set(gateway.api.scenes.keys())
sensors = set(gateway.api.sensors.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( gateway.async_add_device_callback(
NEW_GROUP, NEW_GROUP,