From dcd09523a68f223f16d7bfd2fc8fbbd578db7a94 Mon Sep 17 00:00:00 2001 From: RoboMagus <68224306+RoboMagus@users.noreply.github.com> Date: Fri, 12 Sep 2025 21:48:52 +0200 Subject: [PATCH] Webhook trigger: Enable templated webhook_id (#151193) --- homeassistant/components/webhook/trigger.py | 13 ++++-- tests/components/webhook/test_trigger.py | 44 +++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/webhook/trigger.py b/homeassistant/components/webhook/trigger.py index 907123561f79..3cc27a6f7e13 100644 --- a/homeassistant/components/webhook/trigger.py +++ b/homeassistant/components/webhook/trigger.py @@ -12,8 +12,9 @@ import voluptuous as vol from homeassistant.const import CONF_PLATFORM, CONF_WEBHOOK_ID from homeassistant.core import CALLBACK_TYPE, HassJob, HomeAssistant, callback from homeassistant.helpers import config_validation as cv +from homeassistant.helpers.template import Template from homeassistant.helpers.trigger import TriggerActionType, TriggerInfo -from homeassistant.helpers.typing import ConfigType +from homeassistant.helpers.typing import ConfigType, TemplateVarsType from . import ( DEFAULT_METHODS, @@ -33,7 +34,7 @@ CONF_LOCAL_ONLY = "local_only" TRIGGER_SCHEMA = cv.TRIGGER_BASE_SCHEMA.extend( { vol.Required(CONF_PLATFORM): "webhook", - vol.Required(CONF_WEBHOOK_ID): cv.string, + vol.Required(CONF_WEBHOOK_ID): cv.template, vol.Optional(CONF_ALLOWED_METHODS): vol.All( cv.ensure_list, [vol.All(vol.Upper, vol.In(SUPPORTED_METHODS))], @@ -83,7 +84,13 @@ async def async_attach_trigger( trigger_info: TriggerInfo, ) -> CALLBACK_TYPE: """Trigger based on incoming webhooks.""" - webhook_id: str = config[CONF_WEBHOOK_ID] + variables: TemplateVarsType | None = None + if trigger_info: + variables = trigger_info.get("variables") + webhook_id_template: Template = config[CONF_WEBHOOK_ID] + webhook_id: str = webhook_id_template.async_render( + variables, limited=True, parse_result=False + ) local_only = config.get(CONF_LOCAL_ONLY, True) allowed_methods = config.get(CONF_ALLOWED_METHODS, DEFAULT_METHODS) job = HassJob(action) diff --git a/tests/components/webhook/test_trigger.py b/tests/components/webhook/test_trigger.py index 2963db70ad4e..74a2d15b9ba9 100644 --- a/tests/components/webhook/test_trigger.py +++ b/tests/components/webhook/test_trigger.py @@ -333,3 +333,47 @@ async def test_webhook_reload( assert len(events) == 2 assert events[1].data["hello"] == "yo2 world" + + +async def test_webhook_template( + hass: HomeAssistant, hass_client_no_auth: ClientSessionGenerator +) -> None: + """Test triggering with a template webhook.""" + # Set up fake cloud + hass.config.components.add("cloud") + + events = [] + + @callback + def store_event(event): + """Help store events.""" + events.append(event) + + hass.bus.async_listen("test_success", store_event) + + assert await async_setup_component( + hass, + "automation", + { + "automation": { + "trigger": { + "platform": "webhook", + "webhook_id": "webhook-{{ sqrt(9)|round }}", + "local_only": True, + }, + "action": { + "event": "test_success", + "event_data_template": {"hello": "yo {{ trigger.data.hello }}"}, + }, + } + }, + ) + await hass.async_block_till_done() + + client = await hass_client_no_auth() + + await client.post("/api/webhook/webhook-3", data={"hello": "world"}) + await hass.async_block_till_done() + + assert len(events) == 1 + assert events[0].data["hello"] == "yo world"