From b26779a27a915f20901f28833a965626f9e1ed6d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 31 Mar 2021 14:56:04 +0200 Subject: [PATCH] Add id to automation triggers (#48464) --- .../components/arcam_fmj/device_trigger.py | 9 ++++++++- .../components/automation/__init__.py | 6 +++++- .../components/geo_location/trigger.py | 2 ++ .../components/homeassistant/triggers/event.py | 2 ++ .../homeassistant/triggers/homeassistant.py | 3 +++ .../homeassistant/triggers/numeric_state.py | 2 ++ .../components/homeassistant/triggers/state.py | 2 ++ .../components/homeassistant/triggers/time.py | 2 ++ .../homeassistant/triggers/time_pattern.py | 2 ++ .../homekit_controller/device_trigger.py | 5 ++++- .../components/kodi/device_trigger.py | 13 +++++++++---- homeassistant/components/litejet/trigger.py | 2 ++ homeassistant/components/mqtt/trigger.py | 2 ++ .../components/philips_js/device_trigger.py | 2 ++ homeassistant/components/sun/trigger.py | 2 ++ homeassistant/components/tag/trigger.py | 2 ++ homeassistant/components/template/trigger.py | 2 ++ homeassistant/components/webhook/trigger.py | 6 ++++-- homeassistant/components/zone/trigger.py | 2 ++ homeassistant/helpers/trigger.py | 3 ++- .../tests/test_device_trigger.py | 18 ++++++++++-------- .../arcam_fmj/test_device_trigger.py | 6 +++++- tests/components/geo_location/test_trigger.py | 3 ++- .../homeassistant/triggers/test_event.py | 6 +++++- .../triggers/test_homeassistant.py | 12 ++++++++++-- .../triggers/test_numeric_state.py | 6 +++++- .../homeassistant/triggers/test_state.py | 3 ++- .../homeassistant/triggers/test_time.py | 4 +++- .../triggers/test_time_pattern.py | 6 +++++- .../homekit_controller/test_device_trigger.py | 10 ++++++---- tests/components/kodi/test_device_trigger.py | 12 ++++++++---- tests/components/litejet/test_trigger.py | 9 ++++++++- tests/components/mqtt/test_trigger.py | 10 ++++++---- .../philips_js/test_device_trigger.py | 6 +++++- tests/components/sun/test_trigger.py | 6 +++++- tests/components/tag/test_trigger.py | 6 +++++- tests/components/template/test_trigger.py | 6 +++++- tests/components/trace/test_websocket_api.py | 15 +++++---------- tests/components/webhook/test_trigger.py | 6 +++++- tests/components/zone/test_trigger.py | 3 ++- 40 files changed, 168 insertions(+), 56 deletions(-) diff --git a/homeassistant/components/arcam_fmj/device_trigger.py b/homeassistant/components/arcam_fmj/device_trigger.py index be2b136bf97..4ae34abb2c2 100644 --- a/homeassistant/components/arcam_fmj/device_trigger.py +++ b/homeassistant/components/arcam_fmj/device_trigger.py @@ -56,6 +56,7 @@ async def async_attach_trigger( automation_info: dict, ) -> CALLBACK_TYPE: """Attach a trigger.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None job = HassJob(action) if config[CONF_TYPE] == "turn_on": @@ -66,7 +67,13 @@ async def async_attach_trigger( if event.data[ATTR_ENTITY_ID] == entity_id: hass.async_run_hass_job( job, - {"trigger": {**config, "description": f"{DOMAIN} - {entity_id}"}}, + { + "trigger": { + **config, + "description": f"{DOMAIN} - {entity_id}", + "id": trigger_id, + } + }, event.context, ) diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index f5bbc2b6e60..554b27fdb2f 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -455,7 +455,11 @@ class AutomationEntity(ToggleEntity, RestoreEntity): automation_trace.set_trigger_description(trigger_description) # Add initial variables as the trigger step - trace_element = TraceElement(variables, "trigger") + if "trigger" in variables and "id" in variables["trigger"]: + trigger_path = f"trigger/{variables['trigger']['id']}" + else: + trigger_path = "trigger" + trace_element = TraceElement(variables, trigger_path) trace_append_element(trace_element) if ( diff --git a/homeassistant/components/geo_location/trigger.py b/homeassistant/components/geo_location/trigger.py index 9ca8c86e150..3cdefccfeab 100644 --- a/homeassistant/components/geo_location/trigger.py +++ b/homeassistant/components/geo_location/trigger.py @@ -33,6 +33,7 @@ def source_match(state, source): async def async_attach_trigger(hass, config, action, automation_info): """Listen for state changes based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None source = config.get(CONF_SOURCE).lower() zone_entity_id = config.get(CONF_ZONE) trigger_event = config.get(CONF_EVENT) @@ -74,6 +75,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "zone": zone_state, "event": trigger_event, "description": f"geo_location - {source}", + "id": trigger_id, } }, event.context, diff --git a/homeassistant/components/homeassistant/triggers/event.py b/homeassistant/components/homeassistant/triggers/event.py index 2bc42c3d063..2e78a93315d 100644 --- a/homeassistant/components/homeassistant/triggers/event.py +++ b/homeassistant/components/homeassistant/triggers/event.py @@ -31,6 +31,7 @@ async def async_attach_trigger( hass, config, action, automation_info, *, platform_type="event" ): """Listen for events based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None variables = None if automation_info: variables = automation_info.get("variables") @@ -95,6 +96,7 @@ async def async_attach_trigger( "platform": platform_type, "event": event, "description": f"event '{event.event_type}'", + "id": trigger_id, } }, event.context, diff --git a/homeassistant/components/homeassistant/triggers/homeassistant.py b/homeassistant/components/homeassistant/triggers/homeassistant.py index 2f3ebfb82d9..2f3ae8e6ad2 100644 --- a/homeassistant/components/homeassistant/triggers/homeassistant.py +++ b/homeassistant/components/homeassistant/triggers/homeassistant.py @@ -19,6 +19,7 @@ TRIGGER_SCHEMA = vol.Schema( async def async_attach_trigger(hass, config, action, automation_info): """Listen for events based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None event = config.get(CONF_EVENT) job = HassJob(action) @@ -34,6 +35,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "platform": "homeassistant", "event": event, "description": "Home Assistant stopping", + "id": trigger_id, } }, event.context, @@ -51,6 +53,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "platform": "homeassistant", "event": event, "description": "Home Assistant starting", + "id": trigger_id, } }, ) diff --git a/homeassistant/components/homeassistant/triggers/numeric_state.py b/homeassistant/components/homeassistant/triggers/numeric_state.py index 59f16c41a36..05eed9ee27b 100644 --- a/homeassistant/components/homeassistant/triggers/numeric_state.py +++ b/homeassistant/components/homeassistant/triggers/numeric_state.py @@ -78,6 +78,7 @@ async def async_attach_trigger( attribute = config.get(CONF_ATTRIBUTE) job = HassJob(action) + trigger_id = automation_info.get("trigger_id") if automation_info else None _variables = {} if automation_info: _variables = automation_info.get("variables") or {} @@ -139,6 +140,7 @@ async def async_attach_trigger( "to_state": to_s, "for": time_delta if not time_delta else period[entity_id], "description": f"numeric state of {entity_id}", + "id": trigger_id, } }, to_s.context, diff --git a/homeassistant/components/homeassistant/triggers/state.py b/homeassistant/components/homeassistant/triggers/state.py index df8e3c419e1..69cddbfe126 100644 --- a/homeassistant/components/homeassistant/triggers/state.py +++ b/homeassistant/components/homeassistant/triggers/state.py @@ -87,6 +87,7 @@ async def async_attach_trigger( attribute = config.get(CONF_ATTRIBUTE) job = HassJob(action) + trigger_id = automation_info.get("trigger_id") if automation_info else None _variables = {} if automation_info: _variables = automation_info.get("variables") or {} @@ -140,6 +141,7 @@ async def async_attach_trigger( "for": time_delta if not time_delta else period[entity], "attribute": attribute, "description": f"state of {entity}", + "id": trigger_id, } }, event.context, diff --git a/homeassistant/components/homeassistant/triggers/time.py b/homeassistant/components/homeassistant/triggers/time.py index b0fced4d55d..69f01672078 100644 --- a/homeassistant/components/homeassistant/triggers/time.py +++ b/homeassistant/components/homeassistant/triggers/time.py @@ -39,6 +39,7 @@ TRIGGER_SCHEMA = vol.Schema( async def async_attach_trigger(hass, config, action, automation_info): """Listen for state changes based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None entities = {} removes = [] job = HassJob(action) @@ -54,6 +55,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "now": now, "description": description, "entity_id": entity_id, + "id": trigger_id, } }, ) diff --git a/homeassistant/components/homeassistant/triggers/time_pattern.py b/homeassistant/components/homeassistant/triggers/time_pattern.py index 3107d590d91..859f76b773b 100644 --- a/homeassistant/components/homeassistant/triggers/time_pattern.py +++ b/homeassistant/components/homeassistant/triggers/time_pattern.py @@ -57,6 +57,7 @@ TRIGGER_SCHEMA = vol.All( async def async_attach_trigger(hass, config, action, automation_info): """Listen for state changes based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None hours = config.get(CONF_HOURS) minutes = config.get(CONF_MINUTES) seconds = config.get(CONF_SECONDS) @@ -78,6 +79,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "platform": "time_pattern", "now": now, "description": "time pattern", + "id": trigger_id, } }, ) diff --git a/homeassistant/components/homekit_controller/device_trigger.py b/homeassistant/components/homekit_controller/device_trigger.py index 59cc32c0b1b..c9cd771edf6 100644 --- a/homeassistant/components/homekit_controller/device_trigger.py +++ b/homeassistant/components/homekit_controller/device_trigger.py @@ -75,11 +75,14 @@ class TriggerSource: automation_info: dict, ) -> CALLBACK_TYPE: """Attach a trigger.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None def event_handler(char): if config[CONF_SUBTYPE] != HK_TO_HA_INPUT_EVENT_VALUES[char["value"]]: return - self._hass.async_create_task(action({"trigger": config})) + self._hass.async_create_task( + action({"trigger": {**config, "id": trigger_id}}) + ) trigger = self._triggers[config[CONF_TYPE], config[CONF_SUBTYPE]] iid = trigger["characteristic"] diff --git a/homeassistant/components/kodi/device_trigger.py b/homeassistant/components/kodi/device_trigger.py index c59fe53be14..b8653290c0d 100644 --- a/homeassistant/components/kodi/device_trigger.py +++ b/homeassistant/components/kodi/device_trigger.py @@ -61,8 +61,13 @@ async def async_get_triggers(hass: HomeAssistant, device_id: str) -> list[dict]: @callback def _attach_trigger( - hass: HomeAssistant, config: ConfigType, action: AutomationActionType, event_type + hass: HomeAssistant, + config: ConfigType, + action: AutomationActionType, + event_type, + automation_info: dict, ): + trigger_id = automation_info.get("trigger_id") if automation_info else None job = HassJob(action) @callback @@ -70,7 +75,7 @@ def _attach_trigger( if event.data[ATTR_ENTITY_ID] == config[CONF_ENTITY_ID]: hass.async_run_hass_job( job, - {"trigger": {**config, "description": event_type}}, + {"trigger": {**config, "description": event_type, "id": trigger_id}}, event.context, ) @@ -85,9 +90,9 @@ async def async_attach_trigger( ) -> CALLBACK_TYPE: """Attach a trigger.""" if config[CONF_TYPE] == "turn_on": - return _attach_trigger(hass, config, action, EVENT_TURN_ON) + return _attach_trigger(hass, config, action, EVENT_TURN_ON, automation_info) if config[CONF_TYPE] == "turn_off": - return _attach_trigger(hass, config, action, EVENT_TURN_OFF) + return _attach_trigger(hass, config, action, EVENT_TURN_OFF, automation_info) return lambda: None diff --git a/homeassistant/components/litejet/trigger.py b/homeassistant/components/litejet/trigger.py index 71841d9c4fd..6800282766b 100644 --- a/homeassistant/components/litejet/trigger.py +++ b/homeassistant/components/litejet/trigger.py @@ -31,6 +31,7 @@ TRIGGER_SCHEMA = vol.Schema( async def async_attach_trigger(hass, config, action, automation_info): """Listen for events based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None number = config.get(CONF_NUMBER) held_more_than = config.get(CONF_HELD_MORE_THAN) held_less_than = config.get(CONF_HELD_LESS_THAN) @@ -50,6 +51,7 @@ async def async_attach_trigger(hass, config, action, automation_info): CONF_HELD_MORE_THAN: held_more_than, CONF_HELD_LESS_THAN: held_less_than, "description": f"litejet switch #{number}", + "id": trigger_id, } }, ) diff --git a/homeassistant/components/mqtt/trigger.py b/homeassistant/components/mqtt/trigger.py index 856106e029d..34c47aec791 100644 --- a/homeassistant/components/mqtt/trigger.py +++ b/homeassistant/components/mqtt/trigger.py @@ -37,6 +37,7 @@ _LOGGER = logging.getLogger(__name__) async def async_attach_trigger(hass, config, action, automation_info): """Listen for state changes based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None topic = config[CONF_TOPIC] wanted_payload = config.get(CONF_PAYLOAD) value_template = config.get(CONF_VALUE_TEMPLATE) @@ -78,6 +79,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "payload": mqttmsg.payload, "qos": mqttmsg.qos, "description": f"mqtt topic {mqttmsg.topic}", + "id": trigger_id, } with suppress(ValueError): diff --git a/homeassistant/components/philips_js/device_trigger.py b/homeassistant/components/philips_js/device_trigger.py index 615d758735e..77782fc641c 100644 --- a/homeassistant/components/philips_js/device_trigger.py +++ b/homeassistant/components/philips_js/device_trigger.py @@ -45,6 +45,7 @@ async def async_attach_trigger( automation_info: dict, ) -> CALLBACK_TYPE | None: """Attach a trigger.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None registry: DeviceRegistry = await async_get_registry(hass) if config[CONF_TYPE] == TRIGGER_TYPE_TURN_ON: variables = { @@ -53,6 +54,7 @@ async def async_attach_trigger( "domain": DOMAIN, "device_id": config[CONF_DEVICE_ID], "description": f"philips_js '{config[CONF_TYPE]}' event", + "id": trigger_id, } } diff --git a/homeassistant/components/sun/trigger.py b/homeassistant/components/sun/trigger.py index 779d3078f13..d2b6f6de560 100644 --- a/homeassistant/components/sun/trigger.py +++ b/homeassistant/components/sun/trigger.py @@ -26,6 +26,7 @@ TRIGGER_SCHEMA = vol.Schema( async def async_attach_trigger(hass, config, action, automation_info): """Listen for events based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None event = config.get(CONF_EVENT) offset = config.get(CONF_OFFSET) description = event @@ -44,6 +45,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "event": event, "offset": offset, "description": description, + "id": trigger_id, } }, ) diff --git a/homeassistant/components/tag/trigger.py b/homeassistant/components/tag/trigger.py index 9803bd56afe..4f6dd89a252 100644 --- a/homeassistant/components/tag/trigger.py +++ b/homeassistant/components/tag/trigger.py @@ -18,6 +18,7 @@ TRIGGER_SCHEMA = vol.Schema( async def async_attach_trigger(hass, config, action, automation_info): """Listen for tag_scanned events based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None tag_ids = set(config[TAG_ID]) device_ids = set(config[DEVICE_ID]) if DEVICE_ID in config else None @@ -37,6 +38,7 @@ async def async_attach_trigger(hass, config, action, automation_info): "platform": DOMAIN, "event": event, "description": "Tag scanned", + "id": trigger_id, } }, event.context, diff --git a/homeassistant/components/template/trigger.py b/homeassistant/components/template/trigger.py index 1f378c59335..e631950a74a 100644 --- a/homeassistant/components/template/trigger.py +++ b/homeassistant/components/template/trigger.py @@ -31,6 +31,7 @@ async def async_attach_trigger( hass, config, action, automation_info, *, platform_type="template" ): """Listen for state changes based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None value_template = config.get(CONF_VALUE_TEMPLATE) value_template.hass = hass time_delta = config.get(CONF_FOR) @@ -100,6 +101,7 @@ async def async_attach_trigger( trigger_variables = { "for": time_delta, "description": description, + "id": trigger_id, } @callback diff --git a/homeassistant/components/webhook/trigger.py b/homeassistant/components/webhook/trigger.py index 81c4c2813cd..a82dd0251c9 100644 --- a/homeassistant/components/webhook/trigger.py +++ b/homeassistant/components/webhook/trigger.py @@ -17,7 +17,7 @@ TRIGGER_SCHEMA = vol.Schema( ) -async def _handle_webhook(job, hass, webhook_id, request): +async def _handle_webhook(job, trigger_id, hass, webhook_id, request): """Handle incoming webhook.""" result = {"platform": "webhook", "webhook_id": webhook_id} @@ -28,18 +28,20 @@ async def _handle_webhook(job, hass, webhook_id, request): result["query"] = request.query result["description"] = "webhook" + result["id"] = trigger_id hass.async_run_hass_job(job, {"trigger": result}) async def async_attach_trigger(hass, config, action, automation_info): """Trigger based on incoming webhooks.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None webhook_id = config.get(CONF_WEBHOOK_ID) job = HassJob(action) hass.components.webhook.async_register( automation_info["domain"], automation_info["name"], webhook_id, - partial(_handle_webhook, job), + partial(_handle_webhook, job, trigger_id), ) @callback diff --git a/homeassistant/components/zone/trigger.py b/homeassistant/components/zone/trigger.py index a5f89a7515d..db5ca2cf01b 100644 --- a/homeassistant/components/zone/trigger.py +++ b/homeassistant/components/zone/trigger.py @@ -37,6 +37,7 @@ async def async_attach_trigger( hass, config, action, automation_info, *, platform_type: str = "zone" ) -> CALLBACK_TYPE: """Listen for state changes based on configuration.""" + trigger_id = automation_info.get("trigger_id") if automation_info else None entity_id = config.get(CONF_ENTITY_ID) zone_entity_id = config.get(CONF_ZONE) event = config.get(CONF_EVENT) @@ -80,6 +81,7 @@ async def async_attach_trigger( "zone": zone_state, "event": event, "description": description, + "id": trigger_id, } }, to_s.context, diff --git a/homeassistant/helpers/trigger.py b/homeassistant/helpers/trigger.py index f40a924ae1b..045c56d964c 100644 --- a/homeassistant/helpers/trigger.py +++ b/homeassistant/helpers/trigger.py @@ -72,8 +72,9 @@ async def async_initialize_triggers( } triggers = [] - for conf in trigger_config: + for idx, conf in enumerate(trigger_config): platform = await _async_get_trigger_platform(hass, conf) + info = {**info, "trigger_id": f"{idx}"} triggers.append(platform.async_attach_trigger(hass, conf, action, info)) attach_results = await asyncio.gather(*triggers, return_exceptions=True) diff --git a/script/scaffold/templates/device_trigger/tests/test_device_trigger.py b/script/scaffold/templates/device_trigger/tests/test_device_trigger.py index 23daaf8dadd..55343abadb1 100644 --- a/script/scaffold/templates/device_trigger/tests/test_device_trigger.py +++ b/script/scaffold/templates/device_trigger/tests/test_device_trigger.py @@ -87,7 +87,8 @@ async def test_if_fires_on_state_change(hass, calls): "some": ( "turn_on - {{ trigger.platform}} - " "{{ trigger.entity_id}} - {{ trigger.from_state.state}} - " - "{{ trigger.to_state.state}} - {{ trigger.for }}" + "{{ trigger.to_state.state}} - {{ trigger.for }} - " + "{{ trigger.id}}" ) }, }, @@ -106,7 +107,8 @@ async def test_if_fires_on_state_change(hass, calls): "some": ( "turn_off - {{ trigger.platform}} - " "{{ trigger.entity_id}} - {{ trigger.from_state.state}} - " - "{{ trigger.to_state.state}} - {{ trigger.for }}" + "{{ trigger.to_state.state}} - {{ trigger.for }} - " + "{{ trigger.id}}" ) }, }, @@ -119,14 +121,14 @@ async def test_if_fires_on_state_change(hass, calls): hass.states.async_set("NEW_DOMAIN.entity", STATE_ON) await hass.async_block_till_done() assert len(calls) == 1 - assert calls[0].data["some"] == "turn_on - device - {} - off - on - None".format( - "NEW_DOMAIN.entity" - ) + assert calls[0].data[ + "some" + ] == "turn_on - device - {} - off - on - None - 0".format("NEW_DOMAIN.entity") # Fake that the entity is turning off. hass.states.async_set("NEW_DOMAIN.entity", STATE_OFF) await hass.async_block_till_done() assert len(calls) == 2 - assert calls[1].data["some"] == "turn_off - device - {} - on - off - None".format( - "NEW_DOMAIN.entity" - ) + assert calls[1].data[ + "some" + ] == "turn_off - device - {} - on - off - None - 0".format("NEW_DOMAIN.entity") diff --git a/tests/components/arcam_fmj/test_device_trigger.py b/tests/components/arcam_fmj/test_device_trigger.py index ff3cf55ecd1..d5ab820ce46 100644 --- a/tests/components/arcam_fmj/test_device_trigger.py +++ b/tests/components/arcam_fmj/test_device_trigger.py @@ -82,7 +82,10 @@ async def test_if_fires_on_turn_on_request(hass, calls, player_setup, state): }, "action": { "service": "test.automation", - "data_template": {"some": "{{ trigger.entity_id }}"}, + "data_template": { + "some": "{{ trigger.entity_id }}", + "id": "{{ trigger.id }}", + }, }, } ] @@ -99,3 +102,4 @@ async def test_if_fires_on_turn_on_request(hass, calls, player_setup, state): await hass.async_block_till_done() assert len(calls) == 1 assert calls[0].data["some"] == player_setup + assert calls[0].data["id"] == 0 diff --git a/tests/components/geo_location/test_trigger.py b/tests/components/geo_location/test_trigger.py index c547cb61230..e40b134e657 100644 --- a/tests/components/geo_location/test_trigger.py +++ b/tests/components/geo_location/test_trigger.py @@ -68,6 +68,7 @@ async def test_if_fires_on_zone_enter(hass, calls): "from_state.state", "to_state.state", "zone.name", + "id", ) ) }, @@ -88,7 +89,7 @@ async def test_if_fires_on_zone_enter(hass, calls): assert calls[0].context.parent_id == context.id assert ( calls[0].data["some"] - == "geo_location - geo_location.entity - hello - hello - test" + == "geo_location - geo_location.entity - hello - hello - test - 0" ) # Set out of zone again so we can trigger call diff --git a/tests/components/homeassistant/triggers/test_event.py b/tests/components/homeassistant/triggers/test_event.py index f1ff3564065..8ca7caaa0a5 100644 --- a/tests/components/homeassistant/triggers/test_event.py +++ b/tests/components/homeassistant/triggers/test_event.py @@ -37,7 +37,10 @@ async def test_if_fires_on_event(hass, calls): { automation.DOMAIN: { "trigger": {"platform": "event", "event_type": "test_event"}, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } }, ) @@ -57,6 +60,7 @@ async def test_if_fires_on_event(hass, calls): hass.bus.async_fire("test_event") await hass.async_block_till_done() assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_if_fires_on_templated_event(hass, calls): diff --git a/tests/components/homeassistant/triggers/test_homeassistant.py b/tests/components/homeassistant/triggers/test_homeassistant.py index 7ff7e566db0..231b81e3862 100644 --- a/tests/components/homeassistant/triggers/test_homeassistant.py +++ b/tests/components/homeassistant/triggers/test_homeassistant.py @@ -16,7 +16,10 @@ async def test_if_fires_on_hass_start(hass): automation.DOMAIN: { "alias": "hello", "trigger": {"platform": "homeassistant", "event": "start"}, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } } @@ -39,6 +42,7 @@ async def test_if_fires_on_hass_start(hass): assert automation.is_on(hass, "automation.hello") assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_if_fires_on_hass_shutdown(hass): @@ -53,7 +57,10 @@ async def test_if_fires_on_hass_shutdown(hass): automation.DOMAIN: { "alias": "hello", "trigger": {"platform": "homeassistant", "event": "shutdown"}, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } }, ) @@ -68,3 +75,4 @@ async def test_if_fires_on_hass_shutdown(hass): with patch.object(hass.loop, "stop"): await hass.async_stop() assert len(calls) == 1 + assert calls[0].data["id"] == 0 diff --git a/tests/components/homeassistant/triggers/test_numeric_state.py b/tests/components/homeassistant/triggers/test_numeric_state.py index 9eb9ac79a94..38372d09825 100644 --- a/tests/components/homeassistant/triggers/test_numeric_state.py +++ b/tests/components/homeassistant/triggers/test_numeric_state.py @@ -92,7 +92,10 @@ async def test_if_fires_on_entity_change_below(hass, calls, below): "entity_id": "test.entity", "below": below, }, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } }, ) @@ -114,6 +117,7 @@ async def test_if_fires_on_entity_change_below(hass, calls, below): hass.states.async_set("test.entity", 9) await hass.async_block_till_done() assert len(calls) == 1 + assert calls[0].data["id"] == 0 @pytest.mark.parametrize("below", (10, "input_number.value_10")) diff --git a/tests/components/homeassistant/triggers/test_state.py b/tests/components/homeassistant/triggers/test_state.py index 14120fe94df..8671e40d293 100644 --- a/tests/components/homeassistant/triggers/test_state.py +++ b/tests/components/homeassistant/triggers/test_state.py @@ -55,6 +55,7 @@ async def test_if_fires_on_entity_change(hass, calls): "from_state.state", "to_state.state", "for", + "id", ) ) }, @@ -68,7 +69,7 @@ async def test_if_fires_on_entity_change(hass, calls): await hass.async_block_till_done() assert len(calls) == 1 assert calls[0].context.parent_id == context.id - assert calls[0].data["some"] == "state - test.entity - hello - world - None" + assert calls[0].data["some"] == "state - test.entity - hello - world - None - 0" await hass.services.async_call( automation.DOMAIN, diff --git a/tests/components/homeassistant/triggers/test_time.py b/tests/components/homeassistant/triggers/test_time.py index 5805aa07fe3..499fcf8611e 100644 --- a/tests/components/homeassistant/triggers/test_time.py +++ b/tests/components/homeassistant/triggers/test_time.py @@ -51,7 +51,8 @@ async def test_if_fires_using_at(hass, calls): "action": { "service": "test.automation", "data_template": { - "some": "{{ trigger.platform }} - {{ trigger.now.hour }}" + "some": "{{ trigger.platform }} - {{ trigger.now.hour }}", + "id": "{{ trigger.id}}", }, }, } @@ -64,6 +65,7 @@ async def test_if_fires_using_at(hass, calls): assert len(calls) == 1 assert calls[0].data["some"] == "time - 5" + assert calls[0].data["id"] == 0 @pytest.mark.parametrize( diff --git a/tests/components/homeassistant/triggers/test_time_pattern.py b/tests/components/homeassistant/triggers/test_time_pattern.py index 147bb388fed..1018bf7ab14 100644 --- a/tests/components/homeassistant/triggers/test_time_pattern.py +++ b/tests/components/homeassistant/triggers/test_time_pattern.py @@ -46,7 +46,10 @@ async def test_if_fires_when_hour_matches(hass, calls): "minutes": "*", "seconds": "*", }, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } }, ) @@ -65,6 +68,7 @@ async def test_if_fires_when_hour_matches(hass, calls): async_fire_time_changed(hass, now.replace(year=now.year + 1, hour=0)) await hass.async_block_till_done() assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_if_fires_when_minute_matches(hass, calls): diff --git a/tests/components/homekit_controller/test_device_trigger.py b/tests/components/homekit_controller/test_device_trigger.py index cbb8da36bc2..7c02c1a6456 100644 --- a/tests/components/homekit_controller/test_device_trigger.py +++ b/tests/components/homekit_controller/test_device_trigger.py @@ -214,7 +214,8 @@ async def test_handle_events(hass, utcnow, calls): "data_template": { "some": ( "{{ trigger.platform}} - " - "{{ trigger.type }} - {{ trigger.subtype }}" + "{{ trigger.type }} - {{ trigger.subtype }} - " + "{{ trigger.id }}" ) }, }, @@ -233,7 +234,8 @@ async def test_handle_events(hass, utcnow, calls): "data_template": { "some": ( "{{ trigger.platform}} - " - "{{ trigger.type }} - {{ trigger.subtype }}" + "{{ trigger.type }} - {{ trigger.subtype }} - " + "{{ trigger.id }}" ) }, }, @@ -249,7 +251,7 @@ async def test_handle_events(hass, utcnow, calls): await hass.async_block_till_done() assert len(calls) == 1 - assert calls[0].data["some"] == "device - button1 - single_press" + assert calls[0].data["some"] == "device - button1 - single_press - 0" # Make sure automation doesn't trigger for long press helper.pairing.testing.update_named_service( @@ -274,7 +276,7 @@ async def test_handle_events(hass, utcnow, calls): await hass.async_block_till_done() assert len(calls) == 2 - assert calls[1].data["some"] == "device - button2 - long_press" + assert calls[1].data["some"] == "device - button2 - long_press - 0" # Turn the automations off await hass.services.async_call( diff --git a/tests/components/kodi/test_device_trigger.py b/tests/components/kodi/test_device_trigger.py index 1edf7da6604..462d2381cec 100644 --- a/tests/components/kodi/test_device_trigger.py +++ b/tests/components/kodi/test_device_trigger.py @@ -95,7 +95,9 @@ async def test_if_fires_on_state_change(hass, calls, kodi_media_player): "action": { "service": "test.automation", "data_template": { - "some": ("turn_on - {{ trigger.entity_id }}") + "some": ( + "turn_on - {{ trigger.entity_id }} - {{ trigger.id}}" + ) }, }, }, @@ -110,7 +112,9 @@ async def test_if_fires_on_state_change(hass, calls, kodi_media_player): "action": { "service": "test.automation", "data_template": { - "some": ("turn_off - {{ trigger.entity_id }}") + "some": ( + "turn_off - {{ trigger.entity_id }} - {{ trigger.id}}" + ) }, }, }, @@ -128,7 +132,7 @@ async def test_if_fires_on_state_change(hass, calls, kodi_media_player): await hass.async_block_till_done() assert len(calls) == 1 - assert calls[0].data["some"] == f"turn_on - {kodi_media_player}" + assert calls[0].data["some"] == f"turn_on - {kodi_media_player} - 0" await hass.services.async_call( MP_DOMAIN, @@ -139,4 +143,4 @@ async def test_if_fires_on_state_change(hass, calls, kodi_media_player): await hass.async_block_till_done() assert len(calls) == 2 - assert calls[1].data["some"] == f"turn_off - {kodi_media_player}" + assert calls[1].data["some"] == f"turn_off - {kodi_media_player} - 0" diff --git a/tests/components/litejet/test_trigger.py b/tests/components/litejet/test_trigger.py index 50d7fb40715..a06d490cea6 100644 --- a/tests/components/litejet/test_trigger.py +++ b/tests/components/litejet/test_trigger.py @@ -82,7 +82,10 @@ async def setup_automation(hass, trigger): { "alias": "My Test", "trigger": trigger, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } ] }, @@ -100,6 +103,7 @@ async def test_simple(hass, calls, mock_litejet): await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_held_more_than_short(hass, calls, mock_litejet): @@ -134,6 +138,7 @@ async def test_held_more_than_long(hass, calls, mock_litejet): assert len(calls) == 0 await simulate_time(hass, mock_litejet, timedelta(seconds=0.3)) assert len(calls) == 1 + assert calls[0].data["id"] == 0 await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 @@ -154,6 +159,7 @@ async def test_held_less_than_short(hass, calls, mock_litejet): assert len(calls) == 0 await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_held_less_than_long(hass, calls, mock_litejet): @@ -211,6 +217,7 @@ async def test_held_in_range_just_right(hass, calls, mock_litejet): assert len(calls) == 0 await simulate_release(hass, mock_litejet, ENTITY_OTHER_SWITCH_NUMBER) assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_held_in_range_long(hass, calls, mock_litejet): diff --git a/tests/components/mqtt/test_trigger.py b/tests/components/mqtt/test_trigger.py index 332ed9a04d2..c2c77dcddd8 100644 --- a/tests/components/mqtt/test_trigger.py +++ b/tests/components/mqtt/test_trigger.py @@ -34,9 +34,9 @@ async def test_if_fires_on_topic_match(hass, calls): "action": { "service": "test.automation", "data_template": { - "some": "{{ trigger.platform }} - {{ trigger.topic }}" - " - {{ trigger.payload }} - " - "{{ trigger.payload_json.hello }}" + "some": "{{ trigger.platform }} - {{ trigger.topic }} - " + "{{ trigger.payload }} - {{ trigger.payload_json.hello }} - " + "{{ trigger.id }}" }, }, } @@ -46,7 +46,9 @@ async def test_if_fires_on_topic_match(hass, calls): async_fire_mqtt_message(hass, "test-topic", '{ "hello": "world" }') await hass.async_block_till_done() assert len(calls) == 1 - assert calls[0].data["some"] == 'mqtt - test-topic - { "hello": "world" } - world' + assert ( + calls[0].data["some"] == 'mqtt - test-topic - { "hello": "world" } - world - 0' + ) await hass.services.async_call( automation.DOMAIN, diff --git a/tests/components/philips_js/test_device_trigger.py b/tests/components/philips_js/test_device_trigger.py index e0ee10c6abb..936dd65f115 100644 --- a/tests/components/philips_js/test_device_trigger.py +++ b/tests/components/philips_js/test_device_trigger.py @@ -54,7 +54,10 @@ async def test_if_fires_on_turn_on_request( }, "action": { "service": "test.automation", - "data_template": {"some": "{{ trigger.device_id }}"}, + "data_template": { + "some": "{{ trigger.device_id }}", + "id": "{{ trigger.id}}", + }, }, } ] @@ -71,3 +74,4 @@ async def test_if_fires_on_turn_on_request( await hass.async_block_till_done() assert len(calls) == 1 assert calls[0].data["some"] == mock_device.id + assert calls[0].data["id"] == 0 diff --git a/tests/components/sun/test_trigger.py b/tests/components/sun/test_trigger.py index fd01daac5b7..3ed91d1d896 100644 --- a/tests/components/sun/test_trigger.py +++ b/tests/components/sun/test_trigger.py @@ -56,7 +56,10 @@ async def test_sunset_trigger(hass, calls, legacy_patchable_time): { automation.DOMAIN: { "trigger": {"platform": "sun", "event": SUN_EVENT_SUNSET}, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } }, ) @@ -83,6 +86,7 @@ async def test_sunset_trigger(hass, calls, legacy_patchable_time): async_fire_time_changed(hass, trigger_time) await hass.async_block_till_done() assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_sunrise_trigger(hass, calls, legacy_patchable_time): diff --git a/tests/components/tag/test_trigger.py b/tests/components/tag/test_trigger.py index 5563b5644a4..3976c3193d1 100644 --- a/tests/components/tag/test_trigger.py +++ b/tests/components/tag/test_trigger.py @@ -50,7 +50,10 @@ async def test_triggers(hass, tag_setup, calls): "trigger": {"platform": DOMAIN, TAG_ID: "abc123"}, "action": { "service": "test.automation", - "data": {"message": "service called"}, + "data_template": { + "message": "service called", + "id": "{{ trigger.id}}", + }, }, } ] @@ -64,6 +67,7 @@ async def test_triggers(hass, tag_setup, calls): assert len(calls) == 1 assert calls[0].data["message"] == "service called" + assert calls[0].data["id"] == 0 await hass.services.async_call( automation.DOMAIN, diff --git a/tests/components/template/test_trigger.py b/tests/components/template/test_trigger.py index c85600571e8..e9634248c72 100644 --- a/tests/components/template/test_trigger.py +++ b/tests/components/template/test_trigger.py @@ -45,7 +45,10 @@ async def test_if_fires_on_change_bool(hass, calls): "platform": "template", "value_template": '{{ states.test.entity.state == "world" and true }}', }, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": {"id": "{{ trigger.id}}"}, + }, } }, ) @@ -66,6 +69,7 @@ async def test_if_fires_on_change_bool(hass, calls): hass.states.async_set("test.entity", "planet") await hass.async_block_till_done() assert len(calls) == 1 + assert calls[0].data["id"] == 0 async def test_if_fires_on_change_str(hass, calls): diff --git a/tests/components/trace/test_websocket_api.py b/tests/components/trace/test_websocket_api.py index 1ff86060eec..c4b4f476fcc 100644 --- a/tests/components/trace/test_websocket_api.py +++ b/tests/components/trace/test_websocket_api.py @@ -112,7 +112,7 @@ async def test_get_trace(hass, hass_ws_client, domain, prefix): trace = response["result"] if domain == "automation": assert len(trace["trace"]) == 2 - assert set(trace["trace"]) == {"trigger", f"{prefix}/0"} + assert set(trace["trace"]) == {"trigger/0", f"{prefix}/0"} else: assert len(trace["trace"]) == 1 assert set(trace["trace"]) == {f"{prefix}/0"} @@ -163,7 +163,7 @@ async def test_get_trace(hass, hass_ws_client, domain, prefix): trace = response["result"] if domain == "automation": assert len(trace["trace"]) == 3 - assert set(trace["trace"]) == {"trigger", "condition/0", f"{prefix}/0"} + assert set(trace["trace"]) == {"trigger/0", "condition/0", f"{prefix}/0"} else: assert len(trace["trace"]) == 1 assert set(trace["trace"]) == {f"{prefix}/0"} @@ -217,12 +217,7 @@ async def test_get_trace(hass, hass_ws_client, domain, prefix): response = await client.receive_json() assert response["success"] trace = response["result"] - if domain == "automation": - assert len(trace["trace"]) == 2 - assert set(trace["trace"]) == {"trigger", "condition/0"} - else: - assert len(trace["trace"]) == 1 - assert set(trace["trace"]) == {f"{prefix}/0"} + assert set(trace["trace"]) == {"trigger/1", "condition/0"} assert len(trace["trace"]["condition/0"]) == 1 assert trace["trace"]["condition/0"][0]["result"] == {"result": False} assert trace["config"] == moon_config @@ -261,7 +256,7 @@ async def test_get_trace(hass, hass_ws_client, domain, prefix): assert response["success"] trace = response["result"] assert len(trace["trace"]) == 3 - assert set(trace["trace"]) == {"trigger", "condition/0", f"{prefix}/0"} + assert set(trace["trace"]) == {"trigger/0", "condition/0", f"{prefix}/0"} assert len(trace["trace"][f"{prefix}/0"]) == 1 assert "error" not in trace["trace"][f"{prefix}/0"][0] assert trace["trace"][f"{prefix}/0"][0]["result"] == moon_action @@ -591,7 +586,7 @@ async def test_nested_traces(hass, hass_ws_client, domain, prefix): trace = response["result"] if domain == "automation": assert len(trace["trace"]) == 2 - assert set(trace["trace"]) == {"trigger", f"{prefix}/0"} + assert set(trace["trace"]) == {"trigger/0", f"{prefix}/0"} else: assert len(trace["trace"]) == 1 assert set(trace["trace"]) == {f"{prefix}/0"} diff --git a/tests/components/webhook/test_trigger.py b/tests/components/webhook/test_trigger.py index 4909c668dfe..ae70460de5d 100644 --- a/tests/components/webhook/test_trigger.py +++ b/tests/components/webhook/test_trigger.py @@ -36,7 +36,10 @@ async def test_webhook_json(hass, aiohttp_client): "trigger": {"platform": "webhook", "webhook_id": "json_webhook"}, "action": { "event": "test_success", - "event_data_template": {"hello": "yo {{ trigger.json.hello }}"}, + "event_data_template": { + "hello": "yo {{ trigger.json.hello }}", + "id": "{{ trigger.id}}", + }, }, } }, @@ -50,6 +53,7 @@ async def test_webhook_json(hass, aiohttp_client): assert len(events) == 1 assert events[0].data["hello"] == "yo world" + assert events[0].data["id"] == 0 async def test_webhook_post(hass, aiohttp_client): diff --git a/tests/components/zone/test_trigger.py b/tests/components/zone/test_trigger.py index 2b0d2f27afd..978603ae242 100644 --- a/tests/components/zone/test_trigger.py +++ b/tests/components/zone/test_trigger.py @@ -66,6 +66,7 @@ async def test_if_fires_on_zone_enter(hass, calls): "from_state.state", "to_state.state", "zone.name", + "id", ) ) }, @@ -84,7 +85,7 @@ async def test_if_fires_on_zone_enter(hass, calls): assert len(calls) == 1 assert calls[0].context.parent_id == context.id - assert calls[0].data["some"] == "zone - test.entity - hello - hello - test" + assert calls[0].data["some"] == "zone - test.entity - hello - hello - test - 0" # Set out of zone again so we can trigger call hass.states.async_set(