From e4edc688f3541026d1bcdb99555e163222e92352 Mon Sep 17 00:00:00 2001 From: Nolan Stover Date: Wed, 15 Apr 2026 15:50:59 -0500 Subject: [PATCH 1/2] Add webhook_trigger stub --- .../pyscript/stubs/pyscript_builtins.py | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/custom_components/pyscript/stubs/pyscript_builtins.py b/custom_components/pyscript/stubs/pyscript_builtins.py index 0834634..55b7044 100644 --- a/custom_components/pyscript/stubs/pyscript_builtins.py +++ b/custom_components/pyscript/stubs/pyscript_builtins.py @@ -4,7 +4,7 @@ and documentation live here. """ -# pylint: disable=unnecessary-ellipsis, invalid-name, redefined-outer-name +# pylint: disable=unnecessary-ellipsis, invalid-name, redefined-outer-name, dangerous-default-value from __future__ import annotations from asyncio import Task @@ -12,6 +12,7 @@ from datetime import datetime from typing import Any, Literal +from homeassistant.components.webhook import SUPPORTED_METHODS from homeassistant.core import HomeAssistant hass: HomeAssistant @@ -121,6 +122,25 @@ def mqtt_trigger( ... +def webhook_trigger( + webhook_id: str, + str_expr: str | None = None, + local_only: bool = True, + methods: set[SUPPORTED_METHODS] | list[SUPPORTED_METHODS] = {"POST", "PUT"}, + kwargs: dict | None = None, +) -> Callable[..., Any]: + """Trigger when a request is made to a webhook endpoint. + + Args: + webhook_id: Webhook id to listen to. + str_expr: Optional expression evaluated against ``trigger_type``, ``webhook_id``, and ``payload``. + local_only: If False, allow requests from anywhere on the internet. + methods: HTTP methods to allow. + kwargs: Extra keyword arguments merged into each invocation. + """ + ... + + def pyscript_compile() -> Callable[..., Any]: """Compile the wrapped function into native (synchronous) Python. @@ -425,7 +445,7 @@ def wait_until( mqtt_trigger_encoding: str | None = None, webhook_trigger: str | list[str] | None = None, webhook_local_only: bool = True, - webhook_methods: list[str] = ("POST", "PUT"), + webhook_methods: list[SUPPORTED_METHODS] = ("POST", "PUT"), timeout: int | float | None = None, state_check_now: bool = True, state_hold: int | float | None = None, From db906a6f6bf6c2e342935cd3cfbc4448ea683749 Mon Sep 17 00:00:00 2001 From: Nolan Stover Date: Wed, 15 Apr 2026 21:23:09 -0500 Subject: [PATCH 2/2] Update and rearrange trigger decorators documentation Function Trigger Decorators section referred to four decorators (did not include webhook trigger). For consistency, the webhook trigger section was moved below the mqtt trigger, and before the state/time decorators. --- docs/reference.rst | 80 +++++++++++++++++++++++----------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/docs/reference.rst b/docs/reference.rst index a03f8a3..fc8992c 100644 --- a/docs/reference.rst +++ b/docs/reference.rst @@ -384,12 +384,13 @@ access the names of those built-in events by importing from ``homeassistant.cons Function Trigger Decorators --------------------------- -There are four decorators for defining state, time, event and MQTT triggers, and two decorators for -defining whether any trigger actually causes the function to run (i.e., is active), based on -state-based expressions or one or more time-windows. The decorators should appear immediately before -the function they refer to. A single function can have any or all of the decorator types specified. -Multiple trigger decorators of the same type can be added to a single function, but only one -``@state_active``, ``@time_active`` or ``@task_unique`` can be used per function. +There are five decorators for defining state, time, event, MQTT and webhook triggers, and two +decorators for defining whether any trigger actually causes the function to run (i.e., is active), +based on state-based expressions or one or more time-windows. The decorators should appear +immediately before the function they refer to. A single function can have any or all of the +decorator types specified. Multiple trigger decorators of the same type can be added to a single +function, but only one ``@state_active``, ``@time_active`` or ``@task_unique`` can be used per +function. A Python function with decorators is still a normal Python function that can be called by any other Python function. The decorators have no effect in the case where you call it directly from another @@ -863,6 +864,39 @@ must be set up to use ``@mqtt_trigger``. task.sleep(300) light.turn_off(entity_id="light.carport") +@webhook_trigger +^^^^^^^^^^^^^^^^ + +.. code:: python + + @webhook_trigger(webhook_id, str_expr=None, local_only=True, methods={"POST", "PUT"}, kwargs=None) + +``@webhook_trigger`` listens for calls to a `Home Assistant webhook `__ at ``your_hass_url/api/webhook/webhook_id`` and triggers whenever a request is made at that endpoint. Multiple ``@webhook_trigger`` decorators can be applied to a single function if you want to trigger off different webhook ids. + +Setting ``local_only`` option to ``False`` will allow request made from anywhere on the internet (as opposed to just on local network). +The methods option needs to be an list or set with elements ``GET``, ``HEAD``, ``POST``, or ``PUT``. + +An optional ``str_expr`` can be used to match against payload message data, and the trigger will only occur if that expression evaluates to ``True`` or non-zero. This expression has available these three +variables: + +- ``trigger_type`` is set to "webhook" +- ``webhook_id`` is set to the webhook_id that was called. +- ``payload`` is the data/json that was sent in the request returned as a dictionary. + +When the ``@webhook_trigger`` occurs, those same variables are passed as keyword arguments to the function in case it needs them. Additional keyword parameters can be specified by setting the optional ``kwargs`` argument to a ``dict`` with the keywords and values. + +An simple example looks like + +.. code:: python + + @webhook_trigger("myid", kwargs={"extra": 10}) + def webhook_test(payload, extra): + log.info(f"It ran! {payload}, {extra}") + +which if called using the curl command ``curl -X POST -d 'key1=xyz&key2=abc' hass_url/api/webhook/myid`` outputs ``It ran! {'key1': 'xyz', 'key2': 'abc'}, 10`` + +NOTE: A webhook_id can only be used by either a built-in Home Assistant automation or pyscript, but not both. Trying to use the same webhook_id in both will result in an error. + @state_active ^^^^^^^^^^^^^ @@ -950,40 +984,6 @@ matches any of the positive arguments, and none of the negative arguments. log.info(f"got motion. turning on the lights") light.turn_on(entity_id="light.hallway") - -@webhook_trigger -^^^^^^^^^^^^^^^^ - -.. code:: python - - @webhook_trigger(webhook_id, str_expr=None, local_only=True, methods={"POST", "PUT"}, kwargs=None) - -``@webhook_trigger`` listens for calls to a `Home Assistant webhook `__ at ``your_hass_url/api/webhook/webhook_id`` and triggers whenever a request is made at that endpoint. Multiple ``@webhook_trigger`` decorators can be applied to a single function if you want to trigger off different webhook ids. - -Setting ``local_only`` option to ``False`` will allow request made from anywhere on the internet (as opposed to just on local network). -The methods option needs to be an list or set with elements ``GET``, ``HEAD``, ``POST``, or ``PUT``. - -An optional ``str_expr`` can be used to match against payload message data, and the trigger will only occur if that expression evaluates to ``True`` or non-zero. This expression has available these three -variables: - -- ``trigger_type`` is set to "webhook" -- ``webhook_id`` is set to the webhook_id that was called. -- ``payload`` is the data/json that was sent in the request returned as a dictionary. - -When the ``@webhook_trigger`` occurs, those same variables are passed as keyword arguments to the function in case it needs them. Additional keyword parameters can be specified by setting the optional ``kwargs`` argument to a ``dict`` with the keywords and values. - -An simple example looks like - -.. code:: python - - @webhook_trigger("myid", kwargs={"extra": 10}) - def webhook_test(payload, extra): - log.info(f"It ran! {payload}, {extra}") - -which if called using the curl command ``curl -X POST -d 'key1=xyz&key2=abc' hass_url/api/webhook/myid`` outputs ``It ran! {'key1': 'xyz', 'key2': 'abc'}, 10`` - -NOTE: A webhook_id can only be used by either a built-in Home Assistant automation or pyscript, but not both. Trying to use the same webhook_id in both will result in an error. - Other Function Decorators -------------------------