Skip to content
Snippets Groups Projects
Commit 645c3a67 authored by Robert Svensson's avatar Robert Svensson Committed by Paulus Schoutsen
Browse files

Fix so that entities are properly unloaded with config entry (#16281)

parent 88f72a65
No related branches found
No related tags found
No related merge requests found
...@@ -54,6 +54,11 @@ class DeconzBinarySensor(BinarySensorDevice): ...@@ -54,6 +54,11 @@ class DeconzBinarySensor(BinarySensorDevice):
self._sensor.register_async_callback(self.async_update_callback) self._sensor.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id
async def async_will_remove_from_hass(self) -> None:
"""Disconnect sensor object when removed."""
self._sensor.remove_callback(self.async_update_callback)
self._sensor = None
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
"""Update the sensor's state. """Update the sensor's state.
......
...@@ -24,7 +24,7 @@ from .const import ( ...@@ -24,7 +24,7 @@ from .const import (
CONF_ALLOW_CLIP_SENSOR, CONFIG_FILE, DATA_DECONZ_EVENT, CONF_ALLOW_CLIP_SENSOR, CONFIG_FILE, DATA_DECONZ_EVENT,
DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DOMAIN, _LOGGER) DATA_DECONZ_ID, DATA_DECONZ_UNSUB, DOMAIN, _LOGGER)
REQUIREMENTS = ['pydeconz==44'] REQUIREMENTS = ['pydeconz==45']
CONFIG_SCHEMA = vol.Schema({ CONFIG_SCHEMA = vol.Schema({
DOMAIN: vol.Schema({ DOMAIN: vol.Schema({
...@@ -179,15 +179,22 @@ async def async_unload_entry(hass, config_entry): ...@@ -179,15 +179,22 @@ async def async_unload_entry(hass, config_entry):
deconz = hass.data.pop(DOMAIN) deconz = hass.data.pop(DOMAIN)
hass.services.async_remove(DOMAIN, SERVICE_DECONZ) hass.services.async_remove(DOMAIN, SERVICE_DECONZ)
deconz.close() deconz.close()
for component in ['binary_sensor', 'light', 'scene', 'sensor']:
for component in ['binary_sensor', 'light', 'scene', 'sensor', 'switch']:
await hass.config_entries.async_forward_entry_unload( await hass.config_entries.async_forward_entry_unload(
config_entry, component) config_entry, component)
dispatchers = hass.data[DATA_DECONZ_UNSUB] dispatchers = hass.data[DATA_DECONZ_UNSUB]
for unsub_dispatcher in dispatchers: for unsub_dispatcher in dispatchers:
unsub_dispatcher() unsub_dispatcher()
hass.data[DATA_DECONZ_UNSUB] = [] hass.data[DATA_DECONZ_UNSUB] = []
hass.data[DATA_DECONZ_EVENT] = []
for event in hass.data[DATA_DECONZ_EVENT]:
event.async_will_remove_from_hass()
hass.data[DATA_DECONZ_EVENT].remove(event)
hass.data[DATA_DECONZ_ID] = [] hass.data[DATA_DECONZ_ID] = []
return True return True
...@@ -206,6 +213,12 @@ class DeconzEvent: ...@@ -206,6 +213,12 @@ class DeconzEvent:
self._event = 'deconz_{}'.format(CONF_EVENT) self._event = 'deconz_{}'.format(CONF_EVENT)
self._id = slugify(self._device.name) self._id = slugify(self._device.name)
@callback
def async_will_remove_from_hass(self) -> None:
"""Disconnect event object when removed."""
self._device.remove_callback(self.async_update_callback)
self._device = None
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
"""Fire the event if reason is that state is updated.""" """Fire the event if reason is that state is updated."""
......
...@@ -82,6 +82,11 @@ class DeconzLight(Light): ...@@ -82,6 +82,11 @@ class DeconzLight(Light):
self._light.register_async_callback(self.async_update_callback) self._light.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._light.deconz_id self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._light.deconz_id
async def async_will_remove_from_hass(self) -> None:
"""Disconnect light object when removed."""
self._light.remove_callback(self.async_update_callback)
self._light = None
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
"""Update the light's state.""" """Update the light's state."""
......
...@@ -38,6 +38,10 @@ class DeconzScene(Scene): ...@@ -38,6 +38,10 @@ class DeconzScene(Scene):
"""Subscribe to sensors events.""" """Subscribe to sensors events."""
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._scene.deconz_id self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._scene.deconz_id
async def async_will_remove_from_hass(self) -> None:
"""Disconnect scene object when removed."""
self._scene = None
async def async_activate(self): async def async_activate(self):
"""Activate the scene.""" """Activate the scene."""
await self._scene.async_set_state({}) await self._scene.async_set_state({})
......
...@@ -64,6 +64,11 @@ class DeconzSensor(Entity): ...@@ -64,6 +64,11 @@ class DeconzSensor(Entity):
self._sensor.register_async_callback(self.async_update_callback) self._sensor.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id
async def async_will_remove_from_hass(self) -> None:
"""Disconnect sensor object when removed."""
self._sensor.remove_callback(self.async_update_callback)
self._sensor = None
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
"""Update the sensor's state. """Update the sensor's state.
...@@ -155,16 +160,21 @@ class DeconzSensor(Entity): ...@@ -155,16 +160,21 @@ class DeconzSensor(Entity):
class DeconzBattery(Entity): class DeconzBattery(Entity):
"""Battery class for when a device is only represented as an event.""" """Battery class for when a device is only represented as an event."""
def __init__(self, device): def __init__(self, sensor):
"""Register dispatcher callback for update of battery state.""" """Register dispatcher callback for update of battery state."""
self._device = device self._sensor = sensor
self._name = '{} {}'.format(self._device.name, 'Battery Level') self._name = '{} {}'.format(self._sensor.name, 'Battery Level')
self._unit_of_measurement = "%" self._unit_of_measurement = "%"
async def async_added_to_hass(self): async def async_added_to_hass(self):
"""Subscribe to sensors events.""" """Subscribe to sensors events."""
self._device.register_async_callback(self.async_update_callback) self._sensor.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._device.deconz_id self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._sensor.deconz_id
async def async_will_remove_from_hass(self) -> None:
"""Disconnect sensor object when removed."""
self._sensor.remove_callback(self.async_update_callback)
self._sensor = None
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
...@@ -175,7 +185,7 @@ class DeconzBattery(Entity): ...@@ -175,7 +185,7 @@ class DeconzBattery(Entity):
@property @property
def state(self): def state(self):
"""Return the state of the battery.""" """Return the state of the battery."""
return self._device.battery return self._sensor.battery
@property @property
def name(self): def name(self):
...@@ -185,7 +195,7 @@ class DeconzBattery(Entity): ...@@ -185,7 +195,7 @@ class DeconzBattery(Entity):
@property @property
def unique_id(self): def unique_id(self):
"""Return a unique identifier for the device.""" """Return a unique identifier for the device."""
return self._device.uniqueid return self._sensor.uniqueid
@property @property
def device_class(self): def device_class(self):
...@@ -206,22 +216,22 @@ class DeconzBattery(Entity): ...@@ -206,22 +216,22 @@ class DeconzBattery(Entity):
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes of the battery.""" """Return the state attributes of the battery."""
attr = { attr = {
ATTR_EVENT_ID: slugify(self._device.name), ATTR_EVENT_ID: slugify(self._sensor.name),
} }
return attr return attr
@property @property
def device_info(self): def device_info(self):
"""Return a device description for device registry.""" """Return a device description for device registry."""
if (self._device.uniqueid is None or if (self._sensor.uniqueid is None or
self._device.uniqueid.count(':') != 7): self._sensor.uniqueid.count(':') != 7):
return None return None
serial = self._device.uniqueid.split('-', 1)[0] serial = self._sensor.uniqueid.split('-', 1)[0]
return { return {
'connections': {(CONNECTION_ZIGBEE, serial)}, 'connections': {(CONNECTION_ZIGBEE, serial)},
'identifiers': {(DECONZ_DOMAIN, serial)}, 'identifiers': {(DECONZ_DOMAIN, serial)},
'manufacturer': self._device.manufacturer, 'manufacturer': self._sensor.manufacturer,
'model': self._device.modelid, 'model': self._sensor.modelid,
'name': self._device.name, 'name': self._sensor.name,
'sw_version': self._device.swversion, 'sw_version': self._sensor.swversion,
} }
...@@ -55,6 +55,11 @@ class DeconzSwitch(SwitchDevice): ...@@ -55,6 +55,11 @@ class DeconzSwitch(SwitchDevice):
self._switch.register_async_callback(self.async_update_callback) self._switch.register_async_callback(self.async_update_callback)
self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._switch.deconz_id self.hass.data[DATA_DECONZ_ID][self.entity_id] = self._switch.deconz_id
async def async_will_remove_from_hass(self) -> None:
"""Disconnect switch object when removed."""
self._switch.remove_callback(self.async_update_callback)
self._switch = None
@callback @callback
def async_update_callback(self, reason): def async_update_callback(self, reason):
"""Update the switch's state.""" """Update the switch's state."""
......
...@@ -820,7 +820,7 @@ pycsspeechtts==1.0.2 ...@@ -820,7 +820,7 @@ pycsspeechtts==1.0.2
pydaikin==0.4 pydaikin==0.4
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==44 pydeconz==45
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5
......
...@@ -139,7 +139,7 @@ py-canary==0.5.0 ...@@ -139,7 +139,7 @@ py-canary==0.5.0
pyblackbird==0.5 pyblackbird==0.5
# homeassistant.components.deconz # homeassistant.components.deconz
pydeconz==44 pydeconz==45
# homeassistant.components.zwave # homeassistant.components.zwave
pydispatcher==2.0.5 pydispatcher==2.0.5
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment