Add device action support to the alarm_control_panel integration (#27616)
* Add device action support to the alarm_control_panel integration * Improve tests
This commit is contained in:
parent
6ffc520b1c
commit
43c85c0549
6 changed files with 623 additions and 0 deletions
126
homeassistant/components/alarm_control_panel/device_action.py
Normal file
126
homeassistant/components/alarm_control_panel/device_action.py
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
"""Provides device automations for Alarm control panel."""
|
||||||
|
from typing import Optional, List
|
||||||
|
import voluptuous as vol
|
||||||
|
|
||||||
|
from homeassistant.const import (
|
||||||
|
ATTR_CODE,
|
||||||
|
ATTR_ENTITY_ID,
|
||||||
|
CONF_CODE,
|
||||||
|
CONF_DEVICE_ID,
|
||||||
|
CONF_DOMAIN,
|
||||||
|
CONF_ENTITY_ID,
|
||||||
|
CONF_TYPE,
|
||||||
|
SERVICE_ALARM_ARM_AWAY,
|
||||||
|
SERVICE_ALARM_ARM_HOME,
|
||||||
|
SERVICE_ALARM_ARM_NIGHT,
|
||||||
|
SERVICE_ALARM_DISARM,
|
||||||
|
SERVICE_ALARM_TRIGGER,
|
||||||
|
)
|
||||||
|
from homeassistant.core import HomeAssistant, Context
|
||||||
|
from homeassistant.helpers import entity_registry
|
||||||
|
import homeassistant.helpers.config_validation as cv
|
||||||
|
from . import ATTR_CODE_ARM_REQUIRED, DOMAIN
|
||||||
|
|
||||||
|
ACTION_TYPES = {"arm_away", "arm_home", "arm_night", "disarm", "trigger"}
|
||||||
|
|
||||||
|
ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
vol.Required(CONF_TYPE): vol.In(ACTION_TYPES),
|
||||||
|
vol.Required(CONF_ENTITY_ID): cv.entity_domain(DOMAIN),
|
||||||
|
vol.Optional(CONF_CODE): cv.string,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_actions(hass: HomeAssistant, device_id: str) -> List[dict]:
|
||||||
|
"""List device actions for Alarm control panel devices."""
|
||||||
|
registry = await entity_registry.async_get_registry(hass)
|
||||||
|
actions = []
|
||||||
|
|
||||||
|
# Get all the integrations entities for this device
|
||||||
|
for entry in entity_registry.async_entries_for_device(registry, device_id):
|
||||||
|
if entry.domain != DOMAIN:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Add actions for each entity that belongs to this integration
|
||||||
|
actions.append(
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: "arm_away",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
actions.append(
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: "arm_home",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
actions.append(
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: "arm_night",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
actions.append(
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: "disarm",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
actions.append(
|
||||||
|
{
|
||||||
|
CONF_DEVICE_ID: device_id,
|
||||||
|
CONF_DOMAIN: DOMAIN,
|
||||||
|
CONF_ENTITY_ID: entry.entity_id,
|
||||||
|
CONF_TYPE: "trigger",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return actions
|
||||||
|
|
||||||
|
|
||||||
|
async def async_call_action_from_config(
|
||||||
|
hass: HomeAssistant, config: dict, variables: dict, context: Optional[Context]
|
||||||
|
) -> None:
|
||||||
|
"""Execute a device action."""
|
||||||
|
config = ACTION_SCHEMA(config)
|
||||||
|
|
||||||
|
service_data = {ATTR_ENTITY_ID: config[CONF_ENTITY_ID]}
|
||||||
|
if CONF_CODE in config:
|
||||||
|
service_data[ATTR_CODE] = config[CONF_CODE]
|
||||||
|
|
||||||
|
if config[CONF_TYPE] == "arm_away":
|
||||||
|
service = SERVICE_ALARM_ARM_AWAY
|
||||||
|
elif config[CONF_TYPE] == "arm_home":
|
||||||
|
service = SERVICE_ALARM_ARM_HOME
|
||||||
|
elif config[CONF_TYPE] == "arm_night":
|
||||||
|
service = SERVICE_ALARM_ARM_NIGHT
|
||||||
|
elif config[CONF_TYPE] == "disarm":
|
||||||
|
service = SERVICE_ALARM_DISARM
|
||||||
|
elif config[CONF_TYPE] == "trigger":
|
||||||
|
service = SERVICE_ALARM_TRIGGER
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
DOMAIN, service, service_data, blocking=True, context=context
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_get_action_capabilities(hass, config):
|
||||||
|
"""List action capabilities."""
|
||||||
|
state = hass.states.get(config[CONF_ENTITY_ID])
|
||||||
|
code_required = state.attributes.get(ATTR_CODE_ARM_REQUIRED) if state else False
|
||||||
|
|
||||||
|
if config[CONF_TYPE] == "trigger" or (
|
||||||
|
config[CONF_TYPE] != "disarm" and not code_required
|
||||||
|
):
|
||||||
|
return {}
|
||||||
|
|
||||||
|
return {"extra_fields": vol.Schema({vol.Optional(CONF_CODE): str})}
|
11
homeassistant/components/alarm_control_panel/strings.json
Normal file
11
homeassistant/components/alarm_control_panel/strings.json
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"device_automation": {
|
||||||
|
"action_type": {
|
||||||
|
"arm_away": "Arm {entity_name} away",
|
||||||
|
"arm_home": "Arm {entity_name} home",
|
||||||
|
"arm_night": "Arm {entity_name} night",
|
||||||
|
"disarm": "Disarm {entity_name}",
|
||||||
|
"trigger": "Trigger {entity_name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -59,6 +59,9 @@ async def async_setup(hass, config):
|
||||||
hass.components.websocket_api.async_register_command(
|
hass.components.websocket_api.async_register_command(
|
||||||
websocket_device_automation_list_triggers
|
websocket_device_automation_list_triggers
|
||||||
)
|
)
|
||||||
|
hass.components.websocket_api.async_register_command(
|
||||||
|
websocket_device_automation_get_action_capabilities
|
||||||
|
)
|
||||||
hass.components.websocket_api.async_register_command(
|
hass.components.websocket_api.async_register_command(
|
||||||
websocket_device_automation_get_condition_capabilities
|
websocket_device_automation_get_condition_capabilities
|
||||||
)
|
)
|
||||||
|
@ -209,6 +212,22 @@ async def websocket_device_automation_list_triggers(hass, connection, msg):
|
||||||
connection.send_result(msg["id"], triggers)
|
connection.send_result(msg["id"], triggers)
|
||||||
|
|
||||||
|
|
||||||
|
@websocket_api.async_response
|
||||||
|
@websocket_api.websocket_command(
|
||||||
|
{
|
||||||
|
vol.Required("type"): "device_automation/action/capabilities",
|
||||||
|
vol.Required("action"): dict,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
async def websocket_device_automation_get_action_capabilities(hass, connection, msg):
|
||||||
|
"""Handle request for device action capabilities."""
|
||||||
|
action = msg["action"]
|
||||||
|
capabilities = await _async_get_device_automation_capabilities(
|
||||||
|
hass, "action", action
|
||||||
|
)
|
||||||
|
connection.send_result(msg["id"], capabilities)
|
||||||
|
|
||||||
|
|
||||||
@websocket_api.async_response
|
@websocket_api.async_response
|
||||||
@websocket_api.websocket_command(
|
@websocket_api.websocket_command(
|
||||||
{
|
{
|
||||||
|
|
274
tests/components/alarm_control_panel/test_device_action.py
Normal file
274
tests/components/alarm_control_panel/test_device_action.py
Normal file
|
@ -0,0 +1,274 @@
|
||||||
|
"""The tests for Alarm control panel device actions."""
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components.alarm_control_panel import DOMAIN
|
||||||
|
from homeassistant.const import (
|
||||||
|
CONF_PLATFORM,
|
||||||
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
|
STATE_UNKNOWN,
|
||||||
|
)
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
import homeassistant.components.automation as automation
|
||||||
|
from homeassistant.helpers import device_registry
|
||||||
|
|
||||||
|
from tests.common import (
|
||||||
|
MockConfigEntry,
|
||||||
|
assert_lists_same,
|
||||||
|
mock_device_registry,
|
||||||
|
mock_registry,
|
||||||
|
async_get_device_automations,
|
||||||
|
async_get_device_automation_capabilities,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def device_reg(hass):
|
||||||
|
"""Return an empty, loaded, registry."""
|
||||||
|
return mock_device_registry(hass)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def entity_reg(hass):
|
||||||
|
"""Return an empty, loaded, registry."""
|
||||||
|
return mock_registry(hass)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_actions(hass, device_reg, entity_reg):
|
||||||
|
"""Test we get the expected actions from a alarm_control_panel."""
|
||||||
|
config_entry = MockConfigEntry(domain="test", data={})
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
device_entry = device_reg.async_get_or_create(
|
||||||
|
config_entry_id=config_entry.entry_id,
|
||||||
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
|
)
|
||||||
|
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
|
||||||
|
expected_actions = [
|
||||||
|
{
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"type": "arm_away",
|
||||||
|
"device_id": device_entry.id,
|
||||||
|
"entity_id": "alarm_control_panel.test_5678",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"type": "arm_home",
|
||||||
|
"device_id": device_entry.id,
|
||||||
|
"entity_id": "alarm_control_panel.test_5678",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"type": "arm_night",
|
||||||
|
"device_id": device_entry.id,
|
||||||
|
"entity_id": "alarm_control_panel.test_5678",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"type": "disarm",
|
||||||
|
"device_id": device_entry.id,
|
||||||
|
"entity_id": "alarm_control_panel.test_5678",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"type": "trigger",
|
||||||
|
"device_id": device_entry.id,
|
||||||
|
"entity_id": "alarm_control_panel.test_5678",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
actions = await async_get_device_automations(hass, "action", device_entry.id)
|
||||||
|
assert_lists_same(actions, expected_actions)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_action_capabilities(hass, device_reg, entity_reg):
|
||||||
|
"""Test we get the expected capabilities from a sensor trigger."""
|
||||||
|
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||||
|
platform.init()
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(domain="test", data={})
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
device_entry = device_reg.async_get_or_create(
|
||||||
|
config_entry_id=config_entry.entry_id,
|
||||||
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
|
)
|
||||||
|
entity_reg.async_get_or_create(
|
||||||
|
DOMAIN,
|
||||||
|
"test",
|
||||||
|
platform.ENTITIES["no_arm_code"].unique_id,
|
||||||
|
device_id=device_entry.id,
|
||||||
|
)
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
||||||
|
|
||||||
|
expected_capabilities = {
|
||||||
|
"arm_away": {"extra_fields": []},
|
||||||
|
"arm_home": {"extra_fields": []},
|
||||||
|
"arm_night": {"extra_fields": []},
|
||||||
|
"disarm": {
|
||||||
|
"extra_fields": [{"name": "code", "optional": True, "type": "string"}]
|
||||||
|
},
|
||||||
|
"trigger": {"extra_fields": []},
|
||||||
|
}
|
||||||
|
actions = await async_get_device_automations(hass, "action", device_entry.id)
|
||||||
|
assert len(actions) == 5
|
||||||
|
for action in actions:
|
||||||
|
capabilities = await async_get_device_automation_capabilities(
|
||||||
|
hass, "action", action
|
||||||
|
)
|
||||||
|
assert capabilities == expected_capabilities[action["type"]]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_get_action_capabilities_arm_code(hass, device_reg, entity_reg):
|
||||||
|
"""Test we get the expected capabilities from a sensor trigger."""
|
||||||
|
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||||
|
platform.init()
|
||||||
|
|
||||||
|
config_entry = MockConfigEntry(domain="test", data={})
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
device_entry = device_reg.async_get_or_create(
|
||||||
|
config_entry_id=config_entry.entry_id,
|
||||||
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
|
)
|
||||||
|
entity_reg.async_get_or_create(
|
||||||
|
DOMAIN,
|
||||||
|
"test",
|
||||||
|
platform.ENTITIES["arm_code"].unique_id,
|
||||||
|
device_id=device_entry.id,
|
||||||
|
)
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
||||||
|
|
||||||
|
expected_capabilities = {
|
||||||
|
"arm_away": {
|
||||||
|
"extra_fields": [{"name": "code", "optional": True, "type": "string"}]
|
||||||
|
},
|
||||||
|
"arm_home": {
|
||||||
|
"extra_fields": [{"name": "code", "optional": True, "type": "string"}]
|
||||||
|
},
|
||||||
|
"arm_night": {
|
||||||
|
"extra_fields": [{"name": "code", "optional": True, "type": "string"}]
|
||||||
|
},
|
||||||
|
"disarm": {
|
||||||
|
"extra_fields": [{"name": "code", "optional": True, "type": "string"}]
|
||||||
|
},
|
||||||
|
"trigger": {"extra_fields": []},
|
||||||
|
}
|
||||||
|
actions = await async_get_device_automations(hass, "action", device_entry.id)
|
||||||
|
assert len(actions) == 5
|
||||||
|
for action in actions:
|
||||||
|
capabilities = await async_get_device_automation_capabilities(
|
||||||
|
hass, "action", action
|
||||||
|
)
|
||||||
|
assert capabilities == expected_capabilities[action["type"]]
|
||||||
|
|
||||||
|
|
||||||
|
async def test_action(hass):
|
||||||
|
"""Test for turn_on and turn_off actions."""
|
||||||
|
platform = getattr(hass.components, f"test.{DOMAIN}")
|
||||||
|
platform.init()
|
||||||
|
|
||||||
|
assert await async_setup_component(
|
||||||
|
hass,
|
||||||
|
automation.DOMAIN,
|
||||||
|
{
|
||||||
|
automation.DOMAIN: [
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "test_event_arm_away",
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"device_id": "abcdefgh",
|
||||||
|
"entity_id": "alarm_control_panel.alarm_no_arm_code",
|
||||||
|
"type": "arm_away",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "test_event_arm_home",
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"device_id": "abcdefgh",
|
||||||
|
"entity_id": "alarm_control_panel.alarm_no_arm_code",
|
||||||
|
"type": "arm_home",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "test_event_arm_night",
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"device_id": "abcdefgh",
|
||||||
|
"entity_id": "alarm_control_panel.alarm_no_arm_code",
|
||||||
|
"type": "arm_night",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": {"platform": "event", "event_type": "test_event_disarm"},
|
||||||
|
"action": {
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"device_id": "abcdefgh",
|
||||||
|
"entity_id": "alarm_control_panel.alarm_no_arm_code",
|
||||||
|
"type": "disarm",
|
||||||
|
"code": "1234",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"trigger": {
|
||||||
|
"platform": "event",
|
||||||
|
"event_type": "test_event_trigger",
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"domain": DOMAIN,
|
||||||
|
"device_id": "abcdefgh",
|
||||||
|
"entity_id": "alarm_control_panel.alarm_no_arm_code",
|
||||||
|
"type": "trigger",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}})
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.alarm_no_arm_code").state == STATE_UNKNOWN
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire("test_event_arm_away")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.alarm_no_arm_code").state
|
||||||
|
== STATE_ALARM_ARMED_AWAY
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire("test_event_arm_home")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.alarm_no_arm_code").state
|
||||||
|
== STATE_ALARM_ARMED_HOME
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire("test_event_arm_night")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.alarm_no_arm_code").state
|
||||||
|
== STATE_ALARM_ARMED_NIGHT
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire("test_event_disarm")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.alarm_no_arm_code").state
|
||||||
|
== STATE_ALARM_DISARMED
|
||||||
|
)
|
||||||
|
|
||||||
|
hass.bus.async_fire("test_event_trigger")
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
assert (
|
||||||
|
hass.states.get("alarm_control_panel.alarm_no_arm_code").state
|
||||||
|
== STATE_ALARM_TRIGGERED
|
||||||
|
)
|
|
@ -170,6 +170,106 @@ async def test_websocket_get_triggers(hass, hass_ws_client, device_reg, entity_r
|
||||||
assert _same_lists(triggers, expected_triggers)
|
assert _same_lists(triggers, expected_triggers)
|
||||||
|
|
||||||
|
|
||||||
|
async def test_websocket_get_action_capabilities(
|
||||||
|
hass, hass_ws_client, device_reg, entity_reg
|
||||||
|
):
|
||||||
|
"""Test we get the expected action capabilities for an alarm through websocket."""
|
||||||
|
await async_setup_component(hass, "device_automation", {})
|
||||||
|
config_entry = MockConfigEntry(domain="test", data={})
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
device_entry = device_reg.async_get_or_create(
|
||||||
|
config_entry_id=config_entry.entry_id,
|
||||||
|
connections={(device_registry.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")},
|
||||||
|
)
|
||||||
|
entity_reg.async_get_or_create(
|
||||||
|
"alarm_control_panel", "test", "5678", device_id=device_entry.id
|
||||||
|
)
|
||||||
|
expected_capabilities = {
|
||||||
|
"arm_away": {"extra_fields": []},
|
||||||
|
"arm_home": {"extra_fields": []},
|
||||||
|
"arm_night": {"extra_fields": []},
|
||||||
|
"disarm": {
|
||||||
|
"extra_fields": [{"name": "code", "optional": True, "type": "string"}]
|
||||||
|
},
|
||||||
|
"trigger": {"extra_fields": []},
|
||||||
|
}
|
||||||
|
|
||||||
|
client = await hass_ws_client(hass)
|
||||||
|
await client.send_json(
|
||||||
|
{"id": 1, "type": "device_automation/action/list", "device_id": device_entry.id}
|
||||||
|
)
|
||||||
|
msg = await client.receive_json()
|
||||||
|
|
||||||
|
assert msg["id"] == 1
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
actions = msg["result"]
|
||||||
|
|
||||||
|
id = 2
|
||||||
|
assert len(actions) == 5
|
||||||
|
for action in actions:
|
||||||
|
await client.send_json(
|
||||||
|
{
|
||||||
|
"id": id,
|
||||||
|
"type": "device_automation/action/capabilities",
|
||||||
|
"action": action,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await client.receive_json()
|
||||||
|
assert msg["id"] == id
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
capabilities = msg["result"]
|
||||||
|
assert capabilities == expected_capabilities[action["type"]]
|
||||||
|
id = id + 1
|
||||||
|
|
||||||
|
|
||||||
|
async def test_websocket_get_bad_action_capabilities(
|
||||||
|
hass, hass_ws_client, device_reg, entity_reg
|
||||||
|
):
|
||||||
|
"""Test we get no action capabilities for a non existing domain."""
|
||||||
|
await async_setup_component(hass, "device_automation", {})
|
||||||
|
expected_capabilities = {}
|
||||||
|
|
||||||
|
client = await hass_ws_client(hass)
|
||||||
|
await client.send_json(
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "device_automation/action/capabilities",
|
||||||
|
"action": {"domain": "beer"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await client.receive_json()
|
||||||
|
assert msg["id"] == 1
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
capabilities = msg["result"]
|
||||||
|
assert capabilities == expected_capabilities
|
||||||
|
|
||||||
|
|
||||||
|
async def test_websocket_get_no_action_capabilities(
|
||||||
|
hass, hass_ws_client, device_reg, entity_reg
|
||||||
|
):
|
||||||
|
"""Test we get no action capabilities for a domain with no device action capabilities."""
|
||||||
|
await async_setup_component(hass, "device_automation", {})
|
||||||
|
expected_capabilities = {}
|
||||||
|
|
||||||
|
client = await hass_ws_client(hass)
|
||||||
|
await client.send_json(
|
||||||
|
{
|
||||||
|
"id": 1,
|
||||||
|
"type": "device_automation/action/capabilities",
|
||||||
|
"action": {"domain": "deconz"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
msg = await client.receive_json()
|
||||||
|
assert msg["id"] == 1
|
||||||
|
assert msg["type"] == TYPE_RESULT
|
||||||
|
assert msg["success"]
|
||||||
|
capabilities = msg["result"]
|
||||||
|
assert capabilities == expected_capabilities
|
||||||
|
|
||||||
|
|
||||||
async def test_websocket_get_condition_capabilities(
|
async def test_websocket_get_condition_capabilities(
|
||||||
hass, hass_ws_client, device_reg, entity_reg
|
hass, hass_ws_client, device_reg, entity_reg
|
||||||
):
|
):
|
||||||
|
@ -204,6 +304,7 @@ async def test_websocket_get_condition_capabilities(
|
||||||
conditions = msg["result"]
|
conditions = msg["result"]
|
||||||
|
|
||||||
id = 2
|
id = 2
|
||||||
|
assert len(conditions) == 2
|
||||||
for condition in conditions:
|
for condition in conditions:
|
||||||
await client.send_json(
|
await client.send_json(
|
||||||
{
|
{
|
||||||
|
@ -301,6 +402,7 @@ async def test_websocket_get_trigger_capabilities(
|
||||||
triggers = msg["result"]
|
triggers = msg["result"]
|
||||||
|
|
||||||
id = 2
|
id = 2
|
||||||
|
assert len(triggers) == 2
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
await client.send_json(
|
await client.send_json(
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
"""
|
||||||
|
Provide a mock alarm_control_panel platform.
|
||||||
|
|
||||||
|
Call init before using it in your tests to ensure clean test data.
|
||||||
|
"""
|
||||||
|
from homeassistant.components.alarm_control_panel import AlarmControlPanel
|
||||||
|
from homeassistant.const import (
|
||||||
|
STATE_ALARM_ARMED_AWAY,
|
||||||
|
STATE_ALARM_ARMED_HOME,
|
||||||
|
STATE_ALARM_ARMED_NIGHT,
|
||||||
|
STATE_ALARM_DISARMED,
|
||||||
|
STATE_ALARM_TRIGGERED,
|
||||||
|
)
|
||||||
|
from tests.common import MockEntity
|
||||||
|
|
||||||
|
ENTITIES = {}
|
||||||
|
|
||||||
|
|
||||||
|
def init(empty=False):
|
||||||
|
"""Initialize the platform with entities."""
|
||||||
|
global ENTITIES
|
||||||
|
|
||||||
|
ENTITIES = (
|
||||||
|
{}
|
||||||
|
if empty
|
||||||
|
else {
|
||||||
|
"arm_code": MockAlarm(
|
||||||
|
name=f"Alarm arm code",
|
||||||
|
code_arm_required=True,
|
||||||
|
unique_id="unique_arm_code",
|
||||||
|
),
|
||||||
|
"no_arm_code": MockAlarm(
|
||||||
|
name=f"Alarm no arm code",
|
||||||
|
code_arm_required=False,
|
||||||
|
unique_id="unique_no_arm_code",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_platform(
|
||||||
|
hass, config, async_add_entities_callback, discovery_info=None
|
||||||
|
):
|
||||||
|
"""Return mock entities."""
|
||||||
|
async_add_entities_callback(list(ENTITIES.values()))
|
||||||
|
|
||||||
|
|
||||||
|
class MockAlarm(MockEntity, AlarmControlPanel):
|
||||||
|
"""Mock Alarm control panel class."""
|
||||||
|
|
||||||
|
def __init__(self, **values):
|
||||||
|
"""Init the Mock Alarm Control Panel."""
|
||||||
|
self._state = None
|
||||||
|
|
||||||
|
MockEntity.__init__(self, **values)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def code_arm_required(self):
|
||||||
|
"""Whether the code is required for arm actions."""
|
||||||
|
return self._handle("code_arm_required")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def state(self):
|
||||||
|
"""Return the state of the device."""
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def alarm_arm_away(self, code=None):
|
||||||
|
"""Send arm away command."""
|
||||||
|
self._state = STATE_ALARM_ARMED_AWAY
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
def alarm_arm_home(self, code=None):
|
||||||
|
"""Send arm home command."""
|
||||||
|
self._state = STATE_ALARM_ARMED_HOME
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
def alarm_arm_night(self, code=None):
|
||||||
|
"""Send arm night command."""
|
||||||
|
self._state = STATE_ALARM_ARMED_NIGHT
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
def alarm_disarm(self, code=None):
|
||||||
|
"""Send disarm command."""
|
||||||
|
if code == "1234":
|
||||||
|
self._state = STATE_ALARM_DISARMED
|
||||||
|
self.async_write_ha_state()
|
||||||
|
|
||||||
|
def alarm_trigger(self, code=None):
|
||||||
|
"""Send alarm trigger command."""
|
||||||
|
self._state = STATE_ALARM_TRIGGERED
|
||||||
|
self.async_write_ha_state()
|
Loading…
Add table
Add a link
Reference in a new issue