From 66f3b4d6ab6489e9a9f5a611182a7eaaa1b94fa9 Mon Sep 17 00:00:00 2001 From: Doug Hoffman Date: Sat, 28 Oct 2023 20:44:02 +0000 Subject: [PATCH 1/3] Create a new context for template triggers --- homeassistant/components/template/coordinator.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/template/coordinator.py b/homeassistant/components/template/coordinator.py index 7f24fe731cc02..937afaefdeda3 100644 --- a/homeassistant/components/template/coordinator.py +++ b/homeassistant/components/template/coordinator.py @@ -3,7 +3,7 @@ import logging from homeassistant.const import EVENT_HOMEASSISTANT_START -from homeassistant.core import CoreState, callback +from homeassistant.core import Context, CoreState, callback from homeassistant.helpers import discovery, trigger as trigger_helper from homeassistant.helpers.script import Script from homeassistant.helpers.typing import ConfigType @@ -85,10 +85,14 @@ async def _attach_triggers(self, start_event=None) -> None: ) async def _handle_triggered(self, run_variables, context=None): + # Create a new context referring to the old context. + parent_id = None if context is None else context.id + trigger_context = Context(parent_id=parent_id) + if self._script: - script_result = await self._script.async_run(run_variables, context) + script_result = await self._script.async_run(run_variables, trigger_context) if script_result: run_variables = script_result.variables self.async_set_updated_data( - {"run_variables": run_variables, "context": context} + {"run_variables": run_variables, "context": trigger_context} ) From 1388d3c1295dbde052a60dd9d80e5403b001c133 Mon Sep 17 00:00:00 2001 From: Doug Hoffman Date: Sat, 28 Oct 2023 22:13:21 +0000 Subject: [PATCH 2/3] Update tests --- tests/components/template/test_binary_sensor.py | 4 ++-- tests/components/template/test_sensor.py | 6 +++--- tests/components/template/test_weather.py | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/components/template/test_binary_sensor.py b/tests/components/template/test_binary_sensor.py index 01c0f005716bd..3394d7827c090 100644 --- a/tests/components/template/test_binary_sensor.py +++ b/tests/components/template/test_binary_sensor.py @@ -1123,7 +1123,7 @@ async def test_trigger_entity( assert state.attributes.get("icon") == "mdi:pirate" assert state.attributes.get("entity_picture") == "/local/dogs.png" assert state.attributes.get("plus_one") == 3 - assert state.context is context + assert state.context.parent_id is context.id assert len(entity_registry.entities) == 2 assert ( @@ -1142,7 +1142,7 @@ async def test_trigger_entity( assert state.attributes.get("entity_picture") == "/local/dogs.png" assert state.attributes.get("plus_one") == 3 assert state.attributes.get("another") == 1 - assert state.context is context + assert state.context.parent_id is context.id # Even if state itself didn't change, attributes might have changed hass.bus.async_fire("test_event", {"beer": 2, "uno_mas": "si"}) diff --git a/tests/components/template/test_sensor.py b/tests/components/template/test_sensor.py index 0ca666d22f1e6..10f5e3c991660 100644 --- a/tests/components/template/test_sensor.py +++ b/tests/components/template/test_sensor.py @@ -1169,7 +1169,7 @@ async def test_trigger_entity( assert state.attributes.get("entity_picture") == "/local/dogs.png" assert state.attributes.get("plus_one") == 3 assert state.attributes.get("unit_of_measurement") == "%" - assert state.context is context + assert state.context.parent_id is context.id assert len(entity_registry.entities) == 2 assert ( @@ -1189,7 +1189,7 @@ async def test_trigger_entity( assert state.attributes.get("plus_one") == 3 assert state.attributes.get("unit_of_measurement") == "%" assert state.attributes.get("state_class") == "measurement" - assert state.context is context + assert state.context.parent_id is context.id @pytest.mark.parametrize(("count", "domain"), [(1, "template")]) @@ -1667,4 +1667,4 @@ async def test_trigger_action( state = hass.states.get("sensor.hello_name") assert state.state == "3" - assert state.context is context + assert state.context.parent_id is context.id diff --git a/tests/components/template/test_weather.py b/tests/components/template/test_weather.py index 524f9c41aeb8a..a555db494063d 100644 --- a/tests/components/template/test_weather.py +++ b/tests/components/template/test_weather.py @@ -635,7 +635,7 @@ async def test_trigger_action( state = hass.states.get("weather.hello_name") assert state.state == "sunny" assert state.attributes["temperature"] == 3.0 - assert state.context is context + assert state.context.parent_id is context.id @pytest.mark.parametrize(("count", "domain"), [(1, "template")]) @@ -752,7 +752,7 @@ async def test_trigger_weather_services( assert state.attributes["cloud_coverage"] == 3.0 assert state.attributes["dew_point"] == 3.0 assert state.attributes["apparent_temperature"] == 3.0 - assert state.context is context + assert state.context.parent_id is context.id response = await hass.services.async_call( WEATHER_DOMAIN, From ebf0238122ac88c8030072c1050cc0dd5d66705c Mon Sep 17 00:00:00 2001 From: Doug Hoffman Date: Sun, 12 Nov 2023 23:23:54 +0000 Subject: [PATCH 3/3] Fire event for proper blame in logbook --- homeassistant/components/template/const.py | 2 ++ .../components/template/coordinator.py | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/template/const.py b/homeassistant/components/template/const.py index 6805c0ad81282..7fc4abe92cf47 100644 --- a/homeassistant/components/template/const.py +++ b/homeassistant/components/template/const.py @@ -33,3 +33,5 @@ CONF_ATTRIBUTE_TEMPLATES = "attribute_templates" CONF_PICTURE = "picture" CONF_OBJECT_ID = "object_id" + +EVENT_TEMPLATE_TRIGGERED = "template_triggered" diff --git a/homeassistant/components/template/coordinator.py b/homeassistant/components/template/coordinator.py index 937afaefdeda3..8bf1b72763d27 100644 --- a/homeassistant/components/template/coordinator.py +++ b/homeassistant/components/template/coordinator.py @@ -2,14 +2,20 @@ from collections.abc import Callable import logging -from homeassistant.const import EVENT_HOMEASSISTANT_START +from homeassistant.const import CONF_UNIQUE_ID, EVENT_HOMEASSISTANT_START from homeassistant.core import Context, CoreState, callback from homeassistant.helpers import discovery, trigger as trigger_helper from homeassistant.helpers.script import Script from homeassistant.helpers.typing import ConfigType from homeassistant.helpers.update_coordinator import DataUpdateCoordinator -from .const import CONF_ACTION, CONF_TRIGGER, DOMAIN, PLATFORMS +from .const import ( + CONF_ACTION, + CONF_TRIGGER, + DOMAIN, + EVENT_TEMPLATE_TRIGGERED, + PLATFORMS, +) _LOGGER = logging.getLogger(__name__) @@ -89,6 +95,14 @@ async def _handle_triggered(self, run_variables, context=None): parent_id = None if context is None else context.id trigger_context = Context(parent_id=parent_id) + self.hass.bus.async_fire( + EVENT_TEMPLATE_TRIGGERED, + { + CONF_UNIQUE_ID: self.unique_id, + }, + context=trigger_context, + ) + if self._script: script_result = await self._script.async_run(run_variables, trigger_context) if script_result: