From 8ddf4baee1e0cf5635ed48433aca56482bae8e0e Mon Sep 17 00:00:00 2001 From: David Poll Date: Mon, 26 May 2025 11:23:00 -0700 Subject: [PATCH] Add docs for as_function and apply (#38730) Co-authored-by: c0ffeeca7 <38767475+c0ffeeca7@users.noreply.github.com> --- .../_docs/configuration/templating.markdown | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/source/_docs/configuration/templating.markdown b/source/_docs/configuration/templating.markdown index d60f5138f1d..cc6f0f60ccd 100644 --- a/source/_docs/configuration/templating.markdown +++ b/source/_docs/configuration/templating.markdown @@ -63,7 +63,8 @@ Jinja supports a set of language extensions that add new functionality to the la To improve the experience of writing Jinja templates, we have enabled the following extensions: -- [Loop Controls](https://jinja.palletsprojects.com/en/3.0.x/extensions/#loop-controls) (`break` and `continue`) +- [Loop Controls](https://jinja.palletsprojects.com/en/stable/extensions/#loop-controls) (`break` and `continue`) +- [Expression Statement](https://jinja.palletsprojects.com/en/stable/extensions/#expression-statement) (`do`) ### Reusing templates @@ -79,7 +80,7 @@ For example, you might define a macro in a template in `config/custom_templates/ {% raw %} -```text +```jinja {% macro format_entity(entity_id) %} {{ state_attr(entity_id, 'friendly_name') }} - {{ states(entity_id) }} {% endmacro %} @@ -91,13 +92,32 @@ In your automations, you could then reuse this macro by importing it: {% raw %} -```text +```jinja {% from 'formatter.jinja' import format_entity %} {{ format_entity('sensor.temperature') }} ``` +{$ endraw %} + +Home Assistant also allows you to write macros with non-string return values by +taking a named argument called `returns` and calling it with a return value. Once created, +pass the macro into the `as_function` filter to use the returned value: + +{% raw %} + +```jinja +{%- macro macro_is_switch(entity_name, returns) -%} + {%- do returns(entity_name.startswith('switch.')) -%} +{%- endmacro -%} +{%- set is_switch = macro_is_switch | as_function -%} +{{ "It's a switch!" if is_switch("switch.my_switch") else "Not a switch!" }} +``` + {% endraw %} +In this way, you can export utility functions that return scalar or complex values rather than +just macros that render to strings. + ## Home Assistant template extensions Extensions allow templates to access all of the Home Assistant specific states and adds other convenience functions and filters. @@ -1361,6 +1381,26 @@ Some examples: {% endraw %} +### Working with macros + +Home Assistant provides two additional functions that make macros much more powerful. + +{% raw %} + +- `apply` is both a filter and a test that allows you to use any callable (macros or functions) wherever +you can use other filters and tests. `apply` also passes along any additional parameters to the function. +For example, if you had a function called `double`, you could call +`{{ [1, 2, 3, 4] | map('apply', double) | list }}`, which would render as `[2, 4, 6, 8]`. +Alternatively, if you had a function called `is_multiple_of`, you could call +`{{ [1, 2, 3, 4] | select('apply', is_multiple_of, 2) | list }}`, which would render as `[2, 4]`. +- `as_function` is a filter that takes a macro that has a named parameter called `returns`. The macro can +then call `{%- do returns(return_value) -%}`. After passing this macro into `as_function`, the resulting +function returns your return value directly, preserving the underlying data type rather than rendering +a string. You can return dictionaries, numbers, `True`/`False` (allowing you to write your own tests when +used with `apply`), or any other value your code might produce. + +{% endraw %} + ## Merge action responses Using action responses we can collect information from various entities at the same time.