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
pull/26648/head
Robert Svensson 2019-09-14 19:15:18 +02:00 committed by GitHub
parent 24f1ff0aef
commit 41c9ed5d51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 48 deletions

View File

@ -2,7 +2,7 @@
from pydeconz.sensor import Presence, Vibration from pydeconz.sensor import Presence, Vibration
from homeassistant.components.binary_sensor import BinarySensorDevice 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.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -17,7 +17,6 @@ ATTR_VIBRATIONSTRENGTH = "vibrationstrength"
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ platforms.""" """Old way of setting up deCONZ platforms."""
pass
async def async_setup_entry(hass, config_entry, async_add_entities): 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): def async_update_callback(self, force_update=False):
"""Update the sensor's state.""" """Update the sensor's state."""
changed = set(self._device.changed_keys) 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): if force_update or any(key in changed for key in keys):
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
@ -79,8 +78,6 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorDevice):
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes of the sensor.""" """Return the state attributes of the sensor."""
attr = {} attr = {}
if self._device.battery:
attr[ATTR_BATTERY_LEVEL] = self._device.battery
if self._device.on is not None: if self._device.on is not None:
attr[ATTR_ON] = self._device.on attr[ATTR_ON] = self._device.on

View File

@ -8,7 +8,7 @@ from homeassistant.components.climate.const import (
HVAC_MODE_OFF, HVAC_MODE_OFF,
SUPPORT_TARGET_TEMPERATURE, 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.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
@ -21,7 +21,6 @@ SUPPORT_HVAC = [HVAC_MODE_AUTO, HVAC_MODE_HEAT, HVAC_MODE_OFF]
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ platforms.""" """Old way of setting up deCONZ platforms."""
pass
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
@ -120,9 +119,6 @@ class DeconzThermostat(DeconzDevice, ClimateDevice):
"""Return the state attributes of the thermostat.""" """Return the state attributes of the thermostat."""
attr = {} attr = {}
if self._device.battery:
attr[ATTR_BATTERY_LEVEL] = self._device.battery
if self._device.offset: if self._device.offset:
attr[ATTR_OFFSET] = self._device.offset attr[ATTR_OFFSET] = self._device.offset

View File

@ -24,10 +24,10 @@ class DeconzBase:
@property @property
def serial(self): def serial(self):
"""Return a serial number for this device.""" """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 None
return self.unique_id.split("-", 1)[0] return self._device.uniqueid.split("-", 1)[0]
@property @property
def device_info(self): def device_info(self):

View File

@ -27,6 +27,11 @@ class DeconzEvent(DeconzBase):
self.event_id = slugify(self._device.name) self.event_id = slugify(self._device.name)
_LOGGER.debug("deCONZ event created: %s", self.event_id) _LOGGER.debug("deCONZ event created: %s", self.event_id)
@property
def device(self):
"""Return Event device."""
return self._device
@callback @callback
def async_will_remove_from_hass(self) -> None: def async_will_remove_from_hass(self) -> None:
"""Disconnect event object when removed.""" """Disconnect event object when removed."""

View File

@ -1,15 +1,9 @@
"""Support for deCONZ sensors.""" """Support for deCONZ sensors."""
from pydeconz.sensor import Consumption, Daylight, LightLevel, Power, Switch from pydeconz.sensor import Consumption, Daylight, LightLevel, Power, Switch
from homeassistant.const import ( from homeassistant.const import ATTR_TEMPERATURE, ATTR_VOLTAGE, DEVICE_CLASS_BATTERY
ATTR_BATTERY_LEVEL,
ATTR_TEMPERATURE,
ATTR_VOLTAGE,
DEVICE_CLASS_BATTERY,
)
from homeassistant.core import callback from homeassistant.core import callback
from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.util import slugify
from .const import ATTR_DARK, ATTR_ON, NEW_SENSOR from .const import ATTR_DARK, ATTR_ON, NEW_SENSOR
from .deconz_device import DeconzDevice from .deconz_device import DeconzDevice
@ -24,41 +18,48 @@ ATTR_EVENT_ID = "event_id"
async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): async def async_setup_platform(hass, config, async_add_entities, discovery_info=None):
"""Old way of setting up deCONZ platforms.""" """Old way of setting up deCONZ platforms."""
pass
async def async_setup_entry(hass, config_entry, async_add_entities): async def async_setup_entry(hass, config_entry, async_add_entities):
"""Set up the deCONZ sensors.""" """Set up the deCONZ sensors."""
gateway = get_gateway_from_config_entry(hass, config_entry) gateway = get_gateway_from_config_entry(hass, config_entry)
batteries = set()
entity_handler = DeconzEntityHandler(gateway) entity_handler = DeconzEntityHandler(gateway)
@callback @callback
def async_add_sensor(sensors): 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 = [] entities = []
for sensor in sensors: 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( if gateway.option_allow_clip_sensor or not sensor.type.startswith(
"CLIP" "CLIP"
): ):
event = DeconzEvent(sensor, gateway) new_event = DeconzEvent(sensor, gateway)
hass.async_create_task(event.async_update_device_registry()) hass.async_create_task(new_event.async_update_device_registry())
gateway.events.append(event) gateway.events.append(new_event)
if sensor.battery: elif not sensor.BINARY:
entities.append(DeconzBattery(sensor, gateway))
else:
new_sensor = DeconzSensor(sensor, gateway) new_sensor = DeconzSensor(sensor, gateway)
entity_handler.add_entity(new_sensor) entity_handler.add_entity(new_sensor)
entities.append(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) async_add_entities(entities, True)
gateway.listeners.append( gateway.listeners.append(
@ -77,7 +78,7 @@ class DeconzSensor(DeconzDevice):
def async_update_callback(self, force_update=False): def async_update_callback(self, force_update=False):
"""Update the sensor's state.""" """Update the sensor's state."""
changed = set(self._device.changed_keys) 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): if force_update or any(key in changed for key in keys):
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
@ -105,8 +106,6 @@ class DeconzSensor(DeconzDevice):
def device_state_attributes(self): def device_state_attributes(self):
"""Return the state attributes of the sensor.""" """Return the state attributes of the sensor."""
attr = {} attr = {}
if self._device.battery:
attr[ATTR_BATTERY_LEVEL] = self._device.battery
if self._device.on is not None: if self._device.on is not None:
attr[ATTR_ON] = self._device.on attr[ATTR_ON] = self._device.on
@ -133,13 +132,6 @@ class DeconzSensor(DeconzDevice):
class DeconzBattery(DeconzDevice): class DeconzBattery(DeconzDevice):
"""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, 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 @callback
def async_update_callback(self, force_update=False): def async_update_callback(self, force_update=False):
"""Update the battery's state, if needed.""" """Update the battery's state, if needed."""
@ -148,6 +140,11 @@ class DeconzBattery(DeconzDevice):
if force_update or any(key in changed for key in keys): if force_update or any(key in changed for key in keys):
self.async_schedule_update_ha_state() self.async_schedule_update_ha_state()
@property
def unique_id(self):
"""Return a unique identifier for this device."""
return f"{self.serial}-battery"
@property @property
def state(self): def state(self):
"""Return the state of the battery.""" """Return the state of the battery."""
@ -156,7 +153,7 @@ class DeconzBattery(DeconzDevice):
@property @property
def name(self): def name(self):
"""Return the name of the battery.""" """Return the name of the battery."""
return self._name return f"{self._device.name} Battery Level"
@property @property
def device_class(self): def device_class(self):
@ -166,10 +163,16 @@ class DeconzBattery(DeconzDevice):
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
"""Return the unit of measurement of this entity.""" """Return the unit of measurement of this entity."""
return self._unit_of_measurement return "%"
@property @property
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_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 return attr