mirror of
https://github.com/home-assistant/core.git
synced 2025-07-16 09:47:13 +00:00
Update alarm control panel and deconz alarm event to reflect the finalized implementation in deCONZ (#54936)
* Update alarm control panel and deconz alarm event to reflect the new implementation in deCONZ * Bump dependency to v83
This commit is contained in:
parent
4d452dbccf
commit
6ad0e0220a
@ -5,13 +5,19 @@ from pydeconz.sensor import (
|
|||||||
ANCILLARY_CONTROL_ARMED_AWAY,
|
ANCILLARY_CONTROL_ARMED_AWAY,
|
||||||
ANCILLARY_CONTROL_ARMED_NIGHT,
|
ANCILLARY_CONTROL_ARMED_NIGHT,
|
||||||
ANCILLARY_CONTROL_ARMED_STAY,
|
ANCILLARY_CONTROL_ARMED_STAY,
|
||||||
|
ANCILLARY_CONTROL_ARMING_AWAY,
|
||||||
|
ANCILLARY_CONTROL_ARMING_NIGHT,
|
||||||
|
ANCILLARY_CONTROL_ARMING_STAY,
|
||||||
ANCILLARY_CONTROL_DISARMED,
|
ANCILLARY_CONTROL_DISARMED,
|
||||||
|
ANCILLARY_CONTROL_ENTRY_DELAY,
|
||||||
|
ANCILLARY_CONTROL_EXIT_DELAY,
|
||||||
|
ANCILLARY_CONTROL_IN_ALARM,
|
||||||
AncillaryControl,
|
AncillaryControl,
|
||||||
)
|
)
|
||||||
import voluptuous as vol
|
|
||||||
|
|
||||||
from homeassistant.components.alarm_control_panel import (
|
from homeassistant.components.alarm_control_panel import (
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
FORMAT_NUMBER,
|
||||||
SUPPORT_ALARM_ARM_AWAY,
|
SUPPORT_ALARM_ARM_AWAY,
|
||||||
SUPPORT_ALARM_ARM_HOME,
|
SUPPORT_ALARM_ARM_HOME,
|
||||||
SUPPORT_ALARM_ARM_NIGHT,
|
SUPPORT_ALARM_ARM_NIGHT,
|
||||||
@ -21,40 +27,39 @@ from homeassistant.const import (
|
|||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
STATE_ALARM_ARMED_HOME,
|
STATE_ALARM_ARMED_HOME,
|
||||||
STATE_ALARM_ARMED_NIGHT,
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_ARMING,
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_PENDING,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
)
|
)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import entity_platform
|
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
|
|
||||||
from .const import NEW_SENSOR
|
from .const import NEW_SENSOR
|
||||||
from .deconz_device import DeconzDevice
|
from .deconz_device import DeconzDevice
|
||||||
from .gateway import get_gateway_from_config_entry
|
from .gateway import get_gateway_from_config_entry
|
||||||
|
|
||||||
PANEL_ENTRY_DELAY = "entry_delay"
|
|
||||||
PANEL_EXIT_DELAY = "exit_delay"
|
|
||||||
PANEL_NOT_READY_TO_ARM = "not_ready_to_arm"
|
|
||||||
|
|
||||||
SERVICE_ALARM_PANEL_STATE = "alarm_panel_state"
|
|
||||||
CONF_ALARM_PANEL_STATE = "panel_state"
|
|
||||||
SERVICE_ALARM_PANEL_STATE_SCHEMA = {
|
|
||||||
vol.Required(CONF_ALARM_PANEL_STATE): vol.In(
|
|
||||||
[
|
|
||||||
PANEL_ENTRY_DELAY,
|
|
||||||
PANEL_EXIT_DELAY,
|
|
||||||
PANEL_NOT_READY_TO_ARM,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
DECONZ_TO_ALARM_STATE = {
|
DECONZ_TO_ALARM_STATE = {
|
||||||
ANCILLARY_CONTROL_ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
|
ANCILLARY_CONTROL_ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
|
||||||
ANCILLARY_CONTROL_ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
|
ANCILLARY_CONTROL_ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
|
||||||
ANCILLARY_CONTROL_ARMED_STAY: STATE_ALARM_ARMED_HOME,
|
ANCILLARY_CONTROL_ARMED_STAY: STATE_ALARM_ARMED_HOME,
|
||||||
|
ANCILLARY_CONTROL_ARMING_AWAY: STATE_ALARM_ARMING,
|
||||||
|
ANCILLARY_CONTROL_ARMING_NIGHT: STATE_ALARM_ARMING,
|
||||||
|
ANCILLARY_CONTROL_ARMING_STAY: STATE_ALARM_ARMING,
|
||||||
ANCILLARY_CONTROL_DISARMED: STATE_ALARM_DISARMED,
|
ANCILLARY_CONTROL_DISARMED: STATE_ALARM_DISARMED,
|
||||||
|
ANCILLARY_CONTROL_ENTRY_DELAY: STATE_ALARM_PENDING,
|
||||||
|
ANCILLARY_CONTROL_EXIT_DELAY: STATE_ALARM_PENDING,
|
||||||
|
ANCILLARY_CONTROL_IN_ALARM: STATE_ALARM_TRIGGERED,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def get_alarm_system_for_unique_id(gateway, unique_id: str):
|
||||||
|
"""Retrieve alarm system unique ID is registered to."""
|
||||||
|
for alarm_system in gateway.api.alarm_systems.values():
|
||||||
|
if unique_id in alarm_system.devices:
|
||||||
|
return alarm_system
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(hass, config_entry, async_add_entities) -> None:
|
async def async_setup_entry(hass, config_entry, async_add_entities) -> None:
|
||||||
"""Set up the deCONZ alarm control panel devices.
|
"""Set up the deCONZ alarm control panel devices.
|
||||||
|
|
||||||
@ -63,8 +68,6 @@ async def async_setup_entry(hass, config_entry, async_add_entities) -> None:
|
|||||||
gateway = get_gateway_from_config_entry(hass, config_entry)
|
gateway = get_gateway_from_config_entry(hass, config_entry)
|
||||||
gateway.entities[DOMAIN] = set()
|
gateway.entities[DOMAIN] = set()
|
||||||
|
|
||||||
platform = entity_platform.async_get_current_platform()
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_add_alarm_control_panel(sensors=gateway.api.sensors.values()) -> None:
|
def async_add_alarm_control_panel(sensors=gateway.api.sensors.values()) -> None:
|
||||||
"""Add alarm control panel devices from deCONZ."""
|
"""Add alarm control panel devices from deCONZ."""
|
||||||
@ -75,15 +78,12 @@ async def async_setup_entry(hass, config_entry, async_add_entities) -> None:
|
|||||||
if (
|
if (
|
||||||
sensor.type in AncillaryControl.ZHATYPE
|
sensor.type in AncillaryControl.ZHATYPE
|
||||||
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
and sensor.uniqueid not in gateway.entities[DOMAIN]
|
||||||
|
and get_alarm_system_for_unique_id(gateway, sensor.uniqueid)
|
||||||
):
|
):
|
||||||
|
|
||||||
entities.append(DeconzAlarmControlPanel(sensor, gateway))
|
entities.append(DeconzAlarmControlPanel(sensor, gateway))
|
||||||
|
|
||||||
if entities:
|
if entities:
|
||||||
platform.async_register_entity_service(
|
|
||||||
SERVICE_ALARM_PANEL_STATE,
|
|
||||||
SERVICE_ALARM_PANEL_STATE_SCHEMA,
|
|
||||||
"async_set_panel_state",
|
|
||||||
)
|
|
||||||
async_add_entities(entities)
|
async_add_entities(entities)
|
||||||
|
|
||||||
config_entry.async_on_unload(
|
config_entry.async_on_unload(
|
||||||
@ -102,7 +102,7 @@ class DeconzAlarmControlPanel(DeconzDevice, AlarmControlPanelEntity):
|
|||||||
|
|
||||||
TYPE = DOMAIN
|
TYPE = DOMAIN
|
||||||
|
|
||||||
_attr_code_arm_required = False
|
_attr_code_format = FORMAT_NUMBER
|
||||||
_attr_supported_features = (
|
_attr_supported_features = (
|
||||||
SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_NIGHT
|
SUPPORT_ALARM_ARM_AWAY | SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_NIGHT
|
||||||
)
|
)
|
||||||
@ -110,16 +110,12 @@ class DeconzAlarmControlPanel(DeconzDevice, AlarmControlPanelEntity):
|
|||||||
def __init__(self, device, gateway) -> None:
|
def __init__(self, device, gateway) -> None:
|
||||||
"""Set up alarm control panel device."""
|
"""Set up alarm control panel device."""
|
||||||
super().__init__(device, gateway)
|
super().__init__(device, gateway)
|
||||||
self._service_to_device_panel_command = {
|
self.alarm_system = get_alarm_system_for_unique_id(gateway, device.uniqueid)
|
||||||
PANEL_ENTRY_DELAY: self._device.entry_delay,
|
|
||||||
PANEL_EXIT_DELAY: self._device.exit_delay,
|
|
||||||
PANEL_NOT_READY_TO_ARM: self._device.not_ready_to_arm,
|
|
||||||
}
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_callback(self, force_update: bool = False) -> None:
|
def async_update_callback(self, force_update: bool = False) -> None:
|
||||||
"""Update the control panels state."""
|
"""Update the control panels state."""
|
||||||
keys = {"armed", "reachable"}
|
keys = {"panel", "reachable"}
|
||||||
if force_update or (
|
if force_update or (
|
||||||
self._device.changed_keys.intersection(keys)
|
self._device.changed_keys.intersection(keys)
|
||||||
and self._device.state in DECONZ_TO_ALARM_STATE
|
and self._device.state in DECONZ_TO_ALARM_STATE
|
||||||
@ -133,20 +129,16 @@ class DeconzAlarmControlPanel(DeconzDevice, AlarmControlPanelEntity):
|
|||||||
|
|
||||||
async def async_alarm_arm_away(self, code: None = None) -> None:
|
async def async_alarm_arm_away(self, code: None = None) -> None:
|
||||||
"""Send arm away command."""
|
"""Send arm away command."""
|
||||||
await self._device.arm_away()
|
await self.alarm_system.arm_away(code)
|
||||||
|
|
||||||
async def async_alarm_arm_home(self, code: None = None) -> None:
|
async def async_alarm_arm_home(self, code: None = None) -> None:
|
||||||
"""Send arm home command."""
|
"""Send arm home command."""
|
||||||
await self._device.arm_stay()
|
await self.alarm_system.arm_stay(code)
|
||||||
|
|
||||||
async def async_alarm_arm_night(self, code: None = None) -> None:
|
async def async_alarm_arm_night(self, code: None = None) -> None:
|
||||||
"""Send arm night command."""
|
"""Send arm night command."""
|
||||||
await self._device.arm_night()
|
await self.alarm_system.arm_night(code)
|
||||||
|
|
||||||
async def async_alarm_disarm(self, code: None = None) -> None:
|
async def async_alarm_disarm(self, code: None = None) -> None:
|
||||||
"""Send disarm command."""
|
"""Send disarm command."""
|
||||||
await self._device.disarm()
|
await self.alarm_system.disarm(code)
|
||||||
|
|
||||||
async def async_set_panel_state(self, panel_state: str) -> None:
|
|
||||||
"""Send panel_state command."""
|
|
||||||
await self._service_to_device_panel_command[panel_state]()
|
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
"""Representation of a deCONZ remote or keypad."""
|
"""Representation of a deCONZ remote or keypad."""
|
||||||
|
|
||||||
from pydeconz.sensor import (
|
from pydeconz.sensor import (
|
||||||
ANCILLARY_CONTROL_ARMED_AWAY,
|
ANCILLARY_CONTROL_EMERGENCY,
|
||||||
ANCILLARY_CONTROL_ARMED_NIGHT,
|
ANCILLARY_CONTROL_FIRE,
|
||||||
ANCILLARY_CONTROL_ARMED_STAY,
|
ANCILLARY_CONTROL_INVALID_CODE,
|
||||||
ANCILLARY_CONTROL_DISARMED,
|
ANCILLARY_CONTROL_PANIC,
|
||||||
AncillaryControl,
|
AncillaryControl,
|
||||||
Switch,
|
Switch,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_CODE,
|
|
||||||
CONF_DEVICE_ID,
|
CONF_DEVICE_ID,
|
||||||
CONF_EVENT,
|
CONF_EVENT,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
CONF_UNIQUE_ID,
|
CONF_UNIQUE_ID,
|
||||||
CONF_XY,
|
CONF_XY,
|
||||||
STATE_ALARM_ARMED_AWAY,
|
|
||||||
STATE_ALARM_ARMED_HOME,
|
|
||||||
STATE_ALARM_ARMED_NIGHT,
|
|
||||||
STATE_ALARM_DISARMED,
|
|
||||||
)
|
)
|
||||||
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
|
||||||
@ -31,11 +26,11 @@ from .deconz_device import DeconzBase
|
|||||||
CONF_DECONZ_EVENT = "deconz_event"
|
CONF_DECONZ_EVENT = "deconz_event"
|
||||||
CONF_DECONZ_ALARM_EVENT = "deconz_alarm_event"
|
CONF_DECONZ_ALARM_EVENT = "deconz_alarm_event"
|
||||||
|
|
||||||
DECONZ_TO_ALARM_STATE = {
|
SUPPORTED_DECONZ_ALARM_EVENTS = {
|
||||||
ANCILLARY_CONTROL_ARMED_AWAY: STATE_ALARM_ARMED_AWAY,
|
ANCILLARY_CONTROL_EMERGENCY,
|
||||||
ANCILLARY_CONTROL_ARMED_NIGHT: STATE_ALARM_ARMED_NIGHT,
|
ANCILLARY_CONTROL_FIRE,
|
||||||
ANCILLARY_CONTROL_ARMED_STAY: STATE_ALARM_ARMED_HOME,
|
ANCILLARY_CONTROL_INVALID_CODE,
|
||||||
ANCILLARY_CONTROL_DISARMED: STATE_ALARM_DISARMED,
|
ANCILLARY_CONTROL_PANIC,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -155,31 +150,23 @@ class DeconzEvent(DeconzBase):
|
|||||||
|
|
||||||
|
|
||||||
class DeconzAlarmEvent(DeconzEvent):
|
class DeconzAlarmEvent(DeconzEvent):
|
||||||
"""Alarm control panel companion event when user inputs a code."""
|
"""Alarm control panel companion event when user interacts with a keypad."""
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def async_update_callback(self, force_update=False):
|
def async_update_callback(self, force_update=False):
|
||||||
"""Fire the event if reason is that state is updated."""
|
"""Fire the event if reason is new action is updated."""
|
||||||
if (
|
if (
|
||||||
self.gateway.ignore_state_updates
|
self.gateway.ignore_state_updates
|
||||||
or "action" not in self._device.changed_keys
|
or "action" not in self._device.changed_keys
|
||||||
|
or self._device.action not in SUPPORTED_DECONZ_ALARM_EVENTS
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
|
||||||
state, code, _area = self._device.action.split(",")
|
|
||||||
except (AttributeError, ValueError):
|
|
||||||
return
|
|
||||||
|
|
||||||
if state not in DECONZ_TO_ALARM_STATE:
|
|
||||||
return
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
CONF_ID: self.event_id,
|
CONF_ID: self.event_id,
|
||||||
CONF_UNIQUE_ID: self.serial,
|
CONF_UNIQUE_ID: self.serial,
|
||||||
CONF_DEVICE_ID: self.device_id,
|
CONF_DEVICE_ID: self.device_id,
|
||||||
CONF_EVENT: DECONZ_TO_ALARM_STATE[state],
|
CONF_EVENT: self._device.action,
|
||||||
CONF_CODE: code,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.gateway.hass.bus.async_fire(CONF_DECONZ_ALARM_EVENT, data)
|
self.gateway.hass.bus.async_fire(CONF_DECONZ_ALARM_EVENT, data)
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/deconz",
|
"documentation": "https://www.home-assistant.io/integrations/deconz",
|
||||||
"requirements": [
|
"requirements": [
|
||||||
"pydeconz==82"
|
"pydeconz==83"
|
||||||
],
|
],
|
||||||
"ssdp": [
|
"ssdp": [
|
||||||
{
|
{
|
||||||
|
@ -63,25 +63,3 @@ remove_orphaned_entries:
|
|||||||
example: "00212EFFFF012345"
|
example: "00212EFFFF012345"
|
||||||
selector:
|
selector:
|
||||||
text:
|
text:
|
||||||
|
|
||||||
alarm_panel_state:
|
|
||||||
name: Alarm panel state
|
|
||||||
description: Put keypad panel in an intermediate state, to help with visual and audible cues to the user.
|
|
||||||
target:
|
|
||||||
entity:
|
|
||||||
integration: deconz
|
|
||||||
domain: alarm_control_panel
|
|
||||||
fields:
|
|
||||||
panel_state:
|
|
||||||
name: Panel state
|
|
||||||
description: >-
|
|
||||||
- "entry_delay": make panel beep until panel is disarmed. Beep interval is long.
|
|
||||||
- "exit_delay": make panel beep until panel is set to armed state. Beep interval is short.
|
|
||||||
- "not_ready_to_arm": turn on yellow status led on the panel. Indicate not all conditions for arming are met.
|
|
||||||
required: true
|
|
||||||
selector:
|
|
||||||
select:
|
|
||||||
options:
|
|
||||||
- "entry_delay"
|
|
||||||
- "exit_delay"
|
|
||||||
- "not_ready_to_arm"
|
|
||||||
|
@ -1400,7 +1400,7 @@ pydaikin==2.4.4
|
|||||||
pydanfossair==0.1.0
|
pydanfossair==0.1.0
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==82
|
pydeconz==83
|
||||||
|
|
||||||
# homeassistant.components.delijn
|
# homeassistant.components.delijn
|
||||||
pydelijn==0.6.1
|
pydelijn==0.6.1
|
||||||
|
@ -797,7 +797,7 @@ pycoolmasternet-async==0.1.2
|
|||||||
pydaikin==2.4.4
|
pydaikin==2.4.4
|
||||||
|
|
||||||
# homeassistant.components.deconz
|
# homeassistant.components.deconz
|
||||||
pydeconz==82
|
pydeconz==83
|
||||||
|
|
||||||
# homeassistant.components.dexcom
|
# homeassistant.components.dexcom
|
||||||
pydexcom==0.2.0
|
pydexcom==0.2.0
|
||||||
|
@ -6,24 +6,21 @@ from pydeconz.sensor import (
|
|||||||
ANCILLARY_CONTROL_ARMED_AWAY,
|
ANCILLARY_CONTROL_ARMED_AWAY,
|
||||||
ANCILLARY_CONTROL_ARMED_NIGHT,
|
ANCILLARY_CONTROL_ARMED_NIGHT,
|
||||||
ANCILLARY_CONTROL_ARMED_STAY,
|
ANCILLARY_CONTROL_ARMED_STAY,
|
||||||
|
ANCILLARY_CONTROL_ARMING_AWAY,
|
||||||
|
ANCILLARY_CONTROL_ARMING_NIGHT,
|
||||||
|
ANCILLARY_CONTROL_ARMING_STAY,
|
||||||
ANCILLARY_CONTROL_DISARMED,
|
ANCILLARY_CONTROL_DISARMED,
|
||||||
ANCILLARY_CONTROL_ENTRY_DELAY,
|
ANCILLARY_CONTROL_ENTRY_DELAY,
|
||||||
ANCILLARY_CONTROL_EXIT_DELAY,
|
ANCILLARY_CONTROL_EXIT_DELAY,
|
||||||
ANCILLARY_CONTROL_NOT_READY_TO_ARM,
|
ANCILLARY_CONTROL_IN_ALARM,
|
||||||
|
ANCILLARY_CONTROL_NOT_READY,
|
||||||
)
|
)
|
||||||
|
|
||||||
from homeassistant.components.alarm_control_panel import (
|
from homeassistant.components.alarm_control_panel import (
|
||||||
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
|
DOMAIN as ALARM_CONTROL_PANEL_DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.components.deconz.alarm_control_panel import (
|
|
||||||
CONF_ALARM_PANEL_STATE,
|
|
||||||
PANEL_ENTRY_DELAY,
|
|
||||||
PANEL_EXIT_DELAY,
|
|
||||||
PANEL_NOT_READY_TO_ARM,
|
|
||||||
SERVICE_ALARM_PANEL_STATE,
|
|
||||||
)
|
|
||||||
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
|
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
|
ATTR_CODE,
|
||||||
ATTR_ENTITY_ID,
|
ATTR_ENTITY_ID,
|
||||||
SERVICE_ALARM_ARM_AWAY,
|
SERVICE_ALARM_ARM_AWAY,
|
||||||
SERVICE_ALARM_ARM_HOME,
|
SERVICE_ALARM_ARM_HOME,
|
||||||
@ -32,7 +29,10 @@ from homeassistant.const import (
|
|||||||
STATE_ALARM_ARMED_AWAY,
|
STATE_ALARM_ARMED_AWAY,
|
||||||
STATE_ALARM_ARMED_HOME,
|
STATE_ALARM_ARMED_HOME,
|
||||||
STATE_ALARM_ARMED_NIGHT,
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_ARMING,
|
||||||
STATE_ALARM_DISARMED,
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_PENDING,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
STATE_UNAVAILABLE,
|
STATE_UNAVAILABLE,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -52,38 +52,68 @@ async def test_no_sensors(hass, aioclient_mock):
|
|||||||
async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
|
async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
|
||||||
"""Test successful creation of alarm control panel entities."""
|
"""Test successful creation of alarm control panel entities."""
|
||||||
data = {
|
data = {
|
||||||
|
"alarmsystems": {
|
||||||
|
"0": {
|
||||||
|
"name": "default",
|
||||||
|
"config": {
|
||||||
|
"armmode": "armed_away",
|
||||||
|
"configured": True,
|
||||||
|
"disarmed_entry_delay": 0,
|
||||||
|
"disarmed_exit_delay": 0,
|
||||||
|
"armed_away_entry_delay": 120,
|
||||||
|
"armed_away_exit_delay": 120,
|
||||||
|
"armed_away_trigger_duration": 120,
|
||||||
|
"armed_stay_entry_delay": 120,
|
||||||
|
"armed_stay_exit_delay": 120,
|
||||||
|
"armed_stay_trigger_duration": 120,
|
||||||
|
"armed_night_entry_delay": 120,
|
||||||
|
"armed_night_exit_delay": 120,
|
||||||
|
"armed_night_trigger_duration": 120,
|
||||||
|
},
|
||||||
|
"state": {"armstate": "armed_away", "seconds_remaining": 0},
|
||||||
|
"devices": {
|
||||||
|
"00:00:00:00:00:00:00:00-00": {},
|
||||||
|
"00:15:8d:00:02:af:95:f9-01-0101": {
|
||||||
|
"armmask": "AN",
|
||||||
|
"trigger": "state/vibration",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
"sensors": {
|
"sensors": {
|
||||||
"0": {
|
"0": {
|
||||||
"config": {
|
"config": {
|
||||||
"armed": "disarmed",
|
"battery": 95,
|
||||||
"enrolled": 0,
|
"enrolled": 1,
|
||||||
"on": True,
|
"on": True,
|
||||||
"panel": "disarmed",
|
|
||||||
"pending": [],
|
"pending": [],
|
||||||
"reachable": True,
|
"reachable": True,
|
||||||
},
|
},
|
||||||
"ep": 1,
|
"ep": 1,
|
||||||
"etag": "3c4008d74035dfaa1f0bb30d24468b12",
|
"etag": "5aaa1c6bae8501f59929539c6e8f44d6",
|
||||||
"lastseen": "2021-04-02T13:07Z",
|
"lastseen": "2021-07-25T18:07Z",
|
||||||
"manufacturername": "Universal Electronics Inc",
|
"manufacturername": "lk",
|
||||||
"modelid": "URC4450BC0-X-R",
|
"modelid": "ZB-KeypadGeneric-D0002",
|
||||||
"name": "Keypad",
|
"name": "Keypad",
|
||||||
"state": {
|
"state": {
|
||||||
"action": "armed_away,1111,55",
|
"action": "armed_stay",
|
||||||
"lastupdated": "2021-04-02T13:08:18.937",
|
"lastupdated": "2021-07-25T18:02:51.172",
|
||||||
"lowbattery": False,
|
"lowbattery": False,
|
||||||
"tampered": True,
|
"panel": "exit_delay",
|
||||||
|
"seconds_remaining": 55,
|
||||||
|
"tampered": False,
|
||||||
},
|
},
|
||||||
|
"swversion": "3.13",
|
||||||
"type": "ZHAAncillaryControl",
|
"type": "ZHAAncillaryControl",
|
||||||
"uniqueid": "00:0d:6f:00:13:4f:61:39-01-0501",
|
"uniqueid": "00:00:00:00:00:00:00:00-00",
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
with patch.dict(DECONZ_WEB_REQUEST, data):
|
with patch.dict(DECONZ_WEB_REQUEST, data):
|
||||||
config_entry = await setup_deconz_integration(hass, aioclient_mock)
|
config_entry = await setup_deconz_integration(hass, aioclient_mock)
|
||||||
|
|
||||||
assert len(hass.states.async_all()) == 2
|
assert len(hass.states.async_all()) == 3
|
||||||
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_DISARMED
|
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_PENDING
|
||||||
|
|
||||||
# Event signals alarm control panel armed away
|
# Event signals alarm control panel armed away
|
||||||
|
|
||||||
@ -92,7 +122,7 @@ async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"config": {"armed": ANCILLARY_CONTROL_ARMED_AWAY},
|
"state": {"panel": ANCILLARY_CONTROL_ARMED_AWAY},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -106,7 +136,7 @@ async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"config": {"armed": ANCILLARY_CONTROL_ARMED_NIGHT},
|
"state": {"panel": ANCILLARY_CONTROL_ARMED_NIGHT},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -122,29 +152,13 @@ async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"config": {"armed": ANCILLARY_CONTROL_ARMED_STAY},
|
"state": {"panel": ANCILLARY_CONTROL_ARMED_STAY},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_ARMED_HOME
|
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_ARMED_HOME
|
||||||
|
|
||||||
# Event signals alarm control panel armed night
|
|
||||||
|
|
||||||
event_changed_sensor = {
|
|
||||||
"t": "event",
|
|
||||||
"e": "changed",
|
|
||||||
"r": "sensors",
|
|
||||||
"id": "0",
|
|
||||||
"config": {"armed": ANCILLARY_CONTROL_ARMED_NIGHT},
|
|
||||||
}
|
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
|
||||||
await hass.async_block_till_done()
|
|
||||||
|
|
||||||
assert (
|
|
||||||
hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_ARMED_NIGHT
|
|
||||||
)
|
|
||||||
|
|
||||||
# Event signals alarm control panel disarmed
|
# Event signals alarm control panel disarmed
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
@ -152,116 +166,139 @@ async def test_alarm_control_panel(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "0",
|
"id": "0",
|
||||||
"config": {"armed": ANCILLARY_CONTROL_DISARMED},
|
"state": {"panel": ANCILLARY_CONTROL_DISARMED},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_DISARMED
|
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_DISARMED
|
||||||
|
|
||||||
|
# Event signals alarm control panel arming
|
||||||
|
|
||||||
|
for arming_event in {
|
||||||
|
ANCILLARY_CONTROL_ARMING_AWAY,
|
||||||
|
ANCILLARY_CONTROL_ARMING_NIGHT,
|
||||||
|
ANCILLARY_CONTROL_ARMING_STAY,
|
||||||
|
}:
|
||||||
|
|
||||||
|
event_changed_sensor = {
|
||||||
|
"t": "event",
|
||||||
|
"e": "changed",
|
||||||
|
"r": "sensors",
|
||||||
|
"id": "0",
|
||||||
|
"state": {"panel": arming_event},
|
||||||
|
}
|
||||||
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_ARMING
|
||||||
|
|
||||||
|
# Event signals alarm control panel pending
|
||||||
|
|
||||||
|
for pending_event in {ANCILLARY_CONTROL_ENTRY_DELAY, ANCILLARY_CONTROL_EXIT_DELAY}:
|
||||||
|
|
||||||
|
event_changed_sensor = {
|
||||||
|
"t": "event",
|
||||||
|
"e": "changed",
|
||||||
|
"r": "sensors",
|
||||||
|
"id": "0",
|
||||||
|
"state": {"panel": pending_event},
|
||||||
|
}
|
||||||
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_PENDING
|
||||||
|
)
|
||||||
|
|
||||||
|
# Event signals alarm control panel triggered
|
||||||
|
|
||||||
|
event_changed_sensor = {
|
||||||
|
"t": "event",
|
||||||
|
"e": "changed",
|
||||||
|
"r": "sensors",
|
||||||
|
"id": "0",
|
||||||
|
"state": {"panel": ANCILLARY_CONTROL_IN_ALARM},
|
||||||
|
}
|
||||||
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_TRIGGERED
|
||||||
|
|
||||||
|
# Event signals alarm control panel unknown state keeps previous state
|
||||||
|
|
||||||
|
event_changed_sensor = {
|
||||||
|
"t": "event",
|
||||||
|
"e": "changed",
|
||||||
|
"r": "sensors",
|
||||||
|
"id": "0",
|
||||||
|
"state": {"panel": ANCILLARY_CONTROL_NOT_READY},
|
||||||
|
}
|
||||||
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
assert hass.states.get("alarm_control_panel.keypad").state == STATE_ALARM_TRIGGERED
|
||||||
|
|
||||||
# Verify service calls
|
# Verify service calls
|
||||||
|
|
||||||
mock_deconz_put_request(aioclient_mock, config_entry.data, "/sensors/0/config")
|
|
||||||
|
|
||||||
# Service set alarm to away mode
|
# Service set alarm to away mode
|
||||||
|
|
||||||
|
mock_deconz_put_request(
|
||||||
|
aioclient_mock, config_entry.data, "/alarmsystems/0/arm_away"
|
||||||
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
ALARM_CONTROL_PANEL_DOMAIN,
|
ALARM_CONTROL_PANEL_DOMAIN,
|
||||||
SERVICE_ALARM_ARM_AWAY,
|
SERVICE_ALARM_ARM_AWAY,
|
||||||
{ATTR_ENTITY_ID: "alarm_control_panel.keypad"},
|
{ATTR_ENTITY_ID: "alarm_control_panel.keypad", ATTR_CODE: "1234"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert aioclient_mock.mock_calls[1][2] == {
|
assert aioclient_mock.mock_calls[1][2] == {"code0": "1234"}
|
||||||
"armed": ANCILLARY_CONTROL_ARMED_AWAY,
|
|
||||||
"panel": ANCILLARY_CONTROL_ARMED_AWAY,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Service set alarm to home mode
|
# Service set alarm to home mode
|
||||||
|
|
||||||
|
mock_deconz_put_request(
|
||||||
|
aioclient_mock, config_entry.data, "/alarmsystems/0/arm_stay"
|
||||||
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
ALARM_CONTROL_PANEL_DOMAIN,
|
ALARM_CONTROL_PANEL_DOMAIN,
|
||||||
SERVICE_ALARM_ARM_HOME,
|
SERVICE_ALARM_ARM_HOME,
|
||||||
{ATTR_ENTITY_ID: "alarm_control_panel.keypad"},
|
{ATTR_ENTITY_ID: "alarm_control_panel.keypad", ATTR_CODE: "2345"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert aioclient_mock.mock_calls[2][2] == {
|
assert aioclient_mock.mock_calls[2][2] == {"code0": "2345"}
|
||||||
"armed": ANCILLARY_CONTROL_ARMED_STAY,
|
|
||||||
"panel": ANCILLARY_CONTROL_ARMED_STAY,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Service set alarm to night mode
|
# Service set alarm to night mode
|
||||||
|
|
||||||
|
mock_deconz_put_request(
|
||||||
|
aioclient_mock, config_entry.data, "/alarmsystems/0/arm_night"
|
||||||
|
)
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
ALARM_CONTROL_PANEL_DOMAIN,
|
ALARM_CONTROL_PANEL_DOMAIN,
|
||||||
SERVICE_ALARM_ARM_NIGHT,
|
SERVICE_ALARM_ARM_NIGHT,
|
||||||
{ATTR_ENTITY_ID: "alarm_control_panel.keypad"},
|
{ATTR_ENTITY_ID: "alarm_control_panel.keypad", ATTR_CODE: "3456"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert aioclient_mock.mock_calls[3][2] == {
|
assert aioclient_mock.mock_calls[3][2] == {"code0": "3456"}
|
||||||
"armed": ANCILLARY_CONTROL_ARMED_NIGHT,
|
|
||||||
"panel": ANCILLARY_CONTROL_ARMED_NIGHT,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Service set alarm to disarmed
|
# Service set alarm to disarmed
|
||||||
|
|
||||||
|
mock_deconz_put_request(aioclient_mock, config_entry.data, "/alarmsystems/0/disarm")
|
||||||
|
|
||||||
await hass.services.async_call(
|
await hass.services.async_call(
|
||||||
ALARM_CONTROL_PANEL_DOMAIN,
|
ALARM_CONTROL_PANEL_DOMAIN,
|
||||||
SERVICE_ALARM_DISARM,
|
SERVICE_ALARM_DISARM,
|
||||||
{ATTR_ENTITY_ID: "alarm_control_panel.keypad"},
|
{ATTR_ENTITY_ID: "alarm_control_panel.keypad", ATTR_CODE: "4567"},
|
||||||
blocking=True,
|
blocking=True,
|
||||||
)
|
)
|
||||||
assert aioclient_mock.mock_calls[4][2] == {
|
assert aioclient_mock.mock_calls[4][2] == {"code0": "4567"}
|
||||||
"armed": ANCILLARY_CONTROL_DISARMED,
|
|
||||||
"panel": ANCILLARY_CONTROL_DISARMED,
|
|
||||||
}
|
|
||||||
|
|
||||||
# Verify entity service calls
|
|
||||||
|
|
||||||
# Service set panel to entry delay
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
|
||||||
DECONZ_DOMAIN,
|
|
||||||
SERVICE_ALARM_PANEL_STATE,
|
|
||||||
{
|
|
||||||
ATTR_ENTITY_ID: "alarm_control_panel.keypad",
|
|
||||||
CONF_ALARM_PANEL_STATE: PANEL_ENTRY_DELAY,
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
assert aioclient_mock.mock_calls[5][2] == {"panel": ANCILLARY_CONTROL_ENTRY_DELAY}
|
|
||||||
|
|
||||||
# Service set panel to exit delay
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
|
||||||
DECONZ_DOMAIN,
|
|
||||||
SERVICE_ALARM_PANEL_STATE,
|
|
||||||
{
|
|
||||||
ATTR_ENTITY_ID: "alarm_control_panel.keypad",
|
|
||||||
CONF_ALARM_PANEL_STATE: PANEL_EXIT_DELAY,
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
assert aioclient_mock.mock_calls[6][2] == {"panel": ANCILLARY_CONTROL_EXIT_DELAY}
|
|
||||||
|
|
||||||
# Service set panel to not ready to arm
|
|
||||||
|
|
||||||
await hass.services.async_call(
|
|
||||||
DECONZ_DOMAIN,
|
|
||||||
SERVICE_ALARM_PANEL_STATE,
|
|
||||||
{
|
|
||||||
ATTR_ENTITY_ID: "alarm_control_panel.keypad",
|
|
||||||
CONF_ALARM_PANEL_STATE: PANEL_NOT_READY_TO_ARM,
|
|
||||||
},
|
|
||||||
blocking=True,
|
|
||||||
)
|
|
||||||
assert aioclient_mock.mock_calls[7][2] == {
|
|
||||||
"panel": ANCILLARY_CONTROL_NOT_READY_TO_ARM
|
|
||||||
}
|
|
||||||
|
|
||||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||||
|
|
||||||
states = hass.states.async_all()
|
states = hass.states.async_all()
|
||||||
assert len(states) == 2
|
assert len(states) == 3
|
||||||
for state in states:
|
for state in states:
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
@ -2,13 +2,20 @@
|
|||||||
|
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
|
from pydeconz.sensor import (
|
||||||
|
ANCILLARY_CONTROL_ARMED_AWAY,
|
||||||
|
ANCILLARY_CONTROL_EMERGENCY,
|
||||||
|
ANCILLARY_CONTROL_FIRE,
|
||||||
|
ANCILLARY_CONTROL_INVALID_CODE,
|
||||||
|
ANCILLARY_CONTROL_PANIC,
|
||||||
|
)
|
||||||
|
|
||||||
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
|
from homeassistant.components.deconz.const import DOMAIN as DECONZ_DOMAIN
|
||||||
from homeassistant.components.deconz.deconz_event import (
|
from homeassistant.components.deconz.deconz_event import (
|
||||||
CONF_DECONZ_ALARM_EVENT,
|
CONF_DECONZ_ALARM_EVENT,
|
||||||
CONF_DECONZ_EVENT,
|
CONF_DECONZ_EVENT,
|
||||||
)
|
)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
CONF_CODE,
|
|
||||||
CONF_DEVICE_ID,
|
CONF_DEVICE_ID,
|
||||||
CONF_EVENT,
|
CONF_EVENT,
|
||||||
CONF_ID,
|
CONF_ID,
|
||||||
@ -200,39 +207,69 @@ async def test_deconz_events(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
async def test_deconz_alarm_events(hass, aioclient_mock, mock_deconz_websocket):
|
async def test_deconz_alarm_events(hass, aioclient_mock, mock_deconz_websocket):
|
||||||
"""Test successful creation of deconz alarm events."""
|
"""Test successful creation of deconz alarm events."""
|
||||||
data = {
|
data = {
|
||||||
|
"alarmsystems": {
|
||||||
|
"0": {
|
||||||
|
"name": "default",
|
||||||
|
"config": {
|
||||||
|
"armmode": "armed_away",
|
||||||
|
"configured": True,
|
||||||
|
"disarmed_entry_delay": 0,
|
||||||
|
"disarmed_exit_delay": 0,
|
||||||
|
"armed_away_entry_delay": 120,
|
||||||
|
"armed_away_exit_delay": 120,
|
||||||
|
"armed_away_trigger_duration": 120,
|
||||||
|
"armed_stay_entry_delay": 120,
|
||||||
|
"armed_stay_exit_delay": 120,
|
||||||
|
"armed_stay_trigger_duration": 120,
|
||||||
|
"armed_night_entry_delay": 120,
|
||||||
|
"armed_night_exit_delay": 120,
|
||||||
|
"armed_night_trigger_duration": 120,
|
||||||
|
},
|
||||||
|
"state": {"armstate": "armed_away", "seconds_remaining": 0},
|
||||||
|
"devices": {
|
||||||
|
"00:00:00:00:00:00:00:01-00": {},
|
||||||
|
"00:15:8d:00:02:af:95:f9-01-0101": {
|
||||||
|
"armmask": "AN",
|
||||||
|
"trigger": "state/vibration",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
"sensors": {
|
"sensors": {
|
||||||
"1": {
|
"1": {
|
||||||
"config": {
|
"config": {
|
||||||
"armed": "disarmed",
|
"battery": 95,
|
||||||
"enrolled": 0,
|
"enrolled": 1,
|
||||||
"on": True,
|
"on": True,
|
||||||
"panel": "disarmed",
|
|
||||||
"pending": [],
|
"pending": [],
|
||||||
"reachable": True,
|
"reachable": True,
|
||||||
},
|
},
|
||||||
"ep": 1,
|
"ep": 1,
|
||||||
"etag": "3c4008d74035dfaa1f0bb30d24468b12",
|
"etag": "5aaa1c6bae8501f59929539c6e8f44d6",
|
||||||
"lastseen": "2021-04-02T13:07Z",
|
"lastseen": "2021-07-25T18:07Z",
|
||||||
"manufacturername": "Universal Electronics Inc",
|
"manufacturername": "lk",
|
||||||
"modelid": "URC4450BC0-X-R",
|
"modelid": "ZB-KeypadGeneric-D0002",
|
||||||
"name": "Keypad",
|
"name": "Keypad",
|
||||||
"state": {
|
"state": {
|
||||||
"action": "armed_away,1111,55",
|
"action": "invalid_code",
|
||||||
"lastupdated": "2021-04-02T13:08:18.937",
|
"lastupdated": "2021-07-25T18:02:51.172",
|
||||||
"lowbattery": False,
|
"lowbattery": False,
|
||||||
"tampered": True,
|
"panel": "exit_delay",
|
||||||
|
"seconds_remaining": 55,
|
||||||
|
"tampered": False,
|
||||||
},
|
},
|
||||||
|
"swversion": "3.13",
|
||||||
"type": "ZHAAncillaryControl",
|
"type": "ZHAAncillaryControl",
|
||||||
"uniqueid": "00:00:00:00:00:00:00:01-01-0501",
|
"uniqueid": "00:00:00:00:00:00:00:01-00",
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
with patch.dict(DECONZ_WEB_REQUEST, data):
|
with patch.dict(DECONZ_WEB_REQUEST, data):
|
||||||
config_entry = await setup_deconz_integration(hass, aioclient_mock)
|
config_entry = await setup_deconz_integration(hass, aioclient_mock)
|
||||||
|
|
||||||
device_registry = await hass.helpers.device_registry.async_get_registry()
|
device_registry = await hass.helpers.device_registry.async_get_registry()
|
||||||
|
|
||||||
assert len(hass.states.async_all()) == 2
|
assert len(hass.states.async_all()) == 3
|
||||||
# 1 alarm control device + 2 additional devices for deconz service and host
|
# 1 alarm control device + 2 additional devices for deconz service and host
|
||||||
assert (
|
assert (
|
||||||
len(async_entries_for_config_entry(device_registry, config_entry.entry_id)) == 3
|
len(async_entries_for_config_entry(device_registry, config_entry.entry_id)) == 3
|
||||||
@ -240,14 +277,14 @@ async def test_deconz_alarm_events(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
|
|
||||||
captured_events = async_capture_events(hass, CONF_DECONZ_ALARM_EVENT)
|
captured_events = async_capture_events(hass, CONF_DECONZ_ALARM_EVENT)
|
||||||
|
|
||||||
# Armed away event
|
# Emergency event
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
"t": "event",
|
"t": "event",
|
||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"state": {"action": "armed_away,1234,1"},
|
"state": {"action": ANCILLARY_CONTROL_EMERGENCY},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
@ -261,86 +298,113 @@ async def test_deconz_alarm_events(hass, aioclient_mock, mock_deconz_websocket):
|
|||||||
CONF_ID: "keypad",
|
CONF_ID: "keypad",
|
||||||
CONF_UNIQUE_ID: "00:00:00:00:00:00:00:01",
|
CONF_UNIQUE_ID: "00:00:00:00:00:00:00:01",
|
||||||
CONF_DEVICE_ID: device.id,
|
CONF_DEVICE_ID: device.id,
|
||||||
CONF_EVENT: "armed_away",
|
CONF_EVENT: ANCILLARY_CONTROL_EMERGENCY,
|
||||||
CONF_CODE: "1234",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Unsupported events
|
# Fire event
|
||||||
|
|
||||||
# Bad action string; string is None
|
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
"t": "event",
|
"t": "event",
|
||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"state": {"action": None},
|
"state": {"action": ANCILLARY_CONTROL_FIRE},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(captured_events) == 1
|
device = device_registry.async_get_device(
|
||||||
|
identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:01")}
|
||||||
|
)
|
||||||
|
|
||||||
# Bad action string; empty string
|
assert len(captured_events) == 2
|
||||||
|
assert captured_events[1].data == {
|
||||||
|
CONF_ID: "keypad",
|
||||||
|
CONF_UNIQUE_ID: "00:00:00:00:00:00:00:01",
|
||||||
|
CONF_DEVICE_ID: device.id,
|
||||||
|
CONF_EVENT: ANCILLARY_CONTROL_FIRE,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Invalid code event
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
"t": "event",
|
"t": "event",
|
||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"state": {"action": ""},
|
"state": {"action": ANCILLARY_CONTROL_INVALID_CODE},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(captured_events) == 1
|
device = device_registry.async_get_device(
|
||||||
|
identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:01")}
|
||||||
|
)
|
||||||
|
|
||||||
# Bad action string; too few ","
|
assert len(captured_events) == 3
|
||||||
|
assert captured_events[2].data == {
|
||||||
|
CONF_ID: "keypad",
|
||||||
|
CONF_UNIQUE_ID: "00:00:00:00:00:00:00:01",
|
||||||
|
CONF_DEVICE_ID: device.id,
|
||||||
|
CONF_EVENT: ANCILLARY_CONTROL_INVALID_CODE,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Panic event
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
"t": "event",
|
"t": "event",
|
||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"state": {"action": "armed_away,1234"},
|
"state": {"action": ANCILLARY_CONTROL_PANIC},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(captured_events) == 1
|
device = device_registry.async_get_device(
|
||||||
|
identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:01")}
|
||||||
|
)
|
||||||
|
|
||||||
# Bad action string; unsupported command
|
assert len(captured_events) == 4
|
||||||
|
assert captured_events[3].data == {
|
||||||
|
CONF_ID: "keypad",
|
||||||
|
CONF_UNIQUE_ID: "00:00:00:00:00:00:00:01",
|
||||||
|
CONF_DEVICE_ID: device.id,
|
||||||
|
CONF_EVENT: ANCILLARY_CONTROL_PANIC,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only care for changes to specific action events
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
"t": "event",
|
"t": "event",
|
||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"state": {"action": "unsupported,1234,1"},
|
"state": {"action": ANCILLARY_CONTROL_ARMED_AWAY},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(captured_events) == 1
|
assert len(captured_events) == 4
|
||||||
|
|
||||||
# Only care for changes to action
|
# Only care for action events
|
||||||
|
|
||||||
event_changed_sensor = {
|
event_changed_sensor = {
|
||||||
"t": "event",
|
"t": "event",
|
||||||
"e": "changed",
|
"e": "changed",
|
||||||
"r": "sensors",
|
"r": "sensors",
|
||||||
"id": "1",
|
"id": "1",
|
||||||
"config": {"panel": "armed_away"},
|
"state": {"panel": ANCILLARY_CONTROL_ARMED_AWAY},
|
||||||
}
|
}
|
||||||
await mock_deconz_websocket(data=event_changed_sensor)
|
await mock_deconz_websocket(data=event_changed_sensor)
|
||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
assert len(captured_events) == 1
|
assert len(captured_events) == 4
|
||||||
|
|
||||||
await hass.config_entries.async_unload(config_entry.entry_id)
|
await hass.config_entries.async_unload(config_entry.entry_id)
|
||||||
|
|
||||||
states = hass.states.async_all()
|
states = hass.states.async_all()
|
||||||
assert len(hass.states.async_all()) == 2
|
assert len(hass.states.async_all()) == 3
|
||||||
for state in states:
|
for state in states:
|
||||||
assert state.state == STATE_UNAVAILABLE
|
assert state.state == STATE_UNAVAILABLE
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user