From a338e7e2426f70467462cce2be60e86b9d1cec43 Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 26 Jun 2023 09:59:01 +0200 Subject: [PATCH] Use entity registry id in toggle_entity device automations (#94995) * Use entity registry id in toggle_entity device automations * Update tests --------- Co-authored-by: J. Nick Koston --- .../components/device_automation/__init__.py | 16 ++ .../components/device_automation/entity.py | 4 +- .../components/device_automation/helpers.py | 12 ++ .../device_automation/toggle_entity.py | 8 +- .../components/humidifier/device_action.py | 14 +- .../components/light/device_action.py | 23 ++- .../components/remote/device_action.py | 14 +- .../components/switch/device_action.py | 14 +- .../components/device_automation/test_init.py | 22 +-- tests/components/fan/test_device_action.py | 52 +++++- tests/components/fan/test_device_trigger.py | 133 ++++++++++++--- .../humidifier/test_device_action.py | 113 +++++++++++-- .../humidifier/test_device_condition.py | 37 ++-- .../humidifier/test_device_trigger.py | 10 +- tests/components/light/test_device_action.py | 147 +++++++--------- .../components/light/test_device_condition.py | 123 +++++++++++--- tests/components/light/test_device_trigger.py | 158 +++++++++++++----- .../media_player/test_device_trigger.py | 34 +--- tests/components/remote/test_device_action.py | 96 +++++++---- .../remote/test_device_condition.py | 129 +++++++++++--- .../components/remote/test_device_trigger.py | 155 +++++++++++++---- tests/components/switch/test_device_action.py | 96 +++++++---- .../switch/test_device_condition.py | 128 +++++++++++--- .../components/switch/test_device_trigger.py | 155 +++++++++++++---- .../components/update/test_device_trigger.py | 123 ++++++++++++-- tests/components/wemo/test_device_trigger.py | 6 +- tests/components/zha/test_device_action.py | 10 +- 27 files changed, 1352 insertions(+), 480 deletions(-) diff --git a/homeassistant/components/device_automation/__init__.py b/homeassistant/components/device_automation/__init__.py index 80c635dc9945..af2fd61081cb 100644 --- a/homeassistant/components/device_automation/__init__.py +++ b/homeassistant/components/device_automation/__init__.py @@ -19,6 +19,7 @@ from homeassistant.const import ( ATTR_ENTITY_ID, CONF_DEVICE_ID, CONF_DOMAIN, + CONF_ENTITY_ID, CONF_PLATFORM, ) from homeassistant.core import HomeAssistant, callback @@ -340,6 +341,21 @@ def async_get_entity_registry_entry_or_raise( return entry +@callback +def async_validate_entity_schema( + hass: HomeAssistant, config: ConfigType, schema: vol.Schema +) -> ConfigType: + """Validate schema and resolve entity registry entry id to entity_id.""" + config = schema(config) + + registry = er.async_get(hass) + config[CONF_ENTITY_ID] = er.async_resolve_entity_id( + registry, config[CONF_ENTITY_ID] + ) + + return config + + def handle_device_errors( func: Callable[[HomeAssistant, ActiveConnection, dict[str, Any]], Awaitable[None]] ) -> Callable[ diff --git a/homeassistant/components/device_automation/entity.py b/homeassistant/components/device_automation/entity.py index f38daf2dae6e..87ff5a2cb520 100644 --- a/homeassistant/components/device_automation/entity.py +++ b/homeassistant/components/device_automation/entity.py @@ -23,7 +23,7 @@ ENTITY_TRIGGERS = [ TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend( { - vol.Required(CONF_ENTITY_ID): cv.entity_id, + vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(CONF_TYPE): vol.In([CONF_CHANGED_STATES]), vol.Optional(CONF_FOR): cv.positive_time_period_dict, } @@ -73,7 +73,7 @@ async def _async_get_automations( { **template, "device_id": device_id, - "entity_id": entry.entity_id, + "entity_id": entry.id, "domain": domain, } for template in automation_templates diff --git a/homeassistant/components/device_automation/helpers.py b/homeassistant/components/device_automation/helpers.py index 5f844c36aa57..8e000733536a 100644 --- a/homeassistant/components/device_automation/helpers.py +++ b/homeassistant/components/device_automation/helpers.py @@ -25,6 +25,8 @@ STATIC_VALIDATOR = { DeviceAutomationType.TRIGGER: "TRIGGER_SCHEMA", } +TOGGLE_ENTITY_DOMAINS = {"fan", "humidifier", "light", "remote", "switch"} + async def async_validate_device_automation_config( hass: HomeAssistant, @@ -43,6 +45,16 @@ async def async_validate_device_automation_config( ConfigType, getattr(platform, STATIC_VALIDATOR[automation_type])(config) ) + # Bypass checks for toggle entity domains + if ( + automation_type == DeviceAutomationType.ACTION + and validated_config[CONF_DOMAIN] in TOGGLE_ENTITY_DOMAINS + ): + return cast( + ConfigType, + await getattr(platform, DYNAMIC_VALIDATOR[automation_type])(hass, config), + ) + # Only call the dynamic validator if the referenced device exists and the relevant # config entry is loaded registry = dr.async_get(hass) diff --git a/homeassistant/components/device_automation/toggle_entity.py b/homeassistant/components/device_automation/toggle_entity.py index e5061cb691e8..189fc750e50a 100644 --- a/homeassistant/components/device_automation/toggle_entity.py +++ b/homeassistant/components/device_automation/toggle_entity.py @@ -78,14 +78,14 @@ DEVICE_ACTION_TYPES = [CONF_TOGGLE, CONF_TURN_OFF, CONF_TURN_ON] ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( { - vol.Required(CONF_ENTITY_ID): cv.entity_id, + vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(CONF_TYPE): vol.In(DEVICE_ACTION_TYPES), } ) CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend( { - vol.Required(CONF_ENTITY_ID): cv.entity_id, + vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(CONF_TYPE): vol.In([CONF_IS_OFF, CONF_IS_ON]), vol.Optional(CONF_FOR): cv.positive_time_period_dict, } @@ -93,7 +93,7 @@ CONDITION_SCHEMA = cv.DEVICE_CONDITION_BASE_SCHEMA.extend( _TOGGLE_TRIGGER_SCHEMA = DEVICE_TRIGGER_BASE_SCHEMA.extend( { - vol.Required(CONF_ENTITY_ID): cv.entity_id, + vol.Required(CONF_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(CONF_TYPE): vol.In([CONF_TURNED_OFF, CONF_TURNED_ON]), vol.Optional(CONF_FOR): cv.positive_time_period_dict, } @@ -196,7 +196,7 @@ async def _async_get_automations( { **template, "device_id": device_id, - "entity_id": entry.entity_id, + "entity_id": entry.id, "domain": domain, } for template in automation_templates diff --git a/homeassistant/components/humidifier/device_action.py b/homeassistant/components/humidifier/device_action.py index 1c027ba22e62..f0f2d415a6f9 100644 --- a/homeassistant/components/humidifier/device_action.py +++ b/homeassistant/components/humidifier/device_action.py @@ -3,7 +3,10 @@ from __future__ import annotations import voluptuous as vol -from homeassistant.components.device_automation import toggle_entity +from homeassistant.components.device_automation import ( + async_validate_entity_schema, + toggle_entity, +) from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_MODE, @@ -41,7 +44,14 @@ SET_MODE_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( ONOFF_SCHEMA = toggle_entity.ACTION_SCHEMA.extend({vol.Required(CONF_DOMAIN): DOMAIN}) -ACTION_SCHEMA = vol.Any(SET_HUMIDITY_SCHEMA, SET_MODE_SCHEMA, ONOFF_SCHEMA) +_ACTION_SCHEMA = vol.Any(SET_HUMIDITY_SCHEMA, SET_MODE_SCHEMA, ONOFF_SCHEMA) + + +async def async_validate_action_config( + hass: HomeAssistant, config: ConfigType +) -> ConfigType: + """Validate config.""" + return async_validate_entity_schema(hass, config, _ACTION_SCHEMA) async def async_get_actions( diff --git a/homeassistant/components/light/device_action.py b/homeassistant/components/light/device_action.py index 2b4c32cb3b19..2e3338e1253f 100644 --- a/homeassistant/components/light/device_action.py +++ b/homeassistant/components/light/device_action.py @@ -3,7 +3,11 @@ from __future__ import annotations import voluptuous as vol -from homeassistant.components.device_automation import toggle_entity +from homeassistant.components.device_automation import ( + async_get_entity_registry_entry_or_raise, + async_validate_entity_schema, + toggle_entity, +) from homeassistant.const import ( ATTR_ENTITY_ID, CONF_DEVICE_ID, @@ -37,9 +41,9 @@ TYPE_BRIGHTNESS_INCREASE = "brightness_increase" TYPE_BRIGHTNESS_DECREASE = "brightness_decrease" TYPE_FLASH = "flash" -ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( +_ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( { - vol.Required(ATTR_ENTITY_ID): cv.entity_id, + vol.Required(ATTR_ENTITY_ID): cv.entity_id_or_uuid, vol.Required(CONF_DOMAIN): DOMAIN, vol.Required(CONF_TYPE): vol.In( toggle_entity.DEVICE_ACTION_TYPES @@ -51,6 +55,13 @@ ACTION_SCHEMA = cv.DEVICE_ACTION_BASE_SCHEMA.extend( ) +async def async_validate_action_config( + hass: HomeAssistant, config: ConfigType +) -> ConfigType: + """Validate config.""" + return async_validate_entity_schema(hass, config, _ACTION_SCHEMA) + + async def async_call_action_from_config( hass: HomeAssistant, config: ConfigType, @@ -126,13 +137,15 @@ async def async_get_action_capabilities( if config[CONF_TYPE] != toggle_entity.CONF_TURN_ON: return {} + entry = async_get_entity_registry_entry_or_raise(hass, config[CONF_ENTITY_ID]) + try: - supported_color_modes = get_supported_color_modes(hass, config[ATTR_ENTITY_ID]) + supported_color_modes = get_supported_color_modes(hass, entry.entity_id) except HomeAssistantError: supported_color_modes = None try: - supported_features = get_supported_features(hass, config[ATTR_ENTITY_ID]) + supported_features = get_supported_features(hass, entry.entity_id) except HomeAssistantError: supported_features = 0 diff --git a/homeassistant/components/remote/device_action.py b/homeassistant/components/remote/device_action.py index 09c540b5e014..936c7aca37a1 100644 --- a/homeassistant/components/remote/device_action.py +++ b/homeassistant/components/remote/device_action.py @@ -3,7 +3,10 @@ from __future__ import annotations import voluptuous as vol -from homeassistant.components.device_automation import toggle_entity +from homeassistant.components.device_automation import ( + async_validate_entity_schema, + toggle_entity, +) from homeassistant.const import CONF_DOMAIN from homeassistant.core import Context, HomeAssistant from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -12,7 +15,14 @@ from . import DOMAIN # mypy: disallow-any-generics -ACTION_SCHEMA = toggle_entity.ACTION_SCHEMA.extend({vol.Required(CONF_DOMAIN): DOMAIN}) +_ACTION_SCHEMA = toggle_entity.ACTION_SCHEMA.extend({vol.Required(CONF_DOMAIN): DOMAIN}) + + +async def async_validate_action_config( + hass: HomeAssistant, config: ConfigType +) -> ConfigType: + """Validate config.""" + return async_validate_entity_schema(hass, config, _ACTION_SCHEMA) async def async_call_action_from_config( diff --git a/homeassistant/components/switch/device_action.py b/homeassistant/components/switch/device_action.py index 1aed2fa2467f..ce9f0a36117a 100644 --- a/homeassistant/components/switch/device_action.py +++ b/homeassistant/components/switch/device_action.py @@ -3,7 +3,10 @@ from __future__ import annotations import voluptuous as vol -from homeassistant.components.device_automation import toggle_entity +from homeassistant.components.device_automation import ( + async_validate_entity_schema, + toggle_entity, +) from homeassistant.const import CONF_DOMAIN from homeassistant.core import Context, HomeAssistant from homeassistant.helpers.typing import ConfigType, TemplateVarsType @@ -12,7 +15,14 @@ from . import DOMAIN # mypy: disallow-any-generics -ACTION_SCHEMA = toggle_entity.ACTION_SCHEMA.extend({vol.Required(CONF_DOMAIN): DOMAIN}) +_ACTION_SCHEMA = toggle_entity.ACTION_SCHEMA.extend({vol.Required(CONF_DOMAIN): DOMAIN}) + + +async def async_validate_action_config( + hass: HomeAssistant, config: ConfigType +) -> ConfigType: + """Validate config.""" + return async_validate_entity_schema(hass, config, _ACTION_SCHEMA) async def async_call_action_from_config( diff --git a/tests/components/device_automation/test_init.py b/tests/components/device_automation/test_init.py index d48fb520eba3..d0f013299b15 100644 --- a/tests/components/device_automation/test_init.py +++ b/tests/components/device_automation/test_init.py @@ -114,7 +114,7 @@ async def test_websocket_get_actions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( "fake_integration", "test", "5678", device_id=device_entry.id ) expected_actions = [ @@ -122,21 +122,21 @@ async def test_websocket_get_actions( "domain": "fake_integration", "type": "turn_off", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, { "domain": "fake_integration", "type": "turn_on", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, { "domain": "fake_integration", "type": "toggle", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, ] @@ -169,7 +169,7 @@ async def test_websocket_get_conditions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( "fake_integration", "test", "5678", device_id=device_entry.id ) expected_conditions = [ @@ -178,7 +178,7 @@ async def test_websocket_get_conditions( "domain": "fake_integration", "type": "is_off", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, { @@ -186,7 +186,7 @@ async def test_websocket_get_conditions( "domain": "fake_integration", "type": "is_on", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, ] @@ -223,7 +223,7 @@ async def test_websocket_get_triggers( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( "fake_integration", "test", "5678", device_id=device_entry.id ) expected_triggers = [ @@ -232,7 +232,7 @@ async def test_websocket_get_triggers( "domain": "fake_integration", "type": "changed_states", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, { @@ -240,7 +240,7 @@ async def test_websocket_get_triggers( "domain": "fake_integration", "type": "turned_off", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, { @@ -248,7 +248,7 @@ async def test_websocket_get_triggers( "domain": "fake_integration", "type": "turned_on", "device_id": device_entry.id, - "entity_id": "fake_integration.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, }, ] diff --git a/tests/components/fan/test_device_action.py b/tests/components/fan/test_device_action.py index 1fa3b3a13702..5404c80340e8 100644 --- a/tests/components/fan/test_device_action.py +++ b/tests/components/fan/test_device_action.py @@ -35,7 +35,7 @@ async def test_get_actions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_actions = [] @@ -44,7 +44,7 @@ async def test_get_actions( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for action in ["turn_on", "turn_off", "toggle"] @@ -78,7 +78,7 @@ async def test_get_actions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -92,7 +92,7 @@ async def test_get_actions_hidden_auxiliary( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for action in ["turn_on", "turn_off", "toggle"] @@ -103,8 +103,10 @@ async def test_get_actions_hidden_auxiliary( assert actions == unordered(expected_actions) -async def test_action(hass: HomeAssistant) -> None: +async def test_action(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None: """Test for turn_on and turn_off actions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + assert await async_setup_component( hass, automation.DOMAIN, @@ -118,7 +120,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "fan.entity", + "entity_id": entry.id, "type": "turn_off", }, }, @@ -130,7 +132,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "fan.entity", + "entity_id": entry.id, "type": "turn_on", }, }, @@ -142,7 +144,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "fan.entity", + "entity_id": entry.id, "type": "toggle", }, }, @@ -171,3 +173,37 @@ async def test_action(hass: HomeAssistant) -> None: assert len(turn_off_calls) == 1 assert len(turn_on_calls) == 1 assert len(toggle_calls) == 1 + + +async def test_action_legacy( + hass: HomeAssistant, entity_registry: er.EntityRegistry +) -> None: + """Test for turn_on and turn_off actions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "event", + "event_type": "test_event_turn_off", + }, + "action": { + "domain": DOMAIN, + "device_id": "abcdefgh", + "entity_id": entry.entity_id, + "type": "turn_off", + }, + }, + ] + }, + ) + + turn_off_calls = async_mock_service(hass, "fan", "turn_off") + + hass.bus.async_fire("test_event_turn_off") + await hass.async_block_till_done() + assert len(turn_off_calls) == 1 diff --git a/tests/components/fan/test_device_trigger.py b/tests/components/fan/test_device_trigger.py index aa26dd8f07db..f1de07a9e977 100644 --- a/tests/components/fan/test_device_trigger.py +++ b/tests/components/fan/test_device_trigger.py @@ -46,7 +46,7 @@ async def test_get_triggers( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_triggers = [ @@ -55,7 +55,7 @@ async def test_get_triggers( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for trigger in ["turned_off", "turned_on", "changed_states"] @@ -89,7 +89,7 @@ async def test_get_triggers_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_triggers_hidden_auxiliary( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for trigger in ["turned_off", "turned_on", "changed_states"] @@ -144,9 +144,44 @@ async def test_get_trigger_capabilities( assert capabilities == expected_capabilities -async def test_if_fires_on_state_change(hass: HomeAssistant, calls) -> None: +async def test_get_trigger_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a switch trigger.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + triggers = await async_get_device_automations( + hass, DeviceAutomationType.TRIGGER, device_entry.id + ) + for trigger in triggers: + trigger["entity_id"] = entity_registry.async_get(trigger["entity_id"]).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.TRIGGER, trigger + ) + assert capabilities == expected_capabilities + + +async def test_if_fires_on_state_change( + hass: HomeAssistant, entity_registry: er.EntityRegistry, calls +) -> None: """Test for turn_on and turn_off triggers firing.""" - hass.states.async_set("fan.entity", STATE_OFF) + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_OFF) assert await async_setup_component( hass, @@ -158,7 +193,7 @@ async def test_if_fires_on_state_change(hass: HomeAssistant, calls) -> None: "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "fan.entity", + "entity_id": entry.id, "type": "turned_on", }, "action": { @@ -180,7 +215,7 @@ async def test_if_fires_on_state_change(hass: HomeAssistant, calls) -> None: "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "fan.entity", + "entity_id": entry.id, "type": "turned_off", }, "action": { @@ -202,7 +237,7 @@ async def test_if_fires_on_state_change(hass: HomeAssistant, calls) -> None: "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "fan.entity", + "entity_id": entry.id, "type": "changed_states", }, "action": { @@ -224,28 +259,31 @@ async def test_if_fires_on_state_change(hass: HomeAssistant, calls) -> None: ) # Fake that the entity is turning on. - hass.states.async_set("fan.entity", STATE_ON) + hass.states.async_set(entry.entity_id, STATE_ON) await hass.async_block_till_done() 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", + f"turn_on - device - {entry.entity_id} - off - on - None", + f"turn_on_or_off - device - {entry.entity_id} - off - on - None", } # Fake that the entity is turning off. - hass.states.async_set("fan.entity", STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) await hass.async_block_till_done() 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", + f"turn_off - device - {entry.entity_id} - on - off - None", + f"turn_on_or_off - device - {entry.entity_id} - on - off - None", } -async def test_if_fires_on_state_change_with_for(hass: HomeAssistant, calls) -> None: - """Test for triggers firing with delay.""" - entity_id = "fan.entity" - hass.states.async_set(entity_id, STATE_ON) +async def test_if_fires_on_state_change_legacy( + hass: HomeAssistant, entity_registry: er.EntityRegistry, calls +) -> None: + """Test for turn_on and turn_off triggers firing.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_OFF) assert await async_setup_component( hass, @@ -257,7 +295,56 @@ async def test_if_fires_on_state_change_with_for(hass: HomeAssistant, calls) -> "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": entity_id, + "entity_id": entry.id, + "type": "turned_on", + }, + "action": { + "service": "test.automation", + "data_template": { + "some": ( + "turn_on " + "- {{ trigger.platform }} " + "- {{ trigger.entity_id }} " + "- {{ trigger.from_state.state }} " + "- {{ trigger.to_state.state }} " + "- {{ trigger.for }}" + ) + }, + }, + }, + ] + }, + ) + + # Fake that the entity is turning on. + hass.states.async_set(entry.entity_id, STATE_ON) + await hass.async_block_till_done() + assert len(calls) == 1 + assert ( + calls[0].data["some"] + == f"turn_on - device - {entry.entity_id} - off - on - None" + ) + + +async def test_if_fires_on_state_change_with_for( + hass: HomeAssistant, entity_registry: er.EntityRegistry, calls +) -> None: + """Test for triggers firing with delay.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.id, "type": "turned_off", "for": {"seconds": 5}, }, @@ -281,10 +368,9 @@ async def test_if_fires_on_state_change_with_for(hass: HomeAssistant, calls) -> }, ) await hass.async_block_till_done() - assert hass.states.get(entity_id).state == STATE_ON assert len(calls) == 0 - hass.states.async_set(entity_id, STATE_OFF) + hass.states.async_set(entry.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)) @@ -292,5 +378,6 @@ async def test_if_fires_on_state_change_with_for(hass: HomeAssistant, calls) -> assert len(calls) == 1 await hass.async_block_till_done() assert ( - calls[0].data["some"] == f"turn_off device - {entity_id} - on - off - 0:00:05" + calls[0].data["some"] + == f"turn_off device - {entry.entity_id} - on - off - 0:00:05" ) diff --git a/tests/components/humidifier/test_device_action.py b/tests/components/humidifier/test_device_action.py index 9c6de7adffe8..4e20d16ea1df 100644 --- a/tests/components/humidifier/test_device_action.py +++ b/tests/components/humidifier/test_device_action.py @@ -53,7 +53,7 @@ async def test_get_actions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -65,7 +65,8 @@ async def test_get_actions( f"{DOMAIN}.test_5678", "attributes", {"supported_features": features_state} ) expected_actions = [] - basic_action_types = ["turn_on", "turn_off", "toggle", "set_humidity"] + basic_action_types = ["set_humidity"] + toggle_action_types = ["turn_on", "turn_off", "toggle"] expected_actions += [ { "domain": DOMAIN, @@ -76,6 +77,16 @@ async def test_get_actions( } for action in basic_action_types ] + expected_actions += [ + { + "domain": DOMAIN, + "type": action, + "device_id": device_entry.id, + "entity_id": entity_entry.id, + "metadata": {"secondary": False}, + } + for action in toggle_action_types + ] expected_actions += [ { "domain": DOMAIN, @@ -115,7 +126,7 @@ async def test_get_actions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -124,6 +135,8 @@ async def test_get_actions_hidden_auxiliary( hidden_by=hidden_by, supported_features=0, ) + basic_action_types = ["set_humidity"] + toggle_action_types = ["turn_on", "turn_off", "toggle"] expected_actions = [] expected_actions += [ { @@ -133,7 +146,17 @@ async def test_get_actions_hidden_auxiliary( "entity_id": f"{DOMAIN}.test_5678", "metadata": {"secondary": True}, } - for action in ["turn_on", "turn_off", "toggle", "set_humidity"] + for action in basic_action_types + ] + expected_actions += [ + { + "domain": DOMAIN, + "type": action, + "device_id": device_entry.id, + "entity_id": entity_entry.id, + "metadata": {"secondary": True}, + } + for action in toggle_action_types ] actions = await async_get_device_automations( hass, DeviceAutomationType.ACTION, device_entry.id @@ -141,10 +164,12 @@ async def test_get_actions_hidden_auxiliary( assert actions == unordered(expected_actions) -async def test_action(hass: HomeAssistant) -> None: +async def test_action(hass: HomeAssistant, entity_registry: er.EntityRegistry) -> None: """Test for actions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + hass.states.async_set( - "humidifier.entity", + entry.entity_id, STATE_ON, {const.ATTR_AVAILABLE_MODES: [const.MODE_HOME, const.MODE_AWAY]}, ) @@ -162,7 +187,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "humidifier.entity", + "entity_id": entry.id, "type": "turn_off", }, }, @@ -174,7 +199,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "humidifier.entity", + "entity_id": entry.id, "type": "turn_on", }, }, @@ -183,7 +208,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "humidifier.entity", + "entity_id": entry.id, "type": "toggle", }, }, @@ -195,7 +220,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "humidifier.entity", + "entity_id": entry.entity_id, "type": "set_humidity", "humidity": 35, }, @@ -208,7 +233,7 @@ async def test_action(hass: HomeAssistant) -> None: "action": { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": "humidifier.entity", + "entity_id": entry.entity_id, "type": "set_mode", "mode": const.MODE_AWAY, }, @@ -269,6 +294,67 @@ async def test_action(hass: HomeAssistant) -> None: assert len(turn_off_calls) == 1 assert len(toggle_calls) == 1 + assert set_humidity_calls[0].domain == DOMAIN + assert set_humidity_calls[0].service == "set_humidity" + assert set_humidity_calls[0].data == {"entity_id": entry.entity_id, "humidity": 35} + assert set_mode_calls[0].domain == DOMAIN + assert set_mode_calls[0].service == "set_mode" + assert set_mode_calls[0].data == {"entity_id": entry.entity_id, "mode": "away"} + assert turn_on_calls[0].domain == DOMAIN + assert turn_on_calls[0].service == "turn_on" + assert turn_on_calls[0].data == {"entity_id": entry.entity_id} + assert turn_off_calls[0].domain == DOMAIN + assert turn_off_calls[0].service == "turn_off" + assert turn_off_calls[0].data == {"entity_id": entry.entity_id} + assert toggle_calls[0].domain == DOMAIN + assert toggle_calls[0].service == "toggle" + assert toggle_calls[0].data == {"entity_id": entry.entity_id} + + +async def test_action_legacy( + hass: HomeAssistant, entity_registry: er.EntityRegistry +) -> None: + """Test for actions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set( + entry.entity_id, + STATE_ON, + {const.ATTR_AVAILABLE_MODES: [const.MODE_HOME, const.MODE_AWAY]}, + ) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "event", + "event_type": "test_event_set_mode", + }, + "action": { + "domain": DOMAIN, + "device_id": "abcdefgh", + "entity_id": entry.entity_id, + "type": "set_mode", + "mode": const.MODE_AWAY, + }, + }, + ] + }, + ) + + set_mode_calls = async_mock_service(hass, "humidifier", "set_mode") + + hass.bus.async_fire("test_event_set_mode") + await hass.async_block_till_done() + assert len(set_mode_calls) == 1 + + assert set_mode_calls[0].domain == DOMAIN + assert set_mode_calls[0].service == "set_mode" + assert set_mode_calls[0].data == {"entity_id": entry.entity_id, "mode": "away"} + @pytest.mark.parametrize( ( @@ -380,7 +466,7 @@ async def test_capabilities( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -399,7 +485,7 @@ async def test_capabilities( { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.entity_id, "type": action, }, ) @@ -418,7 +504,6 @@ async def test_capabilities( ("action", "capability_name", "extra"), [ ("set_humidity", "humidity", {"type": "integer"}), - ("set_mode", "mode", {"type": "select", "options": []}), ], ) async def test_capabilities_missing_entity( diff --git a/tests/components/humidifier/test_device_condition.py b/tests/components/humidifier/test_device_condition.py index 06356c642603..22dfc5c31d5c 100644 --- a/tests/components/humidifier/test_device_condition.py +++ b/tests/components/humidifier/test_device_condition.py @@ -59,7 +59,7 @@ async def test_get_conditions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -78,7 +78,7 @@ async def test_get_conditions( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for condition in basic_condition_types @@ -89,7 +89,7 @@ async def test_get_conditions( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.entity_id, "metadata": {"secondary": False}, } for condition in expected_condition_types @@ -123,7 +123,7 @@ async def test_get_conditions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -137,7 +137,7 @@ async def test_get_conditions_hidden_auxiliary( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for condition in ["is_off", "is_on"] @@ -148,9 +148,13 @@ async def test_get_conditions_hidden_auxiliary( assert conditions == unordered(expected_conditions) -async def test_if_state(hass: HomeAssistant, calls) -> None: +async def test_if_state( + hass: HomeAssistant, entity_registry: er.EntityRegistry, calls +) -> None: """Test for turn_on and turn_off conditions.""" - hass.states.async_set("humidifier.entity", STATE_ON, {ATTR_MODE: const.MODE_AWAY}) + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON, {ATTR_MODE: const.MODE_AWAY}) assert await async_setup_component( hass, @@ -164,7 +168,7 @@ async def test_if_state(hass: HomeAssistant, calls) -> None: "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "humidifier.entity", + "entity_id": entry.id, "type": "is_on", } ], @@ -183,7 +187,7 @@ async def test_if_state(hass: HomeAssistant, calls) -> None: "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "humidifier.entity", + "entity_id": entry.id, "type": "is_off", } ], @@ -202,7 +206,7 @@ async def test_if_state(hass: HomeAssistant, calls) -> None: "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "humidifier.entity", + "entity_id": entry.entity_id, "type": "is_mode", "mode": "away", } @@ -218,7 +222,6 @@ async def test_if_state(hass: HomeAssistant, calls) -> None: }, ) await hass.async_block_till_done() - assert hass.states.get("humidifier.entity").state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -227,14 +230,14 @@ async def test_if_state(hass: HomeAssistant, calls) -> None: assert len(calls) == 1 assert calls[0].data["some"] == "is_on event - test_event1" - hass.states.async_set("humidifier.entity", STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") hass.bus.async_fire("test_event2") await hass.async_block_till_done() assert len(calls) == 2 assert calls[1].data["some"] == "is_off event - test_event2" - hass.states.async_set("humidifier.entity", STATE_ON, {ATTR_MODE: const.MODE_AWAY}) + hass.states.async_set(entry.entity_id, STATE_ON, {ATTR_MODE: const.MODE_AWAY}) hass.bus.async_fire("test_event3") await hass.async_block_till_done() @@ -242,7 +245,7 @@ async def test_if_state(hass: HomeAssistant, calls) -> None: assert len(calls) == 3 assert calls[2].data["some"] == "is_mode - event - test_event3" - hass.states.async_set("humidifier.entity", STATE_ON, {ATTR_MODE: const.MODE_HOME}) + hass.states.async_set(entry.entity_id, STATE_ON, {ATTR_MODE: const.MODE_HOME}) # Should not fire hass.bus.async_fire("test_event3") @@ -386,7 +389,7 @@ async def test_capabilities( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -395,7 +398,7 @@ async def test_capabilities( ) if set_state: hass.states.async_set( - f"{DOMAIN}.test_5678", + entity_entry.entity_id, STATE_ON, capabilities_state, ) @@ -405,7 +408,7 @@ async def test_capabilities( { "domain": DOMAIN, "device_id": "abcdefgh", - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.entity_id, "type": condition, }, ) diff --git a/tests/components/humidifier/test_device_trigger.py b/tests/components/humidifier/test_device_trigger.py index b69a59de1d24..afdbc0460424 100644 --- a/tests/components/humidifier/test_device_trigger.py +++ b/tests/components/humidifier/test_device_trigger.py @@ -89,7 +89,7 @@ async def test_get_triggers( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": entity_entry.entity_id, + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for trigger in toggle_trigger_types @@ -150,7 +150,7 @@ async def test_get_triggers_hidden_auxiliary( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": entity_entry.entity_id, + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for trigger in toggle_trigger_types @@ -231,7 +231,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": entry.entity_id, + "entity_id": entry.id, "type": "turned_on", }, "action": { @@ -255,7 +255,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": entry.entity_id, + "entity_id": entry.id, "type": "turned_off", }, "action": { @@ -279,7 +279,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": entry.entity_id, + "entity_id": entry.id, "type": "changed_states", }, "action": { diff --git a/tests/components/light/test_device_action.py b/tests/components/light/test_device_action.py index 46967d17f871..4f97eaec012c 100644 --- a/tests/components/light/test_device_action.py +++ b/tests/components/light/test_device_action.py @@ -12,9 +12,12 @@ from homeassistant.components.light import ( ColorMode, LightEntityFeature, ) -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant -from homeassistant.helpers import device_registry as dr, entity_registry as er +from homeassistant.helpers import ( + device_registry as dr, + entity_registry as er, +) from homeassistant.helpers.entity_registry import RegistryEntryHider from homeassistant.setup import async_setup_component @@ -49,7 +52,7 @@ async def test_get_actions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -63,13 +66,24 @@ async def test_get_actions( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for action in [ "turn_off", "turn_on", "toggle", + ] + ] + expected_actions += [ + { + "domain": DOMAIN, + "type": action, + "device_id": device_entry.id, + "entity_id": entity_entry.entity_id, + "metadata": {"secondary": False}, + } + for action in [ "brightness_decrease", "brightness_increase", "flash", @@ -104,7 +118,7 @@ async def test_get_actions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -120,7 +134,7 @@ async def test_get_actions_hidden_auxiliary( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for action in ["turn_on", "turn_off", "toggle"] @@ -168,7 +182,7 @@ async def test_get_action_capabilities( capabilities = await async_get_device_automation_capabilities( hass, DeviceAutomationType.ACTION, action ) - assert capabilities == {"extra_fields": []} + assert capabilities == {"extra_fields": []} or capabilities == {} @pytest.mark.parametrize( @@ -319,16 +333,13 @@ async def test_get_action_capabilities_features( async def test_action( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off actions.""" - platform = getattr(hass.components, f"test.{DOMAIN}") - - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1 = platform.ENTITIES[0] + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") assert await async_setup_component( hass, @@ -340,7 +351,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turn_off", }, }, @@ -349,7 +360,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turn_on", }, }, @@ -358,7 +369,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "toggle", }, }, @@ -367,7 +378,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.entity_id, "type": "flash", }, }, @@ -376,7 +387,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.entity_id, "type": "flash", "flash": "long", }, @@ -389,7 +400,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.entity_id, "type": "brightness_increase", }, }, @@ -401,7 +412,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.entity_id, "type": "brightness_decrease", }, }, @@ -410,7 +421,7 @@ async def test_action( "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.entity_id, "type": "turn_on", "brightness_pct": 75, }, @@ -419,89 +430,59 @@ async def test_action( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - assert len(calls) == 0 - - hass.bus.async_fire("test_off") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - - hass.bus.async_fire("test_off") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - - hass.bus.async_fire("test_on") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - - hass.bus.async_fire("test_on") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - - hass.bus.async_fire("test_toggle") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - - hass.bus.async_fire("test_toggle") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - - hass.bus.async_fire("test_toggle") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - - hass.bus.async_fire("test_flash_short") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - - hass.bus.async_fire("test_toggle") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - - hass.bus.async_fire("test_flash_long") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON turn_on_calls = async_mock_service(hass, DOMAIN, "turn_on") + turn_off_calls = async_mock_service(hass, DOMAIN, "turn_off") + toggle_calls = async_mock_service(hass, DOMAIN, "toggle") + + hass.bus.async_fire("test_toggle") + await hass.async_block_till_done() + assert len(toggle_calls) == 1 + assert toggle_calls[-1].data == {"entity_id": entry.entity_id} + + hass.bus.async_fire("test_off") + await hass.async_block_till_done() + assert len(turn_off_calls) == 1 + assert turn_off_calls[-1].data == {"entity_id": entry.entity_id} hass.bus.async_fire("test_brightness_increase") await hass.async_block_till_done() - assert len(turn_on_calls) == 1 - assert turn_on_calls[0].data["entity_id"] == ent1.entity_id - assert turn_on_calls[0].data["brightness_step_pct"] == 10 + assert turn_on_calls[-1].data == { + "entity_id": entry.entity_id, + "brightness_step_pct": 10, + } hass.bus.async_fire("test_brightness_decrease") await hass.async_block_till_done() - assert len(turn_on_calls) == 2 - assert turn_on_calls[1].data["entity_id"] == ent1.entity_id - assert turn_on_calls[1].data["brightness_step_pct"] == -10 + assert turn_on_calls[-1].data == { + "entity_id": entry.entity_id, + "brightness_step_pct": -10, + } hass.bus.async_fire("test_brightness") await hass.async_block_till_done() - assert len(turn_on_calls) == 3 - assert turn_on_calls[2].data["entity_id"] == ent1.entity_id - assert turn_on_calls[2].data["brightness_pct"] == 75 + assert turn_on_calls[-1].data == { + "entity_id": entry.entity_id, + "brightness_pct": 75, + } hass.bus.async_fire("test_on") await hass.async_block_till_done() - assert len(turn_on_calls) == 4 - assert turn_on_calls[3].data["entity_id"] == ent1.entity_id - assert "brightness_pct" not in turn_on_calls[3].data + assert turn_on_calls[-1].data == {"entity_id": entry.entity_id} hass.bus.async_fire("test_flash_short") await hass.async_block_till_done() - assert len(turn_on_calls) == 5 - assert turn_on_calls[4].data["entity_id"] == ent1.entity_id - assert turn_on_calls[4].data["flash"] == FLASH_SHORT + assert turn_on_calls[-1].data == { + "entity_id": entry.entity_id, + "flash": FLASH_SHORT, + } hass.bus.async_fire("test_flash_long") await hass.async_block_till_done() - assert len(turn_on_calls) == 6 - assert turn_on_calls[5].data["entity_id"] == ent1.entity_id - assert turn_on_calls[5].data["flash"] == FLASH_LONG + assert turn_on_calls[-1].data == {"entity_id": entry.entity_id, "flash": FLASH_LONG} diff --git a/tests/components/light/test_device_condition.py b/tests/components/light/test_device_condition.py index b57a2fe8dfe4..b38c225347ae 100644 --- a/tests/components/light/test_device_condition.py +++ b/tests/components/light/test_device_condition.py @@ -46,7 +46,7 @@ async def test_get_conditions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_conditions = [ @@ -55,7 +55,7 @@ async def test_get_conditions( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for condition in ["is_off", "is_on"] @@ -89,7 +89,7 @@ async def test_get_conditions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_conditions_hidden_auxiliary( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for condition in ["is_off", "is_on"] @@ -144,17 +144,49 @@ async def test_get_condition_capabilities( assert capabilities == expected_capabilities +async def test_get_condition_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a light condition.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + conditions = await async_get_device_automations( + hass, DeviceAutomationType.CONDITION, device_entry.id + ) + for condition in conditions: + condition["entity_id"] = entity_registry.async_get( + condition["entity_id"] + ).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.CONDITION, condition + ) + assert capabilities == expected_capabilities + + async def test_if_state( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off conditions.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -168,7 +200,7 @@ async def test_if_state( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_on", } ], @@ -187,7 +219,7 @@ async def test_if_state( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_off", } ], @@ -203,7 +235,6 @@ async def test_if_state( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -212,7 +243,7 @@ async def test_if_state( assert len(calls) == 1 assert calls[0].data["some"] == "is_on event - test_event1" - hass.states.async_set(ent1.entity_id, STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") hass.bus.async_fire("test_event2") await hass.async_block_till_done() @@ -220,10 +251,65 @@ async def test_if_state( assert calls[1].data["some"] == "is_off event - test_event2" +async def test_if_state_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for turn_on and turn_off conditions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": {"platform": "event", "event_type": "test_event1"}, + "condition": [ + { + "condition": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.entity_id, + "type": "is_on", + } + ], + "action": { + "service": "test.automation", + "data_template": { + "some": "is_on {{ trigger.%s }}" + % "}} - {{ trigger.".join(("platform", "event.event_type")) + }, + }, + }, + ] + }, + ) + await hass.async_block_till_done() + assert len(calls) == 0 + + hass.bus.async_fire("test_event1") + hass.bus.async_fire("test_event2") + await hass.async_block_till_done() + assert len(calls) == 1 + assert calls[0].data["some"] == "is_on event - test_event1" + + async def test_if_fires_on_for_condition( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for firing if condition is on with delay.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + point1 = dt_util.utcnow() point2 = point1 + timedelta(seconds=10) point3 = point2 + timedelta(seconds=10) @@ -248,7 +334,7 @@ async def test_if_fires_on_for_condition( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_off", "for": {"seconds": 5}, }, @@ -266,7 +352,6 @@ async def test_if_fires_on_for_condition( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -279,7 +364,7 @@ async def test_if_fires_on_for_condition( await hass.async_block_till_done() assert len(calls) == 0 - hass.states.async_set(ent1.entity_id, STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") await hass.async_block_till_done() assert len(calls) == 0 diff --git a/tests/components/light/test_device_trigger.py b/tests/components/light/test_device_trigger.py index d0b6eaec2aa9..085193e3b34c 100644 --- a/tests/components/light/test_device_trigger.py +++ b/tests/components/light/test_device_trigger.py @@ -7,7 +7,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.light import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -46,7 +46,7 @@ async def test_get_triggers( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_triggers = [ @@ -55,7 +55,7 @@ async def test_get_triggers( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -89,7 +89,7 @@ async def test_get_triggers_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_triggers_hidden_auxiliary( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -144,19 +144,47 @@ async def test_get_trigger_capabilities( assert capabilities == expected_capabilities +async def test_get_trigger_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a light trigger.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + triggers = await async_get_device_automations( + hass, DeviceAutomationType.TRIGGER, device_entry.id + ) + for trigger in triggers: + trigger["entity_id"] = entity_registry.async_get(trigger["entity_id"]).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.TRIGGER, trigger + ) + assert capabilities == expected_capabilities + + async def test_if_fires_on_state_change( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off triggers firing.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - await hass.async_block_till_done() - - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -168,7 +196,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turned_on", }, "action": { @@ -192,7 +220,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turned_off", }, "action": { @@ -216,7 +244,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "changed_states", }, "action": { @@ -239,39 +267,35 @@ async def test_if_fires_on_state_change( }, ) 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) + hass.states.async_set(entry.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", + f"turn_off device - {entry.entity_id} - on - off - None", + f"turn_on_or_off device - {entry.entity_id} - on - off - None", } - hass.states.async_set(ent1.entity_id, STATE_ON) + hass.states.async_set(entry.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", + f"turn_on device - {entry.entity_id} - off - on - None", + f"turn_on_or_off device - {entry.entity_id} - off - on - None", } -async def test_if_fires_on_state_change_with_for( - hass: HomeAssistant, calls, enable_custom_integrations: None +async def test_if_fires_on_state_change_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: - """Test for triggers firing with delay.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + """Test for turn_on and turn_off triggers firing.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - await hass.async_block_till_done() - - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -283,7 +307,61 @@ async def test_if_fires_on_state_change_with_for( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.entity_id, + "type": "turned_off", + }, + "action": { + "service": "test.automation", + "data_template": { + "some": "turn_on {{ trigger.%s }}" + % "}} - {{ trigger.".join( + ( + "platform", + "entity_id", + "from_state.state", + "to_state.state", + "for", + ) + ) + }, + }, + }, + ] + }, + ) + await hass.async_block_till_done() + assert len(calls) == 0 + + hass.states.async_set(entry.entity_id, STATE_OFF) + await hass.async_block_till_done() + assert len(calls) == 1 + assert ( + calls[0].data["some"] == f"turn_on device - {entry.entity_id} - on - off - None" + ) + + +async def test_if_fires_on_state_change_with_for( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for triggers firing with delay.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.id, "type": "turned_off", "for": {"seconds": 5}, }, @@ -307,16 +385,16 @@ async def test_if_fires_on_state_change_with_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) + hass.states.async_set(entry.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 + assert ( + calls[0].data["some"] + == f"turn_off device - {entry.entity_id} - on - off - 0:00:05" ) diff --git a/tests/components/media_player/test_device_trigger.py b/tests/components/media_player/test_device_trigger.py index 8bf71f856475..42608eacb097 100644 --- a/tests/components/media_player/test_device_trigger.py +++ b/tests/components/media_player/test_device_trigger.py @@ -58,11 +58,9 @@ async def test_get_triggers( DOMAIN, "test", "5678", device_id=device_entry.id ) - entity_trigger_types = { - "changed_states", - } trigger_types = { "buffering", + "changed_states", "idle", "paused", "playing", @@ -80,17 +78,6 @@ async def test_get_triggers( } for trigger in trigger_types ] - expected_triggers += [ - { - "platform": "device", - "domain": DOMAIN, - "type": trigger, - "device_id": device_entry.id, - "entity_id": entity_entry.entity_id, - "metadata": {"secondary": False}, - } - for trigger in entity_trigger_types - ] triggers = await async_get_device_automations( hass, DeviceAutomationType.TRIGGER, device_entry.id ) @@ -128,11 +115,9 @@ async def test_get_triggers_hidden_auxiliary( entity_category=entity_category, hidden_by=hidden_by, ) - entity_trigger_types = { - "changed_states", - } trigger_types = { "buffering", + "changed_states", "idle", "paused", "playing", @@ -150,17 +135,6 @@ async def test_get_triggers_hidden_auxiliary( } for trigger in trigger_types ] - expected_triggers += [ - { - "platform": "device", - "domain": DOMAIN, - "type": trigger, - "device_id": device_entry.id, - "entity_id": entity_entry.entity_id, - "metadata": {"secondary": True}, - } - for trigger in entity_trigger_types - ] triggers = await async_get_device_automations( hass, DeviceAutomationType.TRIGGER, device_entry.id ) @@ -263,9 +237,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": entry.entity_id - if trigger == "changed_states" - else entry.id, + "entity_id": entry.id, "type": trigger, }, "action": { diff --git a/tests/components/remote/test_device_action.py b/tests/components/remote/test_device_action.py index 563136e5d6df..97ff2fd58a00 100644 --- a/tests/components/remote/test_device_action.py +++ b/tests/components/remote/test_device_action.py @@ -5,7 +5,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.remote import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -41,7 +41,7 @@ async def test_get_actions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_actions = [ @@ -49,7 +49,7 @@ async def test_get_actions( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for action in ["turn_off", "turn_on", "toggle"] @@ -83,7 +83,7 @@ async def test_get_actions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -97,7 +97,7 @@ async def test_get_actions_hidden_auxiliary( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for action in ["turn_off", "turn_on", "toggle"] @@ -109,16 +109,13 @@ async def test_get_actions_hidden_auxiliary( async def test_action( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off actions.""" - platform = getattr(hass.components, f"test.{DOMAIN}") - - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") assert await async_setup_component( hass, @@ -126,29 +123,29 @@ async def test_action( { automation.DOMAIN: [ { - "trigger": {"platform": "event", "event_type": "test_event1"}, + "trigger": {"platform": "event", "event_type": "test_off"}, "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turn_off", }, }, { - "trigger": {"platform": "event", "event_type": "test_event2"}, + "trigger": {"platform": "event", "event_type": "test_on"}, "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turn_on", }, }, { - "trigger": {"platform": "event", "event_type": "test_event3"}, + "trigger": {"platform": "event", "event_type": "test_toggle"}, "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "toggle", }, }, @@ -156,29 +153,58 @@ async def test_action( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - assert len(calls) == 0 - hass.bus.async_fire("test_event1") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF + turn_on_calls = async_mock_service(hass, DOMAIN, "turn_on") + turn_off_calls = async_mock_service(hass, DOMAIN, "turn_off") + toggle_calls = async_mock_service(hass, DOMAIN, "toggle") - hass.bus.async_fire("test_event1") + hass.bus.async_fire("test_toggle") await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF + assert len(toggle_calls) == 1 + assert toggle_calls[-1].data == {"entity_id": entry.entity_id} - hass.bus.async_fire("test_event2") + hass.bus.async_fire("test_off") await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON + assert len(turn_off_calls) == 1 + assert turn_off_calls[-1].data == {"entity_id": entry.entity_id} - hass.bus.async_fire("test_event2") + hass.bus.async_fire("test_on") await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON + assert len(turn_on_calls) == 1 + assert turn_on_calls[-1].data == {"entity_id": entry.entity_id} - hass.bus.async_fire("test_event3") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - hass.bus.async_fire("test_event3") +async def test_action_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for turn_on and turn_off actions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": {"platform": "event", "event_type": "test_off"}, + "action": { + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.entity_id, + "type": "turn_off", + }, + }, + ] + }, + ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON + + turn_off_calls = async_mock_service(hass, DOMAIN, "turn_off") + + hass.bus.async_fire("test_off") + await hass.async_block_till_done() + assert len(turn_off_calls) == 1 + assert turn_off_calls[-1].data == {"entity_id": entry.entity_id} diff --git a/tests/components/remote/test_device_condition.py b/tests/components/remote/test_device_condition.py index 51ca928b39c3..b07747771d9d 100644 --- a/tests/components/remote/test_device_condition.py +++ b/tests/components/remote/test_device_condition.py @@ -8,7 +8,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.remote import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -46,7 +46,7 @@ async def test_get_conditions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_conditions = [ @@ -55,7 +55,7 @@ async def test_get_conditions( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for condition in ["is_off", "is_on"] @@ -89,7 +89,7 @@ async def test_get_conditions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_conditions_hidden_auxiliary( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for condition in ["is_off", "is_on"] @@ -144,17 +144,49 @@ async def test_get_condition_capabilities( assert capabilities == expected_capabilities +async def test_get_condition_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a remote condition.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + conditions = await async_get_device_automations( + hass, DeviceAutomationType.CONDITION, device_entry.id + ) + for condition in conditions: + condition["entity_id"] = entity_registry.async_get( + condition["entity_id"] + ).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.CONDITION, condition + ) + assert capabilities == expected_capabilities + + async def test_if_state( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off conditions.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -168,7 +200,7 @@ async def test_if_state( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_on", } ], @@ -187,7 +219,7 @@ async def test_if_state( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_off", } ], @@ -203,7 +235,6 @@ async def test_if_state( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -212,7 +243,7 @@ async def test_if_state( assert len(calls) == 1 assert calls[0].data["some"] == "is_on event - test_event1" - hass.states.async_set(ent1.entity_id, STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") hass.bus.async_fire("test_event2") await hass.async_block_till_done() @@ -220,21 +251,68 @@ async def test_if_state( assert calls[1].data["some"] == "is_off event - test_event2" +async def test_if_state_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for turn_on and turn_off conditions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": {"platform": "event", "event_type": "test_event1"}, + "condition": [ + { + "condition": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.entity_id, + "type": "is_on", + } + ], + "action": { + "service": "test.automation", + "data_template": { + "some": "is_on {{ trigger.%s }}" + % "}} - {{ trigger.".join(("platform", "event.event_type")) + }, + }, + }, + ] + }, + ) + await hass.async_block_till_done() + assert len(calls) == 0 + + hass.bus.async_fire("test_event1") + hass.bus.async_fire("test_event2") + await hass.async_block_till_done() + assert len(calls) == 1 + assert calls[0].data["some"] == "is_on event - test_event1" + + async def test_if_fires_on_for_condition( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for firing if condition is on with delay.""" point1 = dt_util.utcnow() point2 = point1 + timedelta(seconds=10) point3 = point2 + timedelta(seconds=10) - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) with freeze_time(point1) as freezer: assert await async_setup_component( @@ -248,7 +326,7 @@ async def test_if_fires_on_for_condition( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_off", "for": {"seconds": 5}, }, @@ -266,7 +344,6 @@ async def test_if_fires_on_for_condition( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -279,7 +356,7 @@ async def test_if_fires_on_for_condition( await hass.async_block_till_done() assert len(calls) == 0 - hass.states.async_set(ent1.entity_id, STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") await hass.async_block_till_done() assert len(calls) == 0 diff --git a/tests/components/remote/test_device_trigger.py b/tests/components/remote/test_device_trigger.py index d45d15b67ee4..b5dcca3dc4c9 100644 --- a/tests/components/remote/test_device_trigger.py +++ b/tests/components/remote/test_device_trigger.py @@ -7,7 +7,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.remote import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -46,7 +46,7 @@ async def test_get_triggers( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_triggers = [ @@ -55,7 +55,7 @@ async def test_get_triggers( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -89,7 +89,7 @@ async def test_get_triggers_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_triggers_hidden_auxiliary( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -144,17 +144,47 @@ async def test_get_trigger_capabilities( assert capabilities == expected_capabilities +async def test_get_trigger_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a remote trigger.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + triggers = await async_get_device_automations( + hass, DeviceAutomationType.TRIGGER, device_entry.id + ) + for trigger in triggers: + trigger["entity_id"] = entity_registry.async_get(trigger["entity_id"]).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.TRIGGER, trigger + ) + assert capabilities == expected_capabilities + + async def test_if_fires_on_state_change( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off triggers firing.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -166,7 +196,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turned_on", }, "action": { @@ -190,7 +220,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turned_off", }, "action": { @@ -214,7 +244,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "changed_states", }, "action": { @@ -236,38 +266,35 @@ async def test_if_fires_on_state_change( ] }, ) - 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) + hass.states.async_set(entry.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", + f"turn_off device - {entry.entity_id} - on - off - None", + f"turn_on_or_off device - {entry.entity_id} - on - off - None", } - hass.states.async_set(ent1.entity_id, STATE_ON) + hass.states.async_set(entry.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", + f"turn_on device - {entry.entity_id} - off - on - None", + f"turn_on_or_off device - {entry.entity_id} - off - on - None", } -async def test_if_fires_on_state_change_with_for( - hass: HomeAssistant, calls, enable_custom_integrations: None +async def test_if_fires_on_state_change_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: - """Test for triggers firing with delay.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + """Test for turn_on and turn_off triggers firing.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -279,7 +306,61 @@ async def test_if_fires_on_state_change_with_for( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.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", + ) + ) + }, + }, + }, + ] + }, + ) + assert len(calls) == 0 + + hass.states.async_set(entry.entity_id, STATE_OFF) + await hass.async_block_till_done() + assert len(calls) == 1 + assert ( + calls[0].data["some"] + == f"turn_off device - {entry.entity_id} - on - off - None" + ) + + +async def test_if_fires_on_state_change_with_for( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for triggers firing with delay.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.id, "type": "turned_off", "for": {"seconds": 5}, }, @@ -303,16 +384,16 @@ async def test_if_fires_on_state_change_with_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) + hass.states.async_set(entry.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 + assert ( + calls[0].data["some"] + == f"turn_off device - {entry.entity_id} - on - off - 0:00:05" ) diff --git a/tests/components/switch/test_device_action.py b/tests/components/switch/test_device_action.py index 1acea0b107ae..85799a49a349 100644 --- a/tests/components/switch/test_device_action.py +++ b/tests/components/switch/test_device_action.py @@ -5,7 +5,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.switch import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -41,7 +41,7 @@ async def test_get_actions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_actions = [] @@ -50,7 +50,7 @@ async def test_get_actions( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for action in ["turn_off", "turn_on", "toggle"] @@ -84,7 +84,7 @@ async def test_get_actions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -98,7 +98,7 @@ async def test_get_actions_hidden_auxiliary( "domain": DOMAIN, "type": action, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for action in ["turn_off", "turn_on", "toggle"] @@ -110,16 +110,13 @@ async def test_get_actions_hidden_auxiliary( async def test_action( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off actions.""" - platform = getattr(hass.components, f"test.{DOMAIN}") - - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") assert await async_setup_component( hass, @@ -127,29 +124,29 @@ async def test_action( { automation.DOMAIN: [ { - "trigger": {"platform": "event", "event_type": "test_event1"}, + "trigger": {"platform": "event", "event_type": "test_off"}, "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turn_off", }, }, { - "trigger": {"platform": "event", "event_type": "test_event2"}, + "trigger": {"platform": "event", "event_type": "test_on"}, "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turn_on", }, }, { - "trigger": {"platform": "event", "event_type": "test_event3"}, + "trigger": {"platform": "event", "event_type": "test_toggle"}, "action": { "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "toggle", }, }, @@ -157,29 +154,58 @@ async def test_action( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON - assert len(calls) == 0 - hass.bus.async_fire("test_event1") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF + turn_on_calls = async_mock_service(hass, DOMAIN, "turn_on") + turn_off_calls = async_mock_service(hass, DOMAIN, "turn_off") + toggle_calls = async_mock_service(hass, DOMAIN, "toggle") - hass.bus.async_fire("test_event1") + hass.bus.async_fire("test_toggle") await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF + assert len(toggle_calls) == 1 + assert toggle_calls[-1].data == {"entity_id": entry.entity_id} - hass.bus.async_fire("test_event2") + hass.bus.async_fire("test_off") await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON + assert len(turn_off_calls) == 1 + assert turn_off_calls[-1].data == {"entity_id": entry.entity_id} - hass.bus.async_fire("test_event2") + hass.bus.async_fire("test_on") await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON + assert len(turn_on_calls) == 1 + assert turn_on_calls[-1].data == {"entity_id": entry.entity_id} - hass.bus.async_fire("test_event3") - await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_OFF - hass.bus.async_fire("test_event3") +async def test_action_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for turn_on and turn_off actions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": {"platform": "event", "event_type": "test_off"}, + "action": { + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.id, + "type": "turn_off", + }, + }, + ] + }, + ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON + + turn_off_calls = async_mock_service(hass, DOMAIN, "turn_off") + + hass.bus.async_fire("test_off") + await hass.async_block_till_done() + assert len(turn_off_calls) == 1 + assert turn_off_calls[-1].data == {"entity_id": entry.entity_id} diff --git a/tests/components/switch/test_device_condition.py b/tests/components/switch/test_device_condition.py index e2512624c155..c60954e335f7 100644 --- a/tests/components/switch/test_device_condition.py +++ b/tests/components/switch/test_device_condition.py @@ -8,7 +8,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.switch import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -46,7 +46,7 @@ async def test_get_conditions( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_conditions = [ @@ -55,7 +55,7 @@ async def test_get_conditions( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for condition in ["is_off", "is_on"] @@ -89,7 +89,7 @@ async def test_get_conditions_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_conditions_hidden_auxiliary( "domain": DOMAIN, "type": condition, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for condition in ["is_off", "is_on"] @@ -144,17 +144,49 @@ async def test_get_condition_capabilities( assert capabilities == expected_capabilities +async def test_get_condition_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a switch condition.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + conditions = await async_get_device_automations( + hass, DeviceAutomationType.CONDITION, device_entry.id + ) + for condition in conditions: + condition["entity_id"] = entity_registry.async_get( + condition["entity_id"] + ).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.CONDITION, condition + ) + assert capabilities == expected_capabilities + + async def test_if_state( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off conditions.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -168,7 +200,7 @@ async def test_if_state( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_on", } ], @@ -187,7 +219,7 @@ async def test_if_state( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_off", } ], @@ -203,7 +235,6 @@ async def test_if_state( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -212,7 +243,7 @@ async def test_if_state( assert len(calls) == 1 assert calls[0].data["some"] == "is_on event - test_event1" - hass.states.async_set(ent1.entity_id, STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") hass.bus.async_fire("test_event2") await hass.async_block_till_done() @@ -220,21 +251,67 @@ async def test_if_state( assert calls[1].data["some"] == "is_off event - test_event2" +async def test_if_state_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for turn_on and turn_off conditions.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": {"platform": "event", "event_type": "test_event1"}, + "condition": [ + { + "condition": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.entity_id, + "type": "is_on", + } + ], + "action": { + "service": "test.automation", + "data_template": { + "some": "is_on {{ trigger.%s }}" + % "}} - {{ trigger.".join(("platform", "event.event_type")) + }, + }, + }, + ] + }, + ) + await hass.async_block_till_done() + assert len(calls) == 0 + + hass.bus.async_fire("test_event1") + await hass.async_block_till_done() + assert len(calls) == 1 + assert calls[0].data["some"] == "is_on event - test_event1" + + async def test_if_fires_on_for_condition( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for firing if condition is on with delay.""" point1 = dt_util.utcnow() point2 = point1 + timedelta(seconds=10) point3 = point2 + timedelta(seconds=10) - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) with freeze_time(point1) as freezer: assert await async_setup_component( @@ -248,7 +325,7 @@ async def test_if_fires_on_for_condition( "condition": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "is_off", "for": {"seconds": 5}, }, @@ -266,7 +343,6 @@ async def test_if_fires_on_for_condition( }, ) await hass.async_block_till_done() - assert hass.states.get(ent1.entity_id).state == STATE_ON assert len(calls) == 0 hass.bus.async_fire("test_event1") @@ -279,7 +355,7 @@ async def test_if_fires_on_for_condition( await hass.async_block_till_done() assert len(calls) == 0 - hass.states.async_set(ent1.entity_id, STATE_OFF) + hass.states.async_set(entry.entity_id, STATE_OFF) hass.bus.async_fire("test_event1") await hass.async_block_till_done() assert len(calls) == 0 diff --git a/tests/components/switch/test_device_trigger.py b/tests/components/switch/test_device_trigger.py index 7ca2e480f4d2..32f8f65b114b 100644 --- a/tests/components/switch/test_device_trigger.py +++ b/tests/components/switch/test_device_trigger.py @@ -7,7 +7,7 @@ from pytest_unordered import unordered import homeassistant.components.automation as automation from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.switch import DOMAIN -from homeassistant.const import CONF_PLATFORM, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.const import STATE_OFF, STATE_ON, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.helpers.entity_registry import RegistryEntryHider @@ -46,7 +46,7 @@ async def test_get_triggers( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_triggers = [ @@ -55,7 +55,7 @@ async def test_get_triggers( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -89,7 +89,7 @@ async def test_get_triggers_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -103,7 +103,7 @@ async def test_get_triggers_hidden_auxiliary( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -144,17 +144,47 @@ async def test_get_trigger_capabilities( assert capabilities == expected_capabilities +async def test_get_trigger_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a switch trigger.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + triggers = await async_get_device_automations( + hass, DeviceAutomationType.TRIGGER, device_entry.id + ) + for trigger in triggers: + trigger["entity_id"] = entity_registry.async_get(trigger["entity_id"]).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.TRIGGER, trigger + ) + assert capabilities == expected_capabilities + + async def test_if_fires_on_state_change( - hass: HomeAssistant, calls, enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off triggers firing.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -166,7 +196,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turned_on", }, "action": { @@ -190,7 +220,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "turned_off", }, "action": { @@ -214,7 +244,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.id, "type": "changed_states", }, "action": { @@ -237,37 +267,35 @@ async def test_if_fires_on_state_change( }, ) 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) + hass.states.async_set(entry.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", + f"turn_off device - {entry.entity_id} - on - off - None", + f"turn_on_or_off device - {entry.entity_id} - on - off - None", } - hass.states.async_set(ent1.entity_id, STATE_ON) + hass.states.async_set(entry.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", + f"turn_on device - {entry.entity_id} - off - on - None", + f"turn_on_or_off device - {entry.entity_id} - off - on - None", } -async def test_if_fires_on_state_change_with_for( - hass: HomeAssistant, calls, enable_custom_integrations: None +async def test_if_fires_on_state_change_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, ) -> None: - """Test for triggers firing with delay.""" - platform = getattr(hass.components, f"test.{DOMAIN}") + """Test for turn_on and turn_off triggers firing.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") - platform.init() - assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) - await hass.async_block_till_done() - - ent1, ent2, ent3 = platform.ENTITIES + hass.states.async_set(entry.entity_id, STATE_ON) assert await async_setup_component( hass, @@ -279,7 +307,62 @@ async def test_if_fires_on_state_change_with_for( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": ent1.entity_id, + "entity_id": entry.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", + ) + ) + }, + }, + }, + ] + }, + ) + await hass.async_block_till_done() + assert len(calls) == 0 + + hass.states.async_set(entry.entity_id, STATE_OFF) + await hass.async_block_till_done() + assert len(calls) == 1 + assert ( + calls[0].data["some"] + == f"turn_off device - {entry.entity_id} - on - off - None" + ) + + +async def test_if_fires_on_state_change_with_for( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls, + enable_custom_integrations: None, +) -> None: + """Test for triggers firing with delay.""" + entry = entity_registry.async_get_or_create(DOMAIN, "test", "5678") + + hass.states.async_set(entry.entity_id, STATE_ON) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.id, "type": "turned_off", "for": {"seconds": 5}, }, @@ -303,16 +386,16 @@ async def test_if_fires_on_state_change_with_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) + hass.states.async_set(entry.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 + assert ( + calls[0].data["some"] + == f"turn_off device - {entry.entity_id} - on - off - 0:00:05" ) diff --git a/tests/components/update/test_device_trigger.py b/tests/components/update/test_device_trigger.py index a9abed935fbb..b2d06a642a88 100644 --- a/tests/components/update/test_device_trigger.py +++ b/tests/components/update/test_device_trigger.py @@ -45,7 +45,7 @@ async def test_get_triggers( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", device_id=device_entry.id ) expected_triggers = [ @@ -54,7 +54,7 @@ async def test_get_triggers( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": False}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -88,7 +88,7 @@ async def test_get_triggers_hidden_auxiliary( config_entry_id=config_entry.entry_id, connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, ) - entity_registry.async_get_or_create( + entity_entry = entity_registry.async_get_or_create( DOMAIN, "test", "5678", @@ -102,7 +102,7 @@ async def test_get_triggers_hidden_auxiliary( "domain": DOMAIN, "type": trigger, "device_id": device_entry.id, - "entity_id": f"{DOMAIN}.test_5678", + "entity_id": entity_entry.id, "metadata": {"secondary": True}, } for trigger in ["changed_states", "turned_off", "turned_on"] @@ -143,8 +143,42 @@ async def test_get_trigger_capabilities( assert capabilities == expected_capabilities +async def test_get_trigger_capabilities_legacy( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test we get the expected capabilities from a update trigger.""" + config_entry = MockConfigEntry(domain="test", data={}) + config_entry.add_to_hass(hass) + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, "12:34:56:AB:CD:EF")}, + ) + entity_registry.async_get_or_create( + DOMAIN, "test", "5678", device_id=device_entry.id + ) + expected_capabilities = { + "extra_fields": [ + {"name": "for", "optional": True, "type": "positive_time_period_dict"} + ] + } + triggers = await async_get_device_automations( + hass, DeviceAutomationType.TRIGGER, device_entry.id + ) + for trigger in triggers: + trigger["entity_id"] = entity_registry.async_get(trigger["entity_id"]).entity_id + capabilities = await async_get_device_automation_capabilities( + hass, DeviceAutomationType.TRIGGER, trigger + ) + assert capabilities == expected_capabilities + + async def test_if_fires_on_state_change( - hass: HomeAssistant, calls: list[ServiceCall], enable_custom_integrations: None + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls: list[ServiceCall], + enable_custom_integrations: None, ) -> None: """Test for turn_on and turn_off triggers firing.""" platform = getattr(hass.components, f"test.{DOMAIN}") @@ -153,6 +187,8 @@ async def test_if_fires_on_state_change( assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) await hass.async_block_till_done() + entry = entity_registry.async_get("update.update_available") + assert await async_setup_component( hass, automation.DOMAIN, @@ -163,7 +199,7 @@ async def test_if_fires_on_state_change( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "update.update_available", + "entity_id": entry.id, "type": "turned_on", }, "action": { @@ -232,16 +268,21 @@ async def test_if_fires_on_state_change( ) -async def test_if_fires_on_state_change_with_for( - hass: HomeAssistant, calls: list[ServiceCall], enable_custom_integrations: None +async def test_if_fires_on_state_change_legacy( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls: list[ServiceCall], + enable_custom_integrations: None, ) -> None: - """Test for triggers firing with delay.""" + """Test for turn_on and turn_off triggers firing.""" platform = getattr(hass.components, f"test.{DOMAIN}") platform.init() assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) await hass.async_block_till_done() + entry = entity_registry.async_get("update.update_available") + assert await async_setup_component( hass, automation.DOMAIN, @@ -252,7 +293,69 @@ async def test_if_fires_on_state_change_with_for( "platform": "device", "domain": DOMAIN, "device_id": "", - "entity_id": "update.update_available", + "entity_id": entry.entity_id, + "type": "turned_off", + }, + "action": { + "service": "test.automation", + "data_template": { + "some": "no_update {{ trigger.%s }}" + % "}} - {{ trigger.".join( + ( + "platform", + "entity_id", + "from_state.state", + "to_state.state", + "for", + ) + ) + }, + }, + }, + ] + }, + ) + await hass.async_block_till_done() + state = hass.states.get("update.update_available") + assert state + assert state.state == STATE_ON + assert not calls + + hass.states.async_set("update.update_available", STATE_OFF) + await hass.async_block_till_done() + assert len(calls) == 1 + assert ( + calls[0].data["some"] + == "no_update device - update.update_available - on - off - None" + ) + + +async def test_if_fires_on_state_change_with_for( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + calls: list[ServiceCall], + enable_custom_integrations: None, +) -> None: + """Test for triggers firing with delay.""" + platform = getattr(hass.components, f"test.{DOMAIN}") + + platform.init() + assert await async_setup_component(hass, DOMAIN, {DOMAIN: {CONF_PLATFORM: "test"}}) + await hass.async_block_till_done() + + entry = entity_registry.async_get("update.update_available") + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": "", + "entity_id": entry.id, "type": "turned_off", "for": {"seconds": 5}, }, diff --git a/tests/components/wemo/test_device_trigger.py b/tests/components/wemo/test_device_trigger.py index e7a1c11e6c86..fd5db46e6c6d 100644 --- a/tests/components/wemo/test_device_trigger.py +++ b/tests/components/wemo/test_device_trigger.py @@ -71,7 +71,7 @@ async def test_get_triggers(hass: HomeAssistant, wemo_entity) -> None: { CONF_DEVICE_ID: wemo_entity.device_id, CONF_DOMAIN: Platform.SWITCH, - CONF_ENTITY_ID: wemo_entity.entity_id, + CONF_ENTITY_ID: wemo_entity.id, CONF_PLATFORM: "device", CONF_TYPE: "changed_states", "metadata": {"secondary": False}, @@ -79,7 +79,7 @@ async def test_get_triggers(hass: HomeAssistant, wemo_entity) -> None: { CONF_DEVICE_ID: wemo_entity.device_id, CONF_DOMAIN: Platform.SWITCH, - CONF_ENTITY_ID: wemo_entity.entity_id, + CONF_ENTITY_ID: wemo_entity.id, CONF_PLATFORM: "device", CONF_TYPE: "turned_off", "metadata": {"secondary": False}, @@ -87,7 +87,7 @@ async def test_get_triggers(hass: HomeAssistant, wemo_entity) -> None: { CONF_DEVICE_ID: wemo_entity.device_id, CONF_DOMAIN: Platform.SWITCH, - CONF_ENTITY_ID: wemo_entity.entity_id, + CONF_ENTITY_ID: wemo_entity.id, CONF_PLATFORM: "device", CONF_TYPE: "turned_on", "metadata": {"secondary": False}, diff --git a/tests/components/zha/test_device_action.py b/tests/components/zha/test_device_action.py index 5b6d7c94539e..32dbf2d88c0a 100644 --- a/tests/components/zha/test_device_action.py +++ b/tests/components/zha/test_device_action.py @@ -14,7 +14,7 @@ from homeassistant.components.device_automation import DeviceAutomationType from homeassistant.components.zha import DOMAIN from homeassistant.const import Platform from homeassistant.core import HomeAssistant -from homeassistant.helpers import device_registry as dr +from homeassistant.helpers import device_registry as dr, entity_registry as er from homeassistant.setup import async_setup_component from .conftest import SIG_EP_INPUT, SIG_EP_OUTPUT, SIG_EP_TYPE @@ -164,6 +164,8 @@ async def test_get_inovelli_actions(hass: HomeAssistant, device_inovelli) -> Non inovelli_reg_device = ha_device_registry.async_get_device( {(DOMAIN, inovelli_ieee_address)} ) + ha_entity_registry = er.async_get(hass) + inovelli_light = ha_entity_registry.async_get("light.inovelli_vzm31_sn_light") actions = await async_get_device_automations( hass, DeviceAutomationType.ACTION, inovelli_reg_device.id @@ -192,21 +194,21 @@ async def test_get_inovelli_actions(hass: HomeAssistant, device_inovelli) -> Non { "device_id": inovelli_reg_device.id, "domain": Platform.LIGHT, - "entity_id": "light.inovelli_vzm31_sn_light", + "entity_id": inovelli_light.id, "metadata": {"secondary": False}, "type": "turn_off", }, { "device_id": inovelli_reg_device.id, "domain": Platform.LIGHT, - "entity_id": "light.inovelli_vzm31_sn_light", + "entity_id": inovelli_light.id, "metadata": {"secondary": False}, "type": "turn_on", }, { "device_id": inovelli_reg_device.id, "domain": Platform.LIGHT, - "entity_id": "light.inovelli_vzm31_sn_light", + "entity_id": inovelli_light.id, "metadata": {"secondary": False}, "type": "toggle", },