From 41c9ed5d5133fe19515959b890f8c748bff0bfb8 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sat, 14 Sep 2019 19:15:18 +0200 Subject: [PATCH] deCONZ - battery sensor instead of battery attribute (#26591) * Allow all sensors to create battery sensors * Neither binary sensor, climate nor sensor will have battery attributes --- .../components/deconz/binary_sensor.py | 7 +- homeassistant/components/deconz/climate.py | 6 +- .../components/deconz/deconz_device.py | 4 +- .../components/deconz/deconz_event.py | 5 ++ homeassistant/components/deconz/sensor.py | 75 ++++++++++--------- 5 files changed, 49 insertions(+), 48 deletions(-) diff --git a/homeassistant/components/deconz/binary_sensor.py b/homeassistant/components/deconz/binary_sensor.py index 492b16a603a5bb..b81ecdc5164a75 100644 --- a/homeassistant/components/deconz/binary_sensor.py +++ b/homeassistant/components/deconz/binary_sensor.py @@ -2,7 +2,7 @@ from pydeconz.sensor import Presence, Vibration from homeassistant.components.binary_sensor import BinarySensorDevice -from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_TEMPERATURE +from homeassistant.const import ATTR_TEMPERATURE from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -17,7 +17,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ platforms.""" - pass async def async_setup_entry(hass, config_entry, async_add_entities): @@ -56,7 +55,7 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorDevice): def async_update_callback(self, force_update=False): """Update the sensor's state.""" changed = set(self._device.changed_keys) - keys = {"battery", "on", "reachable", "state"} + keys = {"on", "reachable", "state"} if force_update or any(key in changed for key in keys): self.async_schedule_update_ha_state() @@ -79,8 +78,6 @@ def icon(self): def device_state_attributes(self): """Return the state attributes of the sensor.""" attr = {} - if self._device.battery: - attr[ATTR_BATTERY_LEVEL] = self._device.battery if self._device.on is not None: attr[ATTR_ON] = self._device.on diff --git a/homeassistant/components/deconz/climate.py b/homeassistant/components/deconz/climate.py index 1844cb2c97c73f..b7a1ebce22ad48 100644 --- a/homeassistant/components/deconz/climate.py +++ b/homeassistant/components/deconz/climate.py @@ -8,7 +8,7 @@ HVAC_MODE_OFF, SUPPORT_TARGET_TEMPERATURE, ) -from homeassistant.const import ATTR_BATTERY_LEVEL, ATTR_TEMPERATURE, TEMP_CELSIUS +from homeassistant.const import ATTR_TEMPERATURE, TEMP_CELSIUS from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -21,7 +21,6 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ platforms.""" - pass async def async_setup_entry(hass, config_entry, async_add_entities): @@ -120,9 +119,6 @@ def device_state_attributes(self): """Return the state attributes of the thermostat.""" attr = {} - if self._device.battery: - attr[ATTR_BATTERY_LEVEL] = self._device.battery - if self._device.offset: attr[ATTR_OFFSET] = self._device.offset diff --git a/homeassistant/components/deconz/deconz_device.py b/homeassistant/components/deconz/deconz_device.py index e6249b2304cfee..68daee6cf260ca 100644 --- a/homeassistant/components/deconz/deconz_device.py +++ b/homeassistant/components/deconz/deconz_device.py @@ -24,10 +24,10 @@ def unique_id(self): @property def serial(self): """Return a serial number for this device.""" - if self.unique_id is None or self.unique_id.count(":") != 7: + if self._device.uniqueid is None or self._device.uniqueid.count(":") != 7: return None - return self.unique_id.split("-", 1)[0] + return self._device.uniqueid.split("-", 1)[0] @property def device_info(self): diff --git a/homeassistant/components/deconz/deconz_event.py b/homeassistant/components/deconz/deconz_event.py index f6c2d471bbf0a1..31588db1f23833 100644 --- a/homeassistant/components/deconz/deconz_event.py +++ b/homeassistant/components/deconz/deconz_event.py @@ -27,6 +27,11 @@ def __init__(self, device, gateway): self.event_id = slugify(self._device.name) _LOGGER.debug("deCONZ event created: %s", self.event_id) + @property + def device(self): + """Return Event device.""" + return self._device + @callback def async_will_remove_from_hass(self) -> None: """Disconnect event object when removed.""" diff --git a/homeassistant/components/deconz/sensor.py b/homeassistant/components/deconz/sensor.py index a6138087f1ce40..001721d4f00035 100644 --- a/homeassistant/components/deconz/sensor.py +++ b/homeassistant/components/deconz/sensor.py @@ -1,15 +1,9 @@ """Support for deCONZ sensors.""" from pydeconz.sensor import Consumption, Daylight, LightLevel, Power, Switch -from homeassistant.const import ( - ATTR_BATTERY_LEVEL, - ATTR_TEMPERATURE, - ATTR_VOLTAGE, - DEVICE_CLASS_BATTERY, -) +from homeassistant.const import ATTR_TEMPERATURE, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY from homeassistant.core import callback from homeassistant.helpers.dispatcher import async_dispatcher_connect -from homeassistant.util import slugify from .const import ATTR_DARK, ATTR_ON, NEW_SENSOR from .deconz_device import DeconzDevice @@ -24,40 +18,47 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Old way of setting up deCONZ platforms.""" - pass async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the deCONZ sensors.""" gateway = get_gateway_from_config_entry(hass, config_entry) + batteries = set() entity_handler = DeconzEntityHandler(gateway) @callback def async_add_sensor(sensors): - """Add sensors from deCONZ.""" + """Add sensors from deCONZ. + + Create DeconzEvent if part of ZHAType list. + Create DeconzSensor if not a ZHAType and not a binary sensor. + Create DeconzBattery if sensor has a battery attribute. + """ entities = [] for sensor in sensors: - if not sensor.BINARY: + if sensor.type in Switch.ZHATYPE: - if sensor.type in Switch.ZHATYPE: + if gateway.option_allow_clip_sensor or not sensor.type.startswith( + "CLIP" + ): + new_event = DeconzEvent(sensor, gateway) + hass.async_create_task(new_event.async_update_device_registry()) + gateway.events.append(new_event) - if gateway.option_allow_clip_sensor or not sensor.type.startswith( - "CLIP" - ): - event = DeconzEvent(sensor, gateway) - hass.async_create_task(event.async_update_device_registry()) - gateway.events.append(event) + elif not sensor.BINARY: - if sensor.battery: - entities.append(DeconzBattery(sensor, gateway)) + new_sensor = DeconzSensor(sensor, gateway) + entity_handler.add_entity(new_sensor) + entities.append(new_sensor) - else: - new_sensor = DeconzSensor(sensor, gateway) - entity_handler.add_entity(new_sensor) - entities.append(new_sensor) + if sensor.battery: + new_battery = DeconzBattery(sensor, gateway) + if new_battery.unique_id not in batteries: + batteries.add(new_battery.unique_id) + entities.append(new_battery) async_add_entities(entities, True) @@ -77,7 +78,7 @@ class DeconzSensor(DeconzDevice): def async_update_callback(self, force_update=False): """Update the sensor's state.""" changed = set(self._device.changed_keys) - keys = {"battery", "on", "reachable", "state"} + keys = {"on", "reachable", "state"} if force_update or any(key in changed for key in keys): self.async_schedule_update_ha_state() @@ -105,8 +106,6 @@ def unit_of_measurement(self): def device_state_attributes(self): """Return the state attributes of the sensor.""" attr = {} - if self._device.battery: - attr[ATTR_BATTERY_LEVEL] = self._device.battery if self._device.on is not None: attr[ATTR_ON] = self._device.on @@ -133,13 +132,6 @@ def device_state_attributes(self): class DeconzBattery(DeconzDevice): """Battery class for when a device is only represented as an event.""" - def __init__(self, device, gateway): - """Register dispatcher callback for update of battery state.""" - super().__init__(device, gateway) - - self._name = "{} {}".format(self._device.name, "Battery Level") - self._unit_of_measurement = "%" - @callback def async_update_callback(self, force_update=False): """Update the battery's state, if needed.""" @@ -148,6 +140,11 @@ def async_update_callback(self, force_update=False): if force_update or any(key in changed for key in keys): self.async_schedule_update_ha_state() + @property + def unique_id(self): + """Return a unique identifier for this device.""" + return f"{self.serial}-battery" + @property def state(self): """Return the state of the battery.""" @@ -156,7 +153,7 @@ def state(self): @property def name(self): """Return the name of the battery.""" - return self._name + return f"{self._device.name} Battery Level" @property def device_class(self): @@ -166,10 +163,16 @@ def device_class(self): @property def unit_of_measurement(self): """Return the unit of measurement of this entity.""" - return self._unit_of_measurement + return "%" @property def device_state_attributes(self): """Return the state attributes of the battery.""" - attr = {ATTR_EVENT_ID: slugify(self._device.name)} + attr = {} + + if self._device.type in Switch.ZHATYPE: + for event in self.gateway.events: + if self._device == event.device: + attr[ATTR_EVENT_ID] = event.event_id + return attr