mirror of
https://github.com/home-assistant/core.git
synced 2025-07-21 04:07:08 +00:00
deCONZ - Support creating battery sensor when reported (#27538)
This commit is contained in:
parent
62b09580c4
commit
557e585e56
@ -26,13 +26,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
entity_handler = DeconzEntityHandler(gateway)
|
entity_handler = DeconzEntityHandler(gateway)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_add_sensor(sensors):
|
def async_add_sensor(sensors, new=True):
|
||||||
"""Add binary sensor from deCONZ."""
|
"""Add binary sensor from deCONZ."""
|
||||||
entities = []
|
entities = []
|
||||||
|
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
|
|
||||||
if sensor.BINARY:
|
if new and sensor.BINARY:
|
||||||
new_sensor = DeconzBinarySensor(sensor, gateway)
|
new_sensor = DeconzBinarySensor(sensor, gateway)
|
||||||
entity_handler.add_entity(new_sensor)
|
entity_handler.add_entity(new_sensor)
|
||||||
entities.append(new_sensor)
|
entities.append(new_sensor)
|
||||||
|
@ -31,13 +31,13 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
gateway = get_gateway_from_config_entry(hass, config_entry)
|
gateway = get_gateway_from_config_entry(hass, config_entry)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_add_climate(sensors):
|
def async_add_climate(sensors, new=True):
|
||||||
"""Add climate devices from deCONZ."""
|
"""Add climate devices from deCONZ."""
|
||||||
entities = []
|
entities = []
|
||||||
|
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
|
|
||||||
if sensor.type in Thermostat.ZHATYPE:
|
if new and sensor.type in Thermostat.ZHATYPE:
|
||||||
entities.append(DeconzThermostat(sensor, gateway))
|
entities.append(DeconzThermostat(sensor, gateway))
|
||||||
|
|
||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
@ -3,7 +3,10 @@ from pydeconz.sensor import Consumption, Daylight, LightLevel, Power, Switch, Th
|
|||||||
|
|
||||||
from homeassistant.const import 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.core import callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import (
|
||||||
|
async_dispatcher_connect,
|
||||||
|
async_dispatcher_send,
|
||||||
|
)
|
||||||
|
|
||||||
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
|
||||||
@ -25,21 +28,23 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
gateway = get_gateway_from_config_entry(hass, config_entry)
|
gateway = get_gateway_from_config_entry(hass, config_entry)
|
||||||
|
|
||||||
batteries = set()
|
batteries = set()
|
||||||
|
battery_handler = DeconzBatteryHandler(gateway)
|
||||||
entity_handler = DeconzEntityHandler(gateway)
|
entity_handler = DeconzEntityHandler(gateway)
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_add_sensor(sensors):
|
def async_add_sensor(sensors, new=True):
|
||||||
"""Add sensors from deCONZ.
|
"""Add sensors from deCONZ.
|
||||||
|
|
||||||
Create DeconzEvent if part of ZHAType list.
|
Create DeconzEvent if part of ZHAType list.
|
||||||
Create DeconzSensor if not a ZHAType and not a binary sensor.
|
Create DeconzSensor if not a ZHAType and not a binary sensor.
|
||||||
Create DeconzBattery if sensor has a battery attribute.
|
Create DeconzBattery if sensor has a battery attribute.
|
||||||
|
If new is false it means an existing sensor has got a battery state reported.
|
||||||
"""
|
"""
|
||||||
entities = []
|
entities = []
|
||||||
|
|
||||||
for sensor in sensors:
|
for sensor in sensors:
|
||||||
|
|
||||||
if sensor.type in Switch.ZHATYPE:
|
if new and 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"
|
||||||
@ -48,7 +53,7 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
hass.async_create_task(new_event.async_update_device_registry())
|
hass.async_create_task(new_event.async_update_device_registry())
|
||||||
gateway.events.append(new_event)
|
gateway.events.append(new_event)
|
||||||
|
|
||||||
elif not sensor.BINARY and sensor.type not in Thermostat.ZHATYPE:
|
elif new and not sensor.BINARY and sensor.type not in Thermostat.ZHATYPE:
|
||||||
|
|
||||||
new_sensor = DeconzSensor(sensor, gateway)
|
new_sensor = DeconzSensor(sensor, gateway)
|
||||||
entity_handler.add_entity(new_sensor)
|
entity_handler.add_entity(new_sensor)
|
||||||
@ -59,6 +64,9 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
|
|||||||
if new_battery.unique_id not in batteries:
|
if new_battery.unique_id not in batteries:
|
||||||
batteries.add(new_battery.unique_id)
|
batteries.add(new_battery.unique_id)
|
||||||
entities.append(new_battery)
|
entities.append(new_battery)
|
||||||
|
battery_handler.remove_tracker(sensor)
|
||||||
|
else:
|
||||||
|
battery_handler.create_tracker(sensor)
|
||||||
|
|
||||||
async_add_entities(entities, True)
|
async_add_entities(entities, True)
|
||||||
|
|
||||||
@ -176,3 +184,54 @@ class DeconzBattery(DeconzDevice):
|
|||||||
attr[ATTR_EVENT_ID] = event.event_id
|
attr[ATTR_EVENT_ID] = event.event_id
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
|
|
||||||
|
class DeconzSensorStateTracker:
|
||||||
|
"""Track sensors without a battery state and signal when battery state exist."""
|
||||||
|
|
||||||
|
def __init__(self, sensor, gateway):
|
||||||
|
"""Set up tracker."""
|
||||||
|
self.sensor = sensor
|
||||||
|
self.gateway = gateway
|
||||||
|
sensor.register_async_callback(self.async_update_callback)
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def close(self):
|
||||||
|
"""Clean up tracker."""
|
||||||
|
self.sensor.remove_callback(self.async_update_callback)
|
||||||
|
self.gateway = None
|
||||||
|
self.sensor = None
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def async_update_callback(self):
|
||||||
|
"""Sensor state updated."""
|
||||||
|
if "battery" in self.sensor.changed_keys:
|
||||||
|
async_dispatcher_send(
|
||||||
|
self.gateway.hass,
|
||||||
|
self.gateway.async_signal_new_device(NEW_SENSOR),
|
||||||
|
[self.sensor],
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class DeconzBatteryHandler:
|
||||||
|
"""Creates and stores trackers for sensors without a battery state."""
|
||||||
|
|
||||||
|
def __init__(self, gateway):
|
||||||
|
"""Set up battery handler."""
|
||||||
|
self.gateway = gateway
|
||||||
|
self._trackers = set()
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def create_tracker(self, sensor):
|
||||||
|
"""Create new tracker for battery state."""
|
||||||
|
self._trackers.add(DeconzSensorStateTracker(sensor, self.gateway))
|
||||||
|
|
||||||
|
@callback
|
||||||
|
def remove_tracker(self, sensor):
|
||||||
|
"""Remove tracker of battery state."""
|
||||||
|
for tracker in self._trackers:
|
||||||
|
if sensor == tracker.sensor:
|
||||||
|
tracker.close()
|
||||||
|
self._trackers.remove(tracker)
|
||||||
|
break
|
||||||
|
@ -233,3 +233,26 @@ async def test_add_new_sensor(hass):
|
|||||||
|
|
||||||
light_level_sensor = hass.states.get("sensor.light_level_sensor")
|
light_level_sensor = hass.states.get("sensor.light_level_sensor")
|
||||||
assert light_level_sensor.state == "999.8"
|
assert light_level_sensor.state == "999.8"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_add_battery_later(hass):
|
||||||
|
"""Test that a sensor without an initial battery state creates a battery sensor once state exist."""
|
||||||
|
data = deepcopy(DECONZ_WEB_REQUEST)
|
||||||
|
data["sensors"] = {"1": deepcopy(SENSORS["3"])}
|
||||||
|
gateway = await setup_deconz_integration(
|
||||||
|
hass, ENTRY_CONFIG, options={}, get_state_response=data
|
||||||
|
)
|
||||||
|
remote = gateway.api.sensors["1"]
|
||||||
|
assert len(gateway.deconz_ids) == 0
|
||||||
|
assert len(gateway.events) == 1
|
||||||
|
assert len(remote._async_callbacks) == 2
|
||||||
|
|
||||||
|
remote.async_update({"config": {"battery": 50}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert len(gateway.deconz_ids) == 1
|
||||||
|
assert len(gateway.events) == 1
|
||||||
|
assert len(remote._async_callbacks) == 2
|
||||||
|
|
||||||
|
battery_sensor = hass.states.get("sensor.switch_1_battery_level")
|
||||||
|
assert battery_sensor is not None
|
||||||
|
Loading…
x
Reference in New Issue
Block a user