diff --git a/homeassistant/components/automation/__init__.py b/homeassistant/components/automation/__init__.py index 6caa53dff79..36b7f1688f8 100644 --- a/homeassistant/components/automation/__init__.py +++ b/homeassistant/components/automation/__init__.py @@ -273,6 +273,7 @@ class AutomationEntity(ToggleEntity, RestoreEntity): variables, trigger_variables, raw_config, + blueprint_inputs, ): """Initialize an automation entity.""" self._id = automation_id @@ -290,6 +291,7 @@ class AutomationEntity(ToggleEntity, RestoreEntity): self._variables: ScriptVariables = variables self._trigger_variables: ScriptVariables = trigger_variables self._raw_config = raw_config + self._blueprint_inputs = blueprint_inputs @property def name(self): @@ -437,7 +439,11 @@ class AutomationEntity(ToggleEntity, RestoreEntity): trigger_context = Context(parent_id=parent_id) with trace_automation( - self.hass, self.unique_id, self._raw_config, trigger_context + self.hass, + self.unique_id, + self._raw_config, + self._blueprint_inputs, + trigger_context, ) as automation_trace: if self._variables: try: @@ -603,10 +609,12 @@ async def _async_process_config( ] for list_no, config_block in enumerate(conf): + raw_blueprint_inputs = None raw_config = None if isinstance(config_block, blueprint.BlueprintInputs): # type: ignore blueprints_used = True blueprint_inputs = config_block + raw_blueprint_inputs = blueprint_inputs.config_with_inputs try: raw_config = blueprint_inputs.async_substitute() @@ -675,6 +683,7 @@ async def _async_process_config( variables, config_block.get(CONF_TRIGGER_VARIABLES), raw_config, + raw_blueprint_inputs, ) entities.append(entity) diff --git a/homeassistant/components/automation/trace.py b/homeassistant/components/automation/trace.py index 0b335f7d87f..cfdbe02056b 100644 --- a/homeassistant/components/automation/trace.py +++ b/homeassistant/components/automation/trace.py @@ -18,11 +18,12 @@ class AutomationTrace(ActionTrace): self, item_id: str, config: dict[str, Any], + blueprint_inputs: dict[str, Any], context: Context, ): """Container for automation trace.""" key = ("automation", item_id) - super().__init__(key, config, context) + super().__init__(key, config, blueprint_inputs, context) self._trigger_description: str | None = None def set_trigger_description(self, trigger: str) -> None: @@ -37,9 +38,9 @@ class AutomationTrace(ActionTrace): @contextmanager -def trace_automation(hass, automation_id, config, context): +def trace_automation(hass, automation_id, config, blueprint_inputs, context): """Trace action execution of automation with automation_id.""" - trace = AutomationTrace(automation_id, config, context) + trace = AutomationTrace(automation_id, config, blueprint_inputs, context) async_store_trace(hass, trace) try: diff --git a/homeassistant/components/script/trace.py b/homeassistant/components/script/trace.py index 1a7cc01e084..a8053feaa1e 100644 --- a/homeassistant/components/script/trace.py +++ b/homeassistant/components/script/trace.py @@ -19,7 +19,7 @@ class ScriptTrace(ActionTrace): ): """Container for automation trace.""" key = ("script", item_id) - super().__init__(key, config, context) + super().__init__(key, config, None, context) @contextmanager diff --git a/homeassistant/components/trace/__init__.py b/homeassistant/components/trace/__init__.py index c17cbf86715..eca22a56da8 100644 --- a/homeassistant/components/trace/__init__.py +++ b/homeassistant/components/trace/__init__.py @@ -48,11 +48,13 @@ class ActionTrace: self, key: tuple[str, str], config: dict[str, Any], + blueprint_inputs: dict[str, Any], context: Context, ): """Container for script trace.""" self._trace: dict[str, Deque[TraceElement]] | None = None self._config: dict[str, Any] = config + self._blueprint_inputs: dict[str, Any] = blueprint_inputs self.context: Context = context self._error: Exception | None = None self._state: str = "running" @@ -93,6 +95,7 @@ class ActionTrace: { "trace": traces, "config": self._config, + "blueprint_inputs": self._blueprint_inputs, "context": self.context, } ) diff --git a/tests/components/trace/test_websocket_api.py b/tests/components/trace/test_websocket_api.py index 8e481dd34b9..0b7b78b3f1a 100644 --- a/tests/components/trace/test_websocket_api.py +++ b/tests/components/trace/test_websocket_api.py @@ -169,6 +169,7 @@ async def test_get_trace( assert trace["trace"][f"{prefix}/0"][0]["error"] assert trace["trace"][f"{prefix}/0"][0]["result"] == sun_action _assert_raw_config(domain, sun_config, trace) + assert trace["blueprint_inputs"] is None assert trace["context"] assert trace["error"] == "Unable to find service test.automation" assert trace["state"] == "stopped" @@ -210,6 +211,7 @@ async def test_get_trace( assert "error" not in trace["trace"][f"{prefix}/0"][0] assert trace["trace"][f"{prefix}/0"][0]["result"] == moon_action _assert_raw_config(domain, moon_config, trace) + assert trace["blueprint_inputs"] is None assert trace["context"] assert "error" not in trace assert trace["state"] == "stopped" @@ -1162,3 +1164,71 @@ async def test_script_mode_2(hass, hass_ws_client, script_mode, script_execution trace = _find_traces(response["result"], "script", "script1")[1] assert trace["state"] == "stopped" assert trace["script_execution"] == "finished" + + +async def test_trace_blueprint_automation(hass, hass_ws_client): + """Test trace of blueprint automation.""" + id = 1 + + def next_id(): + nonlocal id + id += 1 + return id + + domain = "automation" + sun_config = { + "id": "sun", + "use_blueprint": { + "path": "test_event_service.yaml", + "input": { + "trigger_event": "blueprint_event", + "service_to_call": "test.automation", + }, + }, + } + sun_action = { + "limit": 10, + "params": { + "domain": "test", + "service": "automation", + "service_data": {}, + "target": {"entity_id": ["light.kitchen"]}, + }, + "running_script": False, + } + assert await async_setup_component(hass, "automation", {"automation": sun_config}) + client = await hass_ws_client() + hass.bus.async_fire("blueprint_event") + await hass.async_block_till_done() + + # List traces + await client.send_json({"id": next_id(), "type": "trace/list", "domain": domain}) + response = await client.receive_json() + assert response["success"] + run_id = _find_run_id(response["result"], domain, "sun") + + # Get trace + await client.send_json( + { + "id": next_id(), + "type": "trace/get", + "domain": domain, + "item_id": "sun", + "run_id": run_id, + } + ) + response = await client.receive_json() + assert response["success"] + trace = response["result"] + assert set(trace["trace"]) == {"trigger/0", "action/0"} + assert len(trace["trace"]["action/0"]) == 1 + assert trace["trace"]["action/0"][0]["error"] + assert trace["trace"]["action/0"][0]["result"] == sun_action + assert trace["config"]["id"] == "sun" + assert trace["blueprint_inputs"] == sun_config + assert trace["context"] + assert trace["error"] == "Unable to find service test.automation" + assert trace["state"] == "stopped" + assert trace["script_execution"] == "error" + assert trace["item_id"] == "sun" + assert trace.get("trigger", UNDEFINED) == "event 'blueprint_event'"