Make variables action not restricted to local scopes (#38150)

This commit is contained in:
Artur Pragacz 2025-03-23 22:49:38 +01:00 committed by GitHub
parent 501db97ffc
commit e064781c90
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -62,7 +62,7 @@ The variables {% term action %} allows you to set/override variables that will b
```yaml ```yaml
- alias: "Set variables" - alias: "Set variables"
variables: variables:
entities: entities:
- light.kitchen - light.kitchen
- light.living_room - light.living_room
brightness: 100 brightness: 100
@ -94,9 +94,7 @@ Variables can be templated.
### Scope of variables ### Scope of variables
Variables defined by the `variables` {% term action %} have local scope. This means that if a variable is changed in a nested sequence block, that change will not be visible in an outer sequence block. The `variables` {% term action %} assigns the values to previously defined variables with the same name. If a variable was not previously defined, it is assigned in the top-level (script run) scope.
Inside the `if` sequence the `variables` {% term action %} will only alter the `people` variable for that sequence.
{% raw %} {% raw %}
@ -111,17 +109,17 @@ sequence:
entity_id: device_tracker.paulus entity_id: device_tracker.paulus
state: "home" state: "home"
then: then:
# At this scope and this point of the sequence, people == 0
- variables: - variables:
people: "{{ people + 1 }}" people: "{{ people + 1 }}"
# At this scope, people will now be 1 ... paulus_home: true
- action: notify.notify - action: notify.notify
data: data:
message: "There are {{ people }} people home" # "There are 1 people home" message: "There are {{ people }} people home" # "There are 1 people home"
# ... but at this scope it will still be 0 # Variable value is now updated
- action: notify.notify - action: notify.notify
data: data:
message: "There are {{ people }} people home" # "There are 0 people home" message: "There are {{ people }} people home {% if paulus_home is defined %}(including Paulus){% endif %}"
# "There are 1 people home (including Paulus)"
``` ```
{% endraw %} {% endraw %}
@ -213,8 +211,8 @@ This {% term action %} evaluates the template, and if true, the script will cont
The template is re-evaluated whenever an entity ID that it references changes state. If you use non-deterministic functions like `now()` in the template it will not be continuously re-evaluated, but only when an entity ID that is referenced is changed. If you need to periodically re-evaluate the template, reference a sensor from the [Time and Date](/integrations/time_date/) integration that will update minutely or daily. The template is re-evaluated whenever an entity ID that it references changes state. If you use non-deterministic functions like `now()` in the template it will not be continuously re-evaluated, but only when an entity ID that is referenced is changed. If you need to periodically re-evaluate the template, reference a sensor from the [Time and Date](/integrations/time_date/) integration that will update minutely or daily.
{% raw %} {% raw %}
```yaml
```yaml
# Wait until media player is stopped # Wait until media player is stopped
- alias: "Wait until media player is stopped" - alias: "Wait until media player is stopped"
wait_template: "{{ is_state('media_player.floor', 'stop') }}" wait_template: "{{ is_state('media_player.floor', 'stop') }}"
@ -258,8 +256,8 @@ With both types of waits it is possible to set a timeout after which the script
You can also get the script to abort after the timeout by using optional `continue_on_timeout: false`. You can also get the script to abort after the timeout by using optional `continue_on_timeout: false`.
{% raw %} {% raw %}
```yaml
```yaml
# Wait for IFTTT event or abort after specified timeout. # Wait for IFTTT event or abort after specified timeout.
- wait_for_trigger: - wait_for_trigger:
- trigger: event - trigger: event
@ -322,6 +320,7 @@ This can be used to take different actions based on whether or not the condition
target: target:
entity_id: switch.some_light entity_id: switch.some_light
``` ```
{% endraw %} {% endraw %}
## Fire an event ## Fire an event
@ -453,7 +452,7 @@ repeat:
{% endraw %} {% endraw %}
Other types are accepted as list items, for example, each item can be a Other types are accepted as list items, for example, each item can be a
template, or even an mapping of key/value pairs. template, or even an mapping of key/value pairs.
{% raw %} {% raw %}
@ -509,7 +508,7 @@ For example:
- repeat: - repeat:
while: "{{ is_state('sensor.mode', 'Home') and repeat.index < 10 }}" while: "{{ is_state('sensor.mode', 'Home') and repeat.index < 10 }}"
sequence: sequence:
- ... - ...
``` ```
{% endraw %} {% endraw %}
@ -559,8 +558,9 @@ For example:
- repeat: - repeat:
until: "{{ is_state('device_tracker.iphone', 'home') }}" until: "{{ is_state('device_tracker.iphone', 'home') }}"
sequence: sequence:
- ... - ...
``` ```
{% endraw %} {% endraw %}
### Repeat loop variable ### Repeat loop variable
@ -691,7 +691,6 @@ automation:
{% endraw %} {% endraw %}
More `choose` can be used together. This is the case of an IF-IF. More `choose` can be used together. This is the case of an IF-IF.
The following example shows how a single {% term automation %} can control entities that aren't related to each other but have in common the same trigger. The following example shows how a single {% term automation %} can control entities that aren't related to each other but have in common the same trigger.
@ -856,10 +855,8 @@ Some of the caveats of running {% term actions %} in parallel:
there is no guarantee that they will be completed in the same order. there is no guarantee that they will be completed in the same order.
- If one {% term action %} fails or errors, the other {% term actions %} will keep running until - If one {% term action %} fails or errors, the other {% term actions %} will keep running until
they too have finished or errored. they too have finished or errored.
- Variables created/modified in one parallelized {% term action %} are not available - Variables created/modified in one parallelized {% term action %} can conflict with variables
in another parallelized {% term action %}. Each step in a parallelized has its own scope. from another parallelized {% term action %}. Make sure to give them distinct names to prevent that.
- The response data of a parallelized {% term action %} is however also available outside of its
own scope. This is especially useful for parallelizing execution of long-running {% term actions %}.
## Stopping a script sequence ## Stopping a script sequence
@ -963,7 +960,7 @@ blueprint:
input: input:
input_boolean: input_boolean:
name: Boolean name: Boolean
selector: selector:
boolean: boolean:
actions: actions: