Compare commits
5 commits
dev
...
toggle_ent
Author | SHA1 | Date | |
---|---|---|---|
|
0e09aa9083 | ||
|
31679bd2d1 | ||
|
56f6522c00 | ||
|
b2944539f1 | ||
|
751e62e7e1 |
22 changed files with 573 additions and 58 deletions
|
@ -1,4 +1,5 @@
|
|||
"""Constants for device automations."""
|
||||
CONF_CHANGED_STATES = "toggled"
|
||||
CONF_IS_OFF = "is_off"
|
||||
CONF_IS_ON = "is_on"
|
||||
CONF_TOGGLE = "toggle"
|
||||
|
|
108
homeassistant/components/device_automation/entity.py
Normal file
108
homeassistant/components/device_automation/entity.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
"""Device automation helpers for entity."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
|
||||
from homeassistant.components.automation import (
|
||||
AutomationActionType,
|
||||
AutomationTriggerInfo,
|
||||
)
|
||||
from homeassistant.components.device_automation.const import CONF_CHANGED_STATES
|
||||
from homeassistant.components.homeassistant.triggers import state as state_trigger
|
||||
from homeassistant.const import CONF_ENTITY_ID, CONF_FOR, CONF_PLATFORM, CONF_TYPE
|
||||
from homeassistant.core import CALLBACK_TYPE, HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv
|
||||
from homeassistant.helpers.entity_registry import async_entries_for_device
|
||||
from homeassistant.helpers.typing import ConfigType
|
||||
|
||||
from . import DEVICE_TRIGGER_BASE_SCHEMA
|
||||
|
||||
# mypy: allow-untyped-calls, allow-untyped-defs
|
||||
|
||||
ENTITY_TRIGGERS = [
|
||||
{
|
||||
# Trigger when entity is turned on or off
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_TYPE: CONF_CHANGED_STATES,
|
||||
},
|
||||
]
|
||||
|
||||
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(CONF_TYPE): vol.In([CONF_CHANGED_STATES]),
|
||||
vol.Optional(CONF_FOR): cv.positive_time_period_dict,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def async_attach_trigger(
|
||||
hass: HomeAssistant,
|
||||
config: ConfigType,
|
||||
action: AutomationActionType,
|
||||
automation_info: AutomationTriggerInfo,
|
||||
) -> CALLBACK_TYPE:
|
||||
"""Listen for state changes based on configuration."""
|
||||
to_state = None
|
||||
state_config = {
|
||||
CONF_PLATFORM: "state",
|
||||
state_trigger.CONF_ENTITY_ID: config[CONF_ENTITY_ID],
|
||||
state_trigger.CONF_TO: to_state,
|
||||
}
|
||||
if CONF_FOR in config:
|
||||
state_config[CONF_FOR] = config[CONF_FOR]
|
||||
|
||||
state_config = await state_trigger.async_validate_trigger_config(hass, state_config)
|
||||
return await state_trigger.async_attach_trigger(
|
||||
hass, state_config, action, automation_info, platform_type="device"
|
||||
)
|
||||
|
||||
|
||||
async def _async_get_automations(
|
||||
hass: HomeAssistant,
|
||||
device_id: str,
|
||||
automation_templates: list[dict[str, str]],
|
||||
domain: str,
|
||||
) -> list[dict[str, str]]:
|
||||
"""List device automations."""
|
||||
automations: list[dict[str, str]] = []
|
||||
entity_registry = await hass.helpers.entity_registry.async_get_registry()
|
||||
|
||||
entries = [
|
||||
entry
|
||||
for entry in async_entries_for_device(entity_registry, device_id)
|
||||
if entry.domain == domain
|
||||
]
|
||||
|
||||
for entry in entries:
|
||||
automations.extend(
|
||||
{
|
||||
**template,
|
||||
"device_id": device_id,
|
||||
"entity_id": entry.entity_id,
|
||||
"domain": domain,
|
||||
}
|
||||
for template in automation_templates
|
||||
)
|
||||
|
||||
return automations
|
||||
|
||||
|
||||
async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str, domain: str
|
||||
) -> list[dict[str, Any]]:
|
||||
"""List device triggers."""
|
||||
return await _async_get_automations(hass, device_id, ENTITY_TRIGGERS, domain)
|
||||
|
||||
|
||||
async def async_get_trigger_capabilities(
|
||||
hass: HomeAssistant, config: ConfigType
|
||||
) -> dict[str, vol.Schema]:
|
||||
"""List trigger capabilities."""
|
||||
return {
|
||||
"extra_fields": vol.Schema(
|
||||
{vol.Optional(CONF_FOR): cv.positive_time_period_dict}
|
||||
)
|
||||
}
|
|
@ -23,7 +23,7 @@ from homeassistant.helpers import condition, config_validation as cv
|
|||
from homeassistant.helpers.entity_registry import async_entries_for_device
|
||||
from homeassistant.helpers.typing import ConfigType, TemplateVarsType
|
||||
|
||||
from . import DEVICE_TRIGGER_BASE_SCHEMA
|
||||
from . import DEVICE_TRIGGER_BASE_SCHEMA, entity
|
||||
from .const import (
|
||||
CONF_IS_OFF,
|
||||
CONF_IS_ON,
|
||||
|
@ -94,7 +94,7 @@ CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend(
|
|||
}
|
||||
)
|
||||
|
||||
TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
|
||||
_TOGGLE_TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
vol.Required(CONF_TYPE): vol.In([CONF_TURNED_OFF, CONF_TURNED_ON]),
|
||||
|
@ -102,6 +102,8 @@ TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend(
|
|||
}
|
||||
)
|
||||
|
||||
TRIGGER_SCHEMA = vol.Any(entity.TRIGGER_SCHEMA, _TOGGLE_TRIGGER_SCHEMA)
|
||||
|
||||
|
||||
async def async_call_action_from_config(
|
||||
hass: HomeAssistant,
|
||||
|
@ -155,6 +157,9 @@ async def async_attach_trigger(
|
|||
automation_info: AutomationTriggerInfo,
|
||||
) -> CALLBACK_TYPE:
|
||||
"""Listen for state changes based on configuration."""
|
||||
if config[CONF_TYPE] not in [CONF_TURNED_ON, CONF_TURNED_OFF]:
|
||||
return await entity.async_attach_trigger(hass, config, action, automation_info)
|
||||
|
||||
if config[CONF_TYPE] == CONF_TURNED_ON:
|
||||
to_state = "on"
|
||||
else:
|
||||
|
@ -221,7 +226,11 @@ async def async_get_triggers(
|
|||
hass: HomeAssistant, device_id: str, domain: str
|
||||
) -> list[dict[str, Any]]:
|
||||
"""List device triggers."""
|
||||
return await _async_get_automations(hass, device_id, ENTITY_TRIGGERS, domain)
|
||||
triggers = await entity.async_get_triggers(hass, device_id, domain)
|
||||
triggers.extend(
|
||||
await _async_get_automations(hass, device_id, ENTITY_TRIGGERS, domain)
|
||||
)
|
||||
return triggers
|
||||
|
||||
|
||||
async def async_get_condition_capabilities(
|
||||
|
@ -239,6 +248,9 @@ async def async_get_trigger_capabilities(
|
|||
hass: HomeAssistant, config: ConfigType
|
||||
) -> dict[str, vol.Schema]:
|
||||
"""List trigger capabilities."""
|
||||
if config[CONF_TYPE] not in [CONF_TURNED_ON, CONF_TURNED_OFF]:
|
||||
return await entity.async_get_trigger_capabilities(hass, config)
|
||||
|
||||
return {
|
||||
"extra_fields": vol.Schema(
|
||||
{vol.Optional(CONF_FOR): cv.positive_time_period_dict}
|
||||
|
|
|
@ -16,8 +16,9 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import DOMAIN
|
||||
|
||||
TRIGGER_SCHEMA = toggle_entity.TRIGGER_SCHEMA.extend(
|
||||
{vol.Required(CONF_DOMAIN): DOMAIN}
|
||||
TRIGGER_SCHEMA = vol.All(
|
||||
toggle_entity.TRIGGER_SCHEMA,
|
||||
vol.Schema({vol.Required(CONF_DOMAIN): DOMAIN}, extra=vol.ALLOW_EXTRA),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"is_off": "{entity_name} is off"
|
||||
},
|
||||
"trigger_type": {
|
||||
"toggled": "{entity_name} turned on or off",
|
||||
"turned_on": "{entity_name} turned on",
|
||||
"turned_off": "{entity_name} turned off"
|
||||
},
|
||||
|
|
|
@ -35,7 +35,7 @@ from . import DOMAIN
|
|||
|
||||
# mypy: disallow-any-generics
|
||||
|
||||
TARGET_TRIGGER_SCHEMA = vol.All(
|
||||
HUMIDIFIER_TRIGGER_SCHEMA = vol.All(
|
||||
DEVICE_TRIGGER_BASE_SCHEMA.extend(
|
||||
{
|
||||
vol.Required(CONF_ENTITY_ID): cv.entity_id,
|
||||
|
@ -48,12 +48,14 @@ TARGET_TRIGGER_SCHEMA = vol.All(
|
|||
cv.has_at_least_one_key(CONF_BELOW, CONF_ABOVE),
|
||||
)
|
||||
|
||||
TOGGLE_TRIGGER_SCHEMA = toggle_entity.TRIGGER_SCHEMA.extend(
|
||||
{vol.Required(CONF_DOMAIN): DOMAIN}
|
||||
TRIGGER_SCHEMA = vol.All(
|
||||
vol.Any(
|
||||
HUMIDIFIER_TRIGGER_SCHEMA,
|
||||
toggle_entity.TRIGGER_SCHEMA,
|
||||
),
|
||||
vol.Schema({vol.Required(CONF_DOMAIN): DOMAIN}, extra=vol.ALLOW_EXTRA),
|
||||
)
|
||||
|
||||
TRIGGER_SCHEMA = vol.Any(TARGET_TRIGGER_SCHEMA, TOGGLE_TRIGGER_SCHEMA)
|
||||
|
||||
|
||||
async def async_get_triggers(
|
||||
hass: HomeAssistant, device_id: str
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"device_automation": {
|
||||
"trigger_type": {
|
||||
"target_humidity_changed": "{entity_name} target humidity changed",
|
||||
"toggled": "{entity_name} turned on or off",
|
||||
"turned_on": "{entity_name} turned on",
|
||||
"turned_off": "{entity_name} turned off"
|
||||
},
|
||||
|
|
|
@ -16,8 +16,9 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import DOMAIN
|
||||
|
||||
TRIGGER_SCHEMA = toggle_entity.TRIGGER_SCHEMA.extend(
|
||||
{vol.Required(CONF_DOMAIN): DOMAIN}
|
||||
TRIGGER_SCHEMA = vol.All(
|
||||
toggle_entity.TRIGGER_SCHEMA,
|
||||
vol.Schema({vol.Required(CONF_DOMAIN): DOMAIN}, extra=vol.ALLOW_EXTRA),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
"is_off": "{entity_name} is off"
|
||||
},
|
||||
"trigger_type": {
|
||||
"toggled": "{entity_name} turned on or off",
|
||||
"turned_on": "{entity_name} turned on",
|
||||
"turned_off": "{entity_name} turned off"
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import DOMAIN
|
||||
|
||||
TRIGGER_SCHEMA = toggle_entity.TRIGGER_SCHEMA.extend(
|
||||
{vol.Required(CONF_DOMAIN): DOMAIN}
|
||||
TRIGGER_SCHEMA = vol.All(
|
||||
toggle_entity.TRIGGER_SCHEMA,
|
||||
vol.Schema({vol.Required(CONF_DOMAIN): DOMAIN}, extra=vol.ALLOW_EXTRA),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"is_off": "{entity_name} is off"
|
||||
},
|
||||
"trigger_type": {
|
||||
"toggled": "{entity_name} turned on or off",
|
||||
"turned_on": "{entity_name} turned on",
|
||||
"turned_off": "{entity_name} turned off"
|
||||
}
|
||||
|
|
|
@ -16,8 +16,9 @@ from homeassistant.helpers.typing import ConfigType
|
|||
|
||||
from . import DOMAIN
|
||||
|
||||
TRIGGER_SCHEMA = toggle_entity.TRIGGER_SCHEMA.extend(
|
||||
{vol.Required(CONF_DOMAIN): DOMAIN}
|
||||
TRIGGER_SCHEMA = vol.All(
|
||||
toggle_entity.TRIGGER_SCHEMA,
|
||||
vol.Schema({vol.Required(CONF_DOMAIN): DOMAIN}, extra=vol.ALLOW_EXTRA),
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"is_off": "{entity_name} is off"
|
||||
},
|
||||
"trigger_type": {
|
||||
"toggled": "{entity_name} turned on or off",
|
||||
"turned_on": "{entity_name} turned on",
|
||||
"turned_off": "{entity_name} turned off"
|
||||
}
|
||||
|
|
|
@ -140,6 +140,13 @@ async def test_websocket_get_triggers(hass, hass_ws_client, device_reg, entity_r
|
|||
)
|
||||
entity_reg.async_get_or_create("light", "test", "5678", device_id=device_entry.id)
|
||||
expected_triggers = [
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": "light",
|
||||
"type": "toggled",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": "light.test_5678",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": "light",
|
||||
|
@ -395,7 +402,7 @@ async def test_async_get_device_automations_single_device_trigger(
|
|||
hass, "trigger", [device_entry.id]
|
||||
)
|
||||
assert device_entry.id in result
|
||||
assert len(result[device_entry.id]) == 2
|
||||
assert len(result[device_entry.id]) == 3 # toggled, turned_on, turned_off
|
||||
|
||||
|
||||
async def test_async_get_device_automations_all_devices_trigger(
|
||||
|
@ -412,7 +419,7 @@ async def test_async_get_device_automations_all_devices_trigger(
|
|||
entity_reg.async_get_or_create("light", "test", "5678", device_id=device_entry.id)
|
||||
result = await device_automation.async_get_device_automations(hass, "trigger")
|
||||
assert device_entry.id in result
|
||||
assert len(result[device_entry.id]) == 2
|
||||
assert len(result[device_entry.id]) == 3 # toggled, turned_on, turned_off
|
||||
|
||||
|
||||
async def test_async_get_device_automations_all_devices_condition(
|
||||
|
@ -505,7 +512,7 @@ async def test_websocket_get_trigger_capabilities(
|
|||
triggers = msg["result"]
|
||||
|
||||
id = 2
|
||||
assert len(triggers) == 2
|
||||
assert len(triggers) == 3 # toggled, turned_on, turned_off
|
||||
for trigger in triggers:
|
||||
await client.send_json(
|
||||
{
|
||||
|
|
199
tests/components/device_automation/test_toggle_entity.py
Normal file
199
tests/components/device_automation/test_toggle_entity.py
Normal file
|
@ -0,0 +1,199 @@
|
|||
"""The test for device automation toggle entity helpers."""
|
||||
from datetime import timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
import homeassistant.components.automation as automation
|
||||
from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON
|
||||
from homeassistant.setup import async_setup_component
|
||||
import homeassistant.util.dt as dt_util
|
||||
|
||||
from tests.common import async_fire_time_changed, async_mock_service
|
||||
from tests.components.blueprint.conftest import stub_blueprint_populate # noqa: F401
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def calls(hass):
|
||||
"""Track calls to a mock service."""
|
||||
return async_mock_service(hass, "test", "automation")
|
||||
|
||||
|
||||
async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations):
|
||||
"""Test for turn_on and turn_off triggers firing.
|
||||
|
||||
This is a sanity test for the toggle entity device automation helper, this is
|
||||
tested by each integration too.
|
||||
"""
|
||||
platform = getattr(hass.components, "test.switch")
|
||||
|
||||
platform.init()
|
||||
assert await async_setup_component(
|
||||
hass, "switch", {"switch": {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
ent1, ent2, ent3 = platform.ENTITIES
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: [
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": "switch",
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "turned_on",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_on {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": "switch",
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "turned_off",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": "switch",
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "toggled",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_on_or_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_ON
|
||||
assert len(calls) == 0
|
||||
|
||||
hass.states.async_set(ent1.entity_id, STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 2
|
||||
assert {calls[0].data["some"], calls[1].data["some"]} == {
|
||||
f"turn_off device - {ent1.entity_id} - on - off - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - on - off - None",
|
||||
}
|
||||
|
||||
hass.states.async_set(ent1.entity_id, STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 4
|
||||
assert {calls[2].data["some"], calls[3].data["some"]} == {
|
||||
f"turn_on device - {ent1.entity_id} - off - on - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - off - on - None",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("trigger", ["turned_off", "toggled"])
|
||||
async def test_if_fires_on_state_change_with_for(
|
||||
hass, calls, enable_custom_integrations, trigger
|
||||
):
|
||||
"""Test for triggers firing with delay."""
|
||||
platform = getattr(hass.components, "test.switch")
|
||||
|
||||
platform.init()
|
||||
assert await async_setup_component(
|
||||
hass, "switch", {"switch": {CONF_PLATFORM: "test"}}
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
ent1, ent2, ent3 = platform.ENTITIES
|
||||
|
||||
assert await async_setup_component(
|
||||
hass,
|
||||
automation.DOMAIN,
|
||||
{
|
||||
automation.DOMAIN: [
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": "switch",
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": trigger,
|
||||
"for": {"seconds": 5},
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
)
|
||||
await hass.async_block_till_done()
|
||||
assert hass.states.get(ent1.entity_id).state == STATE_ON
|
||||
assert len(calls) == 0
|
||||
|
||||
hass.states.async_set(ent1.entity_id, STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 0
|
||||
async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10))
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
await hass.async_block_till_done()
|
||||
assert calls[0].data["some"] == "turn_off device - {} - on - off - 0:00:05".format(
|
||||
ent1.entity_id
|
||||
)
|
|
@ -65,6 +65,13 @@ async def test_get_triggers(hass, device_reg, entity_reg):
|
|||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"type": "toggled",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
]
|
||||
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
||||
assert_lists_same(triggers, expected_triggers)
|
||||
|
@ -139,6 +146,25 @@ async def test_if_fires_on_state_change(hass, calls):
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": "fan.entity",
|
||||
"type": "toggled",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": (
|
||||
"turn_on_or_off - {{ trigger.platform}} - "
|
||||
"{{ trigger.entity_id}} - {{ trigger.from_state.state}} - "
|
||||
"{{ trigger.to_state.state}} - {{ trigger.for }}"
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
|
@ -146,14 +172,20 @@ async def test_if_fires_on_state_change(hass, calls):
|
|||
# Fake that the entity is turning on.
|
||||
hass.states.async_set("fan.entity", STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["some"] == "turn_on - device - fan.entity - off - on - None"
|
||||
assert len(calls) == 2
|
||||
assert {calls[0].data["some"], calls[1].data["some"]} == {
|
||||
"turn_on - device - fan.entity - off - on - None",
|
||||
"turn_on_or_off - device - fan.entity - off - on - None",
|
||||
}
|
||||
|
||||
# Fake that the entity is turning off.
|
||||
hass.states.async_set("fan.entity", STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 2
|
||||
assert calls[1].data["some"] == "turn_off - device - fan.entity - on - off - None"
|
||||
assert len(calls) == 4
|
||||
assert {calls[2].data["some"], calls[3].data["some"]} == {
|
||||
"turn_off - device - fan.entity - on - off - None",
|
||||
"turn_on_or_off - device - fan.entity - on - off - None",
|
||||
}
|
||||
|
||||
|
||||
async def test_if_fires_on_state_change_with_for(hass, calls):
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
from homeassistant.components.homekit.const import CHAR_PROGRAMMABLE_SWITCH_EVENT
|
||||
from homeassistant.components.homekit.type_triggers import DeviceTriggerAccessory
|
||||
from homeassistant.const import STATE_OFF, STATE_ON
|
||||
from homeassistant.setup import async_setup_component
|
||||
|
@ -47,11 +48,16 @@ async def test_programmable_switch_button_fires_on_trigger(
|
|||
hk_driver.publish.reset_mock()
|
||||
hass.states.async_set("light.ceiling_lights", STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
hk_driver.publish.assert_called_once()
|
||||
assert len(hk_driver.publish.mock_calls) == 2 # one for on, one for toggle
|
||||
for call in hk_driver.publish.mock_calls:
|
||||
char = acc.get_characteristic(call.args[0]["aid"], call.args[0]["iid"])
|
||||
assert char.display_name == CHAR_PROGRAMMABLE_SWITCH_EVENT
|
||||
|
||||
hk_driver.publish.reset_mock()
|
||||
hass.states.async_set("light.ceiling_lights", STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
hk_driver.publish.assert_called_once()
|
||||
|
||||
assert len(hk_driver.publish.mock_calls) == 2 # one for on, one for toggle
|
||||
for call in hk_driver.publish.mock_calls:
|
||||
char = acc.get_characteristic(call.args[0]["aid"], call.args[0]["iid"])
|
||||
assert char.display_name == CHAR_PROGRAMMABLE_SWITCH_EVENT
|
||||
await acc.stop()
|
||||
|
|
|
@ -83,6 +83,13 @@ async def test_get_triggers(hass, device_reg, entity_reg):
|
|||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"type": "toggled",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
]
|
||||
triggers = await async_get_device_automations(hass, "trigger", device_entry.id)
|
||||
assert_lists_same(triggers, expected_triggers)
|
||||
|
@ -197,6 +204,30 @@ async def test_if_fires_on_state_change(hass, calls):
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": "humidifier.entity",
|
||||
"type": "toggled",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_on_or_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
|
@ -222,18 +253,20 @@ async def test_if_fires_on_state_change(hass, calls):
|
|||
# Fake turn off
|
||||
hass.states.async_set("humidifier.entity", STATE_OFF, {const.ATTR_HUMIDITY: 37})
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 4
|
||||
assert (
|
||||
calls[3].data["some"] == "turn_off device - humidifier.entity - on - off - None"
|
||||
)
|
||||
assert len(calls) == 5
|
||||
assert {calls[3].data["some"], calls[4].data["some"]} == {
|
||||
"turn_off device - humidifier.entity - on - off - None",
|
||||
"turn_on_or_off device - humidifier.entity - on - off - None",
|
||||
}
|
||||
|
||||
# Fake turn on
|
||||
hass.states.async_set("humidifier.entity", STATE_ON, {const.ATTR_HUMIDITY: 37})
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 5
|
||||
assert (
|
||||
calls[4].data["some"] == "turn_on device - humidifier.entity - off - on - None"
|
||||
)
|
||||
assert len(calls) == 7
|
||||
assert {calls[5].data["some"], calls[6].data["some"]} == {
|
||||
"turn_on device - humidifier.entity - off - on - None",
|
||||
"turn_on_or_off device - humidifier.entity - off - on - None",
|
||||
}
|
||||
|
||||
|
||||
async def test_invalid_config(hass, calls):
|
||||
|
|
|
@ -50,6 +50,13 @@ async def test_get_triggers(hass, device_reg, entity_reg):
|
|||
)
|
||||
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
|
||||
expected_triggers = [
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"type": "toggled",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
|
@ -156,6 +163,30 @@ async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations)
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "toggled",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_on_or_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
|
@ -165,17 +196,19 @@ async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations)
|
|||
|
||||
hass.states.async_set(ent1.entity_id, STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["some"] == "turn_off device - {} - on - off - None".format(
|
||||
ent1.entity_id
|
||||
)
|
||||
assert len(calls) == 2
|
||||
assert {calls[0].data["some"], calls[1].data["some"]} == {
|
||||
f"turn_off device - {ent1.entity_id} - on - off - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - on - off - None",
|
||||
}
|
||||
|
||||
hass.states.async_set(ent1.entity_id, STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 2
|
||||
assert calls[1].data["some"] == "turn_on device - {} - off - on - None".format(
|
||||
ent1.entity_id
|
||||
)
|
||||
assert len(calls) == 4
|
||||
assert {calls[2].data["some"], calls[3].data["some"]} == {
|
||||
f"turn_on device - {ent1.entity_id} - off - on - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - off - on - None",
|
||||
}
|
||||
|
||||
|
||||
async def test_if_fires_on_state_change_with_for(
|
||||
|
|
|
@ -50,6 +50,13 @@ async def test_get_triggers(hass, device_reg, entity_reg):
|
|||
)
|
||||
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
|
||||
expected_triggers = [
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"type": "toggled",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
|
@ -154,6 +161,30 @@ async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations)
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "toggled",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_on_or_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
|
@ -163,17 +194,19 @@ async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations)
|
|||
|
||||
hass.states.async_set(ent1.entity_id, STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["some"] == "turn_off device - {} - on - off - None".format(
|
||||
ent1.entity_id
|
||||
)
|
||||
assert len(calls) == 2
|
||||
assert {calls[0].data["some"], calls[1].data["some"]} == {
|
||||
f"turn_off device - {ent1.entity_id} - on - off - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - on - off - None",
|
||||
}
|
||||
|
||||
hass.states.async_set(ent1.entity_id, STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 2
|
||||
assert calls[1].data["some"] == "turn_on device - {} - off - on - None".format(
|
||||
ent1.entity_id
|
||||
)
|
||||
assert len(calls) == 4
|
||||
assert {calls[2].data["some"], calls[3].data["some"]} == {
|
||||
f"turn_on device - {ent1.entity_id} - off - on - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - off - on - None",
|
||||
}
|
||||
|
||||
|
||||
async def test_if_fires_on_state_change_with_for(
|
||||
|
|
|
@ -50,6 +50,13 @@ async def test_get_triggers(hass, device_reg, entity_reg):
|
|||
)
|
||||
entity_reg.async_get_or_create(DOMAIN, "test", "5678", device_id=device_entry.id)
|
||||
expected_triggers = [
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"type": "toggled",
|
||||
"device_id": device_entry.id,
|
||||
"entity_id": f"{DOMAIN}.test_5678",
|
||||
},
|
||||
{
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
|
@ -154,6 +161,30 @@ async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations)
|
|||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"trigger": {
|
||||
"platform": "device",
|
||||
"domain": DOMAIN,
|
||||
"device_id": "",
|
||||
"entity_id": ent1.entity_id,
|
||||
"type": "toggled",
|
||||
},
|
||||
"action": {
|
||||
"service": "test.automation",
|
||||
"data_template": {
|
||||
"some": "turn_on_or_off {{ trigger.%s }}"
|
||||
% "}} - {{ trigger.".join(
|
||||
(
|
||||
"platform",
|
||||
"entity_id",
|
||||
"from_state.state",
|
||||
"to_state.state",
|
||||
"for",
|
||||
)
|
||||
)
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
)
|
||||
|
@ -163,17 +194,19 @@ async def test_if_fires_on_state_change(hass, calls, enable_custom_integrations)
|
|||
|
||||
hass.states.async_set(ent1.entity_id, STATE_OFF)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["some"] == "turn_off device - {} - on - off - None".format(
|
||||
ent1.entity_id
|
||||
)
|
||||
assert len(calls) == 2
|
||||
assert {calls[0].data["some"], calls[1].data["some"]} == {
|
||||
f"turn_off device - {ent1.entity_id} - on - off - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - on - off - None",
|
||||
}
|
||||
|
||||
hass.states.async_set(ent1.entity_id, STATE_ON)
|
||||
await hass.async_block_till_done()
|
||||
assert len(calls) == 2
|
||||
assert calls[1].data["some"] == "turn_on device - {} - off - on - None".format(
|
||||
ent1.entity_id
|
||||
)
|
||||
assert len(calls) == 4
|
||||
assert {calls[2].data["some"], calls[3].data["some"]} == {
|
||||
f"turn_on device - {ent1.entity_id} - off - on - None",
|
||||
f"turn_on_or_off device - {ent1.entity_id} - off - on - None",
|
||||
}
|
||||
|
||||
|
||||
async def test_if_fires_on_state_change_with_for(
|
||||
|
|
|
@ -65,6 +65,13 @@ async def test_get_triggers(hass, wemo_entity):
|
|||
CONF_PLATFORM: "device",
|
||||
CONF_TYPE: EVENT_TYPE_LONG_PRESS,
|
||||
},
|
||||
{
|
||||
CONF_DEVICE_ID: wemo_entity.device_id,
|
||||
CONF_DOMAIN: LIGHT_DOMAIN,
|
||||
CONF_ENTITY_ID: wemo_entity.entity_id,
|
||||
CONF_PLATFORM: "device",
|
||||
CONF_TYPE: "toggled",
|
||||
},
|
||||
{
|
||||
CONF_DEVICE_ID: wemo_entity.device_id,
|
||||
CONF_DOMAIN: LIGHT_DOMAIN,
|
||||
|
|
Loading…
Add table
Reference in a new issue