diff --git a/homeassistant/components/deconz/binary_sensor.py b/homeassistant/components/deconz/binary_sensor.py index c67a4673983..286b310c1a9 100644 --- a/homeassistant/components/deconz/binary_sensor.py +++ b/homeassistant/components/deconz/binary_sensor.py @@ -7,12 +7,11 @@ https://home-assistant.io/components/binary_sensor.deconz/ from homeassistant.components.binary_sensor import BinarySensorDevice from homeassistant.const import ATTR_BATTERY_LEVEL from homeassistant.core import callback -from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect from .const import ( - ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DECONZ_REACHABLE, - DOMAIN as DECONZ_DOMAIN) + ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DECONZ_DOMAIN) +from .deconz_device import DeconzDevice DEPENDENCIES = ['deconz'] @@ -45,28 +44,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_sensor(gateway.api.sensors.values()) -class DeconzBinarySensor(BinarySensorDevice): - """Representation of a binary sensor.""" - - def __init__(self, sensor, gateway): - """Set up sensor and add update callback to get data from websocket.""" - self._sensor = sensor - self.gateway = gateway - self.unsub_dispatcher = None - - async def async_added_to_hass(self): - """Subscribe sensors events.""" - self._sensor.register_async_callback(self.async_update_callback) - self.gateway.deconz_ids[self.entity_id] = self._sensor.deconz_id - self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) - - async def async_will_remove_from_hass(self) -> None: - """Disconnect sensor object when removed.""" - if self.unsub_dispatcher is not None: - self.unsub_dispatcher() - self._sensor.remove_callback(self.async_update_callback) - self._sensor = None +class DeconzBinarySensor(DeconzDevice, BinarySensorDevice): + """Representation of a deCONZ binary sensor.""" @callback def async_update_callback(self, reason): @@ -84,65 +63,27 @@ class DeconzBinarySensor(BinarySensorDevice): @property def is_on(self): """Return true if sensor is on.""" - return self._sensor.is_tripped - - @property - def name(self): - """Return the name of the sensor.""" - return self._sensor.name - - @property - def unique_id(self): - """Return a unique identifier for this sensor.""" - return self._sensor.uniqueid + return self._device.is_tripped @property def device_class(self): """Return the class of the sensor.""" - return self._sensor.sensor_class + return self._device.sensor_class @property def icon(self): """Return the icon to use in the frontend.""" - return self._sensor.sensor_icon - - @property - def available(self): - """Return True if sensor is available.""" - return self.gateway.available and self._sensor.reachable - - @property - def should_poll(self): - """No polling needed.""" - return False + return self._device.sensor_icon @property def device_state_attributes(self): """Return the state attributes of the sensor.""" from pydeconz.sensor import PRESENCE attr = {} - if self._sensor.battery: - attr[ATTR_BATTERY_LEVEL] = self._sensor.battery - if self._sensor.on is not None: - attr[ATTR_ON] = self._sensor.on - if self._sensor.type in PRESENCE and self._sensor.dark is not None: - attr[ATTR_DARK] = self._sensor.dark + if self._device.battery: + attr[ATTR_BATTERY_LEVEL] = self._device.battery + if self._device.on is not None: + attr[ATTR_ON] = self._device.on + if self._device.type in PRESENCE and self._device.dark is not None: + attr[ATTR_DARK] = self._device.dark return attr - - @property - def device_info(self): - """Return a device description for device registry.""" - if (self._sensor.uniqueid is None or - self._sensor.uniqueid.count(':') != 7): - return None - serial = self._sensor.uniqueid.split('-', 1)[0] - bridgeid = self.gateway.api.config.bridgeid - return { - 'connections': {(CONNECTION_ZIGBEE, serial)}, - 'identifiers': {(DECONZ_DOMAIN, serial)}, - 'manufacturer': self._sensor.manufacturer, - 'model': self._sensor.modelid, - 'name': self._sensor.name, - 'sw_version': self._sensor.swversion, - 'via_hub': (DECONZ_DOMAIN, bridgeid), - } diff --git a/homeassistant/components/deconz/cover.py b/homeassistant/components/deconz/cover.py index ffd5c912a37..99bdd20a295 100644 --- a/homeassistant/components/deconz/cover.py +++ b/homeassistant/components/deconz/cover.py @@ -8,12 +8,10 @@ from homeassistant.components.cover import ( ATTR_POSITION, CoverDevice, SUPPORT_CLOSE, SUPPORT_OPEN, SUPPORT_STOP, SUPPORT_SET_POSITION) from homeassistant.core import callback -from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import ( - COVER_TYPES, DAMPERS, DECONZ_REACHABLE, DOMAIN as DECONZ_DOMAIN, - WINDOW_COVERS) +from .const import COVER_TYPES, DAMPERS, DOMAIN as DECONZ_DOMAIN, WINDOW_COVERS +from .deconz_device import DeconzDevice DEPENDENCIES = ['deconz'] @@ -51,67 +49,36 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_cover(gateway.api.lights.values()) -class DeconzCover(CoverDevice): +class DeconzCover(DeconzDevice, CoverDevice): """Representation of a deCONZ cover.""" - def __init__(self, cover, gateway): + def __init__(self, device, gateway): """Set up cover and add update callback to get data from websocket.""" - self._cover = cover - self.gateway = gateway - self.unsub_dispatcher = None + super().__init__(device, gateway) self._features = SUPPORT_OPEN self._features |= SUPPORT_CLOSE self._features |= SUPPORT_STOP self._features |= SUPPORT_SET_POSITION - async def async_added_to_hass(self): - """Subscribe to covers events.""" - self._cover.register_async_callback(self.async_update_callback) - self.gateway.deconz_ids[self.entity_id] = self._cover.deconz_id - self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) - - async def async_will_remove_from_hass(self) -> None: - """Disconnect cover object when removed.""" - if self.unsub_dispatcher is not None: - self.unsub_dispatcher() - self._cover.remove_callback(self.async_update_callback) - self._cover = None - - @callback - def async_update_callback(self, reason): - """Update the cover's state.""" - self.async_schedule_update_ha_state() - @property def current_cover_position(self): """Return the current position of the cover.""" if self.is_closed: return 0 - return int(self._cover.brightness / 255 * 100) + return int(self._device.brightness / 255 * 100) @property def is_closed(self): """Return if the cover is closed.""" - return not self._cover.state - - @property - def name(self): - """Return the name of the cover.""" - return self._cover.name - - @property - def unique_id(self): - """Return a unique identifier for this cover.""" - return self._cover.uniqueid + return not self._device.state @property def device_class(self): """Return the class of the cover.""" - if self._cover.type in DAMPERS: + if self._device.type in DAMPERS: return 'damper' - if self._cover.type in WINDOW_COVERS: + if self._device.type in WINDOW_COVERS: return 'window' @property @@ -119,16 +86,6 @@ class DeconzCover(CoverDevice): """Flag supported features.""" return self._features - @property - def available(self): - """Return True if light is available.""" - return self.gateway.available and self._cover.reachable - - @property - def should_poll(self): - """No polling needed.""" - return False - async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" position = kwargs[ATTR_POSITION] @@ -136,7 +93,7 @@ class DeconzCover(CoverDevice): if position > 0: data['on'] = True data['bri'] = int(position / 100 * 255) - await self._cover.async_set_state(data) + await self._device.async_set_state(data) async def async_open_cover(self, **kwargs): """Open cover.""" @@ -151,25 +108,7 @@ class DeconzCover(CoverDevice): async def async_stop_cover(self, **kwargs): """Stop cover.""" data = {'bri_inc': 0} - await self._cover.async_set_state(data) - - @property - def device_info(self): - """Return a device description for device registry.""" - if (self._cover.uniqueid is None or - self._cover.uniqueid.count(':') != 7): - return None - serial = self._cover.uniqueid.split('-', 1)[0] - bridgeid = self.gateway.api.config.bridgeid - return { - 'connections': {(CONNECTION_ZIGBEE, serial)}, - 'identifiers': {(DECONZ_DOMAIN, serial)}, - 'manufacturer': self._cover.manufacturer, - 'model': self._cover.modelid, - 'name': self._cover.name, - 'sw_version': self._cover.swversion, - 'via_hub': (DECONZ_DOMAIN, bridgeid), - } + await self._device.async_set_state(data) class DeconzCoverZigbeeSpec(DeconzCover): @@ -178,12 +117,12 @@ class DeconzCoverZigbeeSpec(DeconzCover): @property def current_cover_position(self): """Return the current position of the cover.""" - return 100 - int(self._cover.brightness / 255 * 100) + return 100 - int(self._device.brightness / 255 * 100) @property def is_closed(self): """Return if the cover is closed.""" - return self._cover.state + return self._device.state async def async_set_cover_position(self, **kwargs): """Move the cover to a specific position.""" @@ -192,4 +131,4 @@ class DeconzCoverZigbeeSpec(DeconzCover): if position < 100: data['on'] = True data['bri'] = 255 - int(position / 100 * 255) - await self._cover.async_set_state(data) + await self._device.async_set_state(data) diff --git a/homeassistant/components/deconz/deconz_device.py b/homeassistant/components/deconz/deconz_device.py new file mode 100644 index 00000000000..bfcbd158b9f --- /dev/null +++ b/homeassistant/components/deconz/deconz_device.py @@ -0,0 +1,74 @@ +"""Base class for deCONZ devices.""" +from homeassistant.core import callback +from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity import Entity + +from .const import DECONZ_REACHABLE, DOMAIN as DECONZ_DOMAIN + + +class DeconzDevice(Entity): + """Representation of a deCONZ device.""" + + def __init__(self, device, gateway): + """Set up device and add update callback to get data from websocket.""" + self._device = device + self.gateway = gateway + self.unsub_dispatcher = None + + async def async_added_to_hass(self): + """Subscribe to device events.""" + self._device.register_async_callback(self.async_update_callback) + self.gateway.deconz_ids[self.entity_id] = self._device.deconz_id + self.unsub_dispatcher = async_dispatcher_connect( + self.hass, DECONZ_REACHABLE, self.async_update_callback) + + async def async_will_remove_from_hass(self) -> None: + """Disconnect device object when removed.""" + if self.unsub_dispatcher is not None: + self.unsub_dispatcher() + self._device.remove_callback(self.async_update_callback) + self._device = None + + @callback + def async_update_callback(self, reason): + """Update the device's state.""" + self.async_schedule_update_ha_state() + + @property + def name(self): + """Return the name of the device.""" + return self._device.name + + @property + def unique_id(self): + """Return a unique identifier for this device.""" + return self._device.uniqueid + + @property + def available(self): + """Return True if device is available.""" + return self.gateway.available and self._device.reachable + + @property + def should_poll(self): + """No polling needed.""" + return False + + @property + def device_info(self): + """Return a device description for device registry.""" + if (self._device.uniqueid is None or + self._device.uniqueid.count(':') != 7): + return None + serial = self._device.uniqueid.split('-', 1)[0] + bridgeid = self.gateway.api.config.bridgeid + return { + 'connections': {(CONNECTION_ZIGBEE, serial)}, + 'identifiers': {(DECONZ_DOMAIN, serial)}, + 'manufacturer': self._device.manufacturer, + 'model': self._device.modelid, + 'name': self._device.name, + 'sw_version': self._device.swversion, + 'via_hub': (DECONZ_DOMAIN, bridgeid), + } diff --git a/homeassistant/components/deconz/light.py b/homeassistant/components/deconz/light.py index a7ad38dd8b7..f7c777b8100 100644 --- a/homeassistant/components/deconz/light.py +++ b/homeassistant/components/deconz/light.py @@ -10,13 +10,13 @@ from homeassistant.components.light import ( SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_EFFECT, SUPPORT_FLASH, SUPPORT_TRANSITION, Light) from homeassistant.core import callback -from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect import homeassistant.util.color as color_util from .const import ( - CONF_ALLOW_DECONZ_GROUPS, DECONZ_REACHABLE, DOMAIN as DECONZ_DOMAIN, - COVER_TYPES, SWITCH_TYPES) + CONF_ALLOW_DECONZ_GROUPS, DOMAIN as DECONZ_DOMAIN, COVER_TYPES, + SWITCH_TYPES) +from .deconz_device import DeconzDevice DEPENDENCIES = ['deconz'] @@ -60,51 +60,30 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_group(gateway.api.groups.values()) -class DeconzLight(Light): +class DeconzLight(DeconzDevice, Light): """Representation of a deCONZ light.""" - def __init__(self, light, gateway): + def __init__(self, device, gateway): """Set up light and add update callback to get data from websocket.""" - self._light = light - self.gateway = gateway - self.unsub_dispatcher = None + super().__init__(device, gateway) self._features = SUPPORT_BRIGHTNESS self._features |= SUPPORT_FLASH self._features |= SUPPORT_TRANSITION - if self._light.ct is not None: + if self._device.ct is not None: self._features |= SUPPORT_COLOR_TEMP - if self._light.xy is not None: + if self._device.xy is not None: self._features |= SUPPORT_COLOR - if self._light.effect is not None: + if self._device.effect is not None: self._features |= SUPPORT_EFFECT - async def async_added_to_hass(self): - """Subscribe to lights events.""" - self._light.register_async_callback(self.async_update_callback) - self.gateway.deconz_ids[self.entity_id] = self._light.deconz_id - self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) - - async def async_will_remove_from_hass(self) -> None: - """Disconnect light object when removed.""" - if self.unsub_dispatcher is not None: - self.unsub_dispatcher() - self._light.remove_callback(self.async_update_callback) - self._light = None - - @callback - def async_update_callback(self, reason): - """Update the light's state.""" - self.async_schedule_update_ha_state() - @property def brightness(self): """Return the brightness of this light between 0..255.""" - return self._light.brightness + return self._device.brightness @property def effect_list(self): @@ -114,48 +93,28 @@ class DeconzLight(Light): @property def color_temp(self): """Return the CT color value.""" - if self._light.colormode != 'ct': + if self._device.colormode != 'ct': return None - return self._light.ct + return self._device.ct @property def hs_color(self): """Return the hs color value.""" - if self._light.colormode in ('xy', 'hs') and self._light.xy: - return color_util.color_xy_to_hs(*self._light.xy) + if self._device.colormode in ('xy', 'hs') and self._device.xy: + return color_util.color_xy_to_hs(*self._device.xy) return None @property def is_on(self): """Return true if light is on.""" - return self._light.state - - @property - def name(self): - """Return the name of the light.""" - return self._light.name - - @property - def unique_id(self): - """Return a unique identifier for this light.""" - return self._light.uniqueid + return self._device.state @property def supported_features(self): """Flag supported features.""" return self._features - @property - def available(self): - """Return True if light is available.""" - return self.gateway.available and self._light.reachable - - @property - def should_poll(self): - """No polling needed.""" - return False - async def async_turn_on(self, **kwargs): """Turn on light.""" data = {'on': True} @@ -186,7 +145,7 @@ class DeconzLight(Light): else: data['effect'] = 'none' - await self._light.async_set_state(data) + await self._device.async_set_state(data) async def async_turn_off(self, **kwargs): """Turn off light.""" @@ -204,31 +163,13 @@ class DeconzLight(Light): data['alert'] = 'lselect' del data['on'] - await self._light.async_set_state(data) + await self._device.async_set_state(data) @property def device_state_attributes(self): """Return the device state attributes.""" attributes = {} - attributes['is_deconz_group'] = self._light.type == 'LightGroup' - if self._light.type == 'LightGroup': - attributes['all_on'] = self._light.all_on + attributes['is_deconz_group'] = self._device.type == 'LightGroup' + if self._device.type == 'LightGroup': + attributes['all_on'] = self._device.all_on return attributes - - @property - def device_info(self): - """Return a device description for device registry.""" - if (self._light.uniqueid is None or - self._light.uniqueid.count(':') != 7): - return None - serial = self._light.uniqueid.split('-', 1)[0] - bridgeid = self.gateway.api.config.bridgeid - return { - 'connections': {(CONNECTION_ZIGBEE, serial)}, - 'identifiers': {(DECONZ_DOMAIN, serial)}, - 'manufacturer': self._light.manufacturer, - 'model': self._light.modelid, - 'name': self._light.name, - 'sw_version': self._light.swversion, - 'via_hub': (DECONZ_DOMAIN, bridgeid), - } diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index da5dcc84935..1913e3d5087 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -7,14 +7,12 @@ https://home-assistant.io/components/sensor.deconz/ from homeassistant.const import ( ATTR_BATTERY_LEVEL, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY) from homeassistant.core import callback -from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.helpers.entity import Entity from homeassistant.util import slugify from .const import ( - ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DECONZ_REACHABLE, - DOMAIN as DECONZ_DOMAIN) + ATTR_DARK, ATTR_ON, CONF_ALLOW_CLIP_SENSOR, DOMAIN as DECONZ_DOMAIN) +from .deconz_device import DeconzDevice DEPENDENCIES = ['deconz'] @@ -55,28 +53,8 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_sensor(gateway.api.sensors.values()) -class DeconzSensor(Entity): - """Representation of a sensor.""" - - def __init__(self, sensor, gateway): - """Set up sensor and add update callback to get data from websocket.""" - self._sensor = sensor - self.gateway = gateway - self.unsub_dispatcher = None - - async def async_added_to_hass(self): - """Subscribe to sensors events.""" - self._sensor.register_async_callback(self.async_update_callback) - self.gateway.deconz_ids[self.entity_id] = self._sensor.deconz_id - self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) - - async def async_will_remove_from_hass(self) -> None: - """Disconnect sensor object when removed.""" - if self.unsub_dispatcher is not None: - self.unsub_dispatcher() - self._sensor.remove_callback(self.async_update_callback) - self._sensor = None +class DeconzSensor(DeconzDevice): + """Representation of a deCONZ sensor.""" @callback def async_update_callback(self, reason): @@ -94,106 +72,52 @@ class DeconzSensor(Entity): @property def state(self): """Return the state of the sensor.""" - return self._sensor.state - - @property - def name(self): - """Return the name of the sensor.""" - return self._sensor.name - - @property - def unique_id(self): - """Return a unique identifier for this sensor.""" - return self._sensor.uniqueid + return self._device.state @property def device_class(self): """Return the class of the sensor.""" - return self._sensor.sensor_class + return self._device.sensor_class @property def icon(self): """Return the icon to use in the frontend.""" - return self._sensor.sensor_icon + return self._device.sensor_icon @property def unit_of_measurement(self): """Return the unit of measurement of this sensor.""" - return self._sensor.sensor_unit - - @property - def available(self): - """Return true if sensor is available.""" - return self.gateway.available and self._sensor.reachable - - @property - def should_poll(self): - """No polling needed.""" - return False + return self._device.sensor_unit @property def device_state_attributes(self): """Return the state attributes of the sensor.""" from pydeconz.sensor import LIGHTLEVEL attr = {} - if self._sensor.battery: - attr[ATTR_BATTERY_LEVEL] = self._sensor.battery - if self._sensor.on is not None: - attr[ATTR_ON] = self._sensor.on - if self._sensor.type in LIGHTLEVEL and self._sensor.dark is not None: - attr[ATTR_DARK] = self._sensor.dark + if self._device.battery: + attr[ATTR_BATTERY_LEVEL] = self._device.battery + if self._device.on is not None: + attr[ATTR_ON] = self._device.on + if self._device.type in LIGHTLEVEL and self._device.dark is not None: + attr[ATTR_DARK] = self._device.dark if self.unit_of_measurement == 'Watts': - attr[ATTR_CURRENT] = self._sensor.current - attr[ATTR_VOLTAGE] = self._sensor.voltage - if self._sensor.sensor_class == 'daylight': - attr[ATTR_DAYLIGHT] = self._sensor.daylight + attr[ATTR_CURRENT] = self._device.current + attr[ATTR_VOLTAGE] = self._device.voltage + if self._device.sensor_class == 'daylight': + attr[ATTR_DAYLIGHT] = self._device.daylight return attr - @property - def device_info(self): - """Return a device description for device registry.""" - if (self._sensor.uniqueid is None or - self._sensor.uniqueid.count(':') != 7): - return None - serial = self._sensor.uniqueid.split('-', 1)[0] - bridgeid = self.gateway.api.config.bridgeid - return { - 'connections': {(CONNECTION_ZIGBEE, serial)}, - 'identifiers': {(DECONZ_DOMAIN, serial)}, - 'manufacturer': self._sensor.manufacturer, - 'model': self._sensor.modelid, - 'name': self._sensor.name, - 'sw_version': self._sensor.swversion, - 'via_hub': (DECONZ_DOMAIN, bridgeid), - } - -class DeconzBattery(Entity): +class DeconzBattery(DeconzDevice): """Battery class for when a device is only represented as an event.""" - def __init__(self, sensor, gateway): + def __init__(self, device, gateway): """Register dispatcher callback for update of battery state.""" - self._sensor = sensor - self.gateway = gateway - self.unsub_dispatcher = None + super().__init__(device, gateway) - self._name = '{} {}'.format(self._sensor.name, 'Battery Level') + self._name = '{} {}'.format(self._device.name, 'Battery Level') self._unit_of_measurement = "%" - async def async_added_to_hass(self): - """Subscribe to sensors events.""" - self._sensor.register_async_callback(self.async_update_callback) - self.gateway.deconz_ids[self.entity_id] = self._sensor.deconz_id - self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) - - async def async_will_remove_from_hass(self) -> None: - """Disconnect sensor object when removed.""" - if self.unsub_dispatcher is not None: - self.unsub_dispatcher() - self._sensor.remove_callback(self.async_update_callback) - self._sensor = None - @callback def async_update_callback(self, reason): """Update the battery's state, if needed.""" @@ -203,18 +127,13 @@ class DeconzBattery(Entity): @property def state(self): """Return the state of the battery.""" - return self._sensor.battery + return self._device.battery @property def name(self): """Return the name of the battery.""" return self._name - @property - def unique_id(self): - """Return a unique identifier for the device.""" - return self._sensor.uniqueid - @property def device_class(self): """Return the class of the sensor.""" @@ -225,38 +144,10 @@ class DeconzBattery(Entity): """Return the unit of measurement of this entity.""" return self._unit_of_measurement - @property - def available(self): - """Return true if sensor is available.""" - return self.gateway.available and self._sensor.reachable - - @property - def should_poll(self): - """No polling needed.""" - return False - @property def device_state_attributes(self): """Return the state attributes of the battery.""" attr = { - ATTR_EVENT_ID: slugify(self._sensor.name), + ATTR_EVENT_ID: slugify(self._device.name), } return attr - - @property - def device_info(self): - """Return a device description for device registry.""" - if (self._sensor.uniqueid is None or - self._sensor.uniqueid.count(':') != 7): - return None - serial = self._sensor.uniqueid.split('-', 1)[0] - bridgeid = self.gateway.api.config.bridgeid - return { - 'connections': {(CONNECTION_ZIGBEE, serial)}, - 'identifiers': {(DECONZ_DOMAIN, serial)}, - 'manufacturer': self._sensor.manufacturer, - 'model': self._sensor.modelid, - 'name': self._sensor.name, - 'sw_version': self._sensor.swversion, - 'via_hub': (DECONZ_DOMAIN, bridgeid), - } diff --git a/homeassistant/components/deconz/switch.py b/homeassistant/components/deconz/switch.py index 6c64fce5bd5..64d93389670 100644 --- a/homeassistant/components/deconz/switch.py +++ b/homeassistant/components/deconz/switch.py @@ -6,11 +6,11 @@ https://home-assistant.io/components/switch.deconz/ """ from homeassistant.components.switch import SwitchDevice from homeassistant.core import callback -from homeassistant.helpers.device_registry import CONNECTION_ZIGBEE from homeassistant.helpers.dispatcher import async_dispatcher_connect -from .const import ( - DECONZ_REACHABLE, DOMAIN as DECONZ_DOMAIN, POWER_PLUGS, SIRENS) +from .const import DOMAIN as DECONZ_DOMAIN, POWER_PLUGS, SIRENS +from .deconz_device import DeconzDevice + DEPENDENCIES = ['deconz'] @@ -45,106 +45,39 @@ async def async_setup_entry(hass, config_entry, async_add_entities): async_add_switch(gateway.api.lights.values()) -class DeconzSwitch(SwitchDevice): - """Representation of a deCONZ switch.""" - - def __init__(self, switch, gateway): - """Set up switch and add update callback to get data from websocket.""" - self._switch = switch - self.gateway = gateway - self.unsub_dispatcher = None - - async def async_added_to_hass(self): - """Subscribe to switches events.""" - self._switch.register_async_callback(self.async_update_callback) - self.gateway.deconz_ids[self.entity_id] = self._switch.deconz_id - self.unsub_dispatcher = async_dispatcher_connect( - self.hass, DECONZ_REACHABLE, self.async_update_callback) - - async def async_will_remove_from_hass(self) -> None: - """Disconnect switch object when removed.""" - if self.unsub_dispatcher is not None: - self.unsub_dispatcher() - self._switch.remove_callback(self.async_update_callback) - self._switch = None - - @callback - def async_update_callback(self, reason): - """Update the switch's state.""" - self.async_schedule_update_ha_state() - - @property - def name(self): - """Return the name of the switch.""" - return self._switch.name - - @property - def unique_id(self): - """Return a unique identifier for this switch.""" - return self._switch.uniqueid - - @property - def available(self): - """Return True if light is available.""" - return self.gateway.available and self._switch.reachable - - @property - def should_poll(self): - """No polling needed.""" - return False - - @property - def device_info(self): - """Return a device description for device registry.""" - if (self._switch.uniqueid is None or - self._switch.uniqueid.count(':') != 7): - return None - serial = self._switch.uniqueid.split('-', 1)[0] - bridgeid = self.gateway.api.config.bridgeid - return { - 'connections': {(CONNECTION_ZIGBEE, serial)}, - 'identifiers': {(DECONZ_DOMAIN, serial)}, - 'manufacturer': self._switch.manufacturer, - 'model': self._switch.modelid, - 'name': self._switch.name, - 'sw_version': self._switch.swversion, - 'via_hub': (DECONZ_DOMAIN, bridgeid), - } - - -class DeconzPowerPlug(DeconzSwitch): - """Representation of power plugs from deCONZ.""" +class DeconzPowerPlug(DeconzDevice, SwitchDevice): + """Representation of a deCONZ power plug.""" @property def is_on(self): """Return true if switch is on.""" - return self._switch.state + return self._device.state async def async_turn_on(self, **kwargs): """Turn on switch.""" data = {'on': True} - await self._switch.async_set_state(data) + await self._device.async_set_state(data) async def async_turn_off(self, **kwargs): """Turn off switch.""" data = {'on': False} - await self._switch.async_set_state(data) + await self._device.async_set_state(data) -class DeconzSiren(DeconzSwitch): - """Representation of sirens from deCONZ.""" +class DeconzSiren(DeconzDevice, SwitchDevice): + """Representation of a deCONZ siren.""" @property def is_on(self): """Return true if switch is on.""" - return self._switch.alert == 'lselect' + return self._device.alert == 'lselect' async def async_turn_on(self, **kwargs): """Turn on switch.""" data = {'alert': 'lselect'} - await self._switch.async_set_state(data) + await self._device.async_set_state(data) async def async_turn_off(self, **kwargs): """Turn off switch.""" data = {'alert': 'none'} - await self._switch.async_set_state(data) + await self._device.async_set_state(data)