Add tampering sensor to deCONZ integration (#49776)

This commit is contained in:
Robert Svensson 2021-04-28 20:16:06 +02:00 committed by GitHub
parent 883513e089
commit 056f636568
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 91 additions and 4 deletions

View File

@ -6,6 +6,7 @@ from homeassistant.components.binary_sensor import (
DEVICE_CLASS_MOISTURE,
DEVICE_CLASS_MOTION,
DEVICE_CLASS_OPENING,
DEVICE_CLASS_PROBLEM,
DEVICE_CLASS_SMOKE,
DEVICE_CLASS_VIBRATION,
DOMAIN,
@ -55,6 +56,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities):
):
entities.append(DeconzBinarySensor(sensor, gateway))
if sensor.tampered is not None:
known_tampering_sensors = set(gateway.entities[DOMAIN])
new_tampering_sensor = DeconzTampering(sensor, gateway)
if new_tampering_sensor.unique_id not in known_tampering_sensors:
entities.append(new_tampering_sensor)
if entities:
async_add_entities(entities)
@ -113,3 +120,36 @@ class DeconzBinarySensor(DeconzDevice, BinarySensorEntity):
attr[ATTR_VIBRATIONSTRENGTH] = self._device.vibrationstrength
return attr
class DeconzTampering(DeconzDevice, BinarySensorEntity):
"""Representation of a deCONZ tampering sensor."""
TYPE = DOMAIN
@property
def unique_id(self) -> str:
"""Return a unique identifier for this device."""
return f"{self.serial}-tampered"
@callback
def async_update_callback(self, force_update: bool = False) -> None:
"""Update the sensor's state."""
keys = {"tampered", "reachable"}
if force_update or self._device.changed_keys.intersection(keys):
super().async_update_callback(force_update=force_update)
@property
def is_on(self) -> bool:
"""Return the state of the sensor."""
return self._device.tampered
@property
def name(self) -> str:
"""Return the name of the sensor."""
return f"{self._device.name} Tampered"
@property
def device_class(self) -> str:
"""Return the class of the sensor."""
return DEVICE_CLASS_PROBLEM

View File

@ -82,7 +82,7 @@ async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
with patch.dict(DECONZ_WEB_REQUEST, data):
config_entry = await setup_deconz_integration(hass, aioclient_mock)
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_all()) == 2
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_DISARMED
# Event signals alarm control panel armed away
@ -261,7 +261,7 @@ async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
await hass.config_entries.async_unload(config_entry.entry_id)
states = hass.states.async_all()
assert len(states) == 1
assert len(states) == 2
for state in states:
assert state.state == STATE_UNAVAILABLE

View File

@ -4,6 +4,7 @@ from unittest.mock import patch
from homeassistant.components.binary_sensor import (
DEVICE_CLASS_MOTION,
DEVICE_CLASS_PROBLEM,
DEVICE_CLASS_VIBRATION,
)
from homeassistant.components.deconz.const import (
@ -116,6 +117,52 @@ async def test_binary_sensors(hass, aioclient_mock, mock_deconz_websocket):
assert len(hass.states.async_all()) == 0
async def test_tampering_sensor(hass, aioclient_mock, mock_deconz_websocket):
"""Verify tampering sensor works."""
data = {
"sensors": {
"1": {
"name": "Presence sensor",
"type": "ZHAPresence",
"state": {"dark": False, "presence": False, "tampered": False},
"config": {"on": True, "reachable": True, "temperature": 10},
"uniqueid": "00:00:00:00:00:00:00:00-00",
},
}
}
with patch.dict(DECONZ_WEB_REQUEST, data):
config_entry = await setup_deconz_integration(hass, aioclient_mock)
assert len(hass.states.async_all()) == 3
presence_tamper = hass.states.get("binary_sensor.presence_sensor_tampered")
assert presence_tamper.state == STATE_OFF
assert presence_tamper.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_PROBLEM
event_changed_sensor = {
"t": "event",
"e": "changed",
"r": "sensors",
"id": "1",
"state": {"tampered": True},
}
await mock_deconz_websocket(data=event_changed_sensor)
await hass.async_block_till_done()
assert hass.states.get("binary_sensor.presence_sensor_tampered").state == STATE_ON
await hass.config_entries.async_unload(config_entry.entry_id)
assert (
hass.states.get("binary_sensor.presence_sensor_tampered").state
== STATE_UNAVAILABLE
)
await hass.config_entries.async_remove(config_entry.entry_id)
await hass.async_block_till_done()
assert len(hass.states.async_all()) == 0
async def test_allow_clip_sensor(hass, aioclient_mock):
"""Test that CLIP sensors can be allowed."""
data = {

View File

@ -232,7 +232,7 @@ async def test_deconz_alarm_events(hass, aioclient_mock, mock_deconz_websocket):
device_registry = await hass.helpers.device_registry.async_get_registry()
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_all()) == 2
# 1 alarm control device + 2 additional devices for deconz service and host
assert (
len(async_entries_for_config_entry(device_registry, config_entry.entry_id)) == 3
@ -294,7 +294,7 @@ async def test_deconz_alarm_events(hass, aioclient_mock, mock_deconz_websocket):
await hass.config_entries.async_unload(config_entry.entry_id)
states = hass.states.async_all()
assert len(hass.states.async_all()) == 1
assert len(hass.states.async_all()) == 2
for state in states:
assert state.state == STATE_UNAVAILABLE