For automations and scripts that have been queued - when are conditions and variables evaluated?
At the moment of trigger or moment of execution?
If i’m not mistaken, conditions are the filter that sits between the trigger and the action.
That is certainly one place for conditions, and those conditions are obviously evaluated at trigger time. I’m referring to variables and conditions in the action section.
If an automation instance is triggered but sits in a queued state for 5 minutes, are the conditions in the action section and variables evaluated at the time of trigger, or 5 minutes later at the time of execution?
I need a value at time the automation is executed. For variables we can obviously redeclare them at the beginning of the action block to force them to reevaluate. I’m basically asking if this is necessary for variables and what happens with conditions (in the action block).
I don’t know the answer but I can offer you my best guess.
The mode
option is used to control the execution of scripts and automations when they are called when already busy (i.e. how to handle the situation when the first execution is still busy when a second execution is requested).
That implies mode
governs the action
of an automation (which adheres to the same syntax as a script).
In other words, the automation’s trigger and condition are evaluated and then the action is executed in the manner dictated by mode
. If the action is currently busy, and mode
is queued, the second instance of the action is added to the queue.
Given this behavior, whatever variables defined outside the action
were computed at the moment it triggered. The same is true for the condition because it had to have evaluated the condition to determine if the action should be queued (you can only get to the action by first evaluating the condition).
Anyway, that’s my hypothesis. I suggest creating an experiment to test it.
Exactly what I did when I didn’t get a response earlier.
- id: test_automation
alias: test automation
initial_state: true
mode: queued
variables:
test: "{{ states('input_boolean.radio_on') }}"
trigger:
- platform: state
entity_id: input_boolean.led_alert
to: 'on'
action:
- service: system_log.write
data:
message: "Radio {{ states('input_boolean.radio_on') }}. Variable {{ test }}."
- service: input_boolean.turn_off
entity_id: input_boolean.radio_on
- delay:
minutes: 1
- service: system_log.write
data:
message: "I'm done. Radio {{ states('input_boolean.radio_on') }}. Variable {{ test }}."
- condition: state
entity_id: input_boolean.radio_on
state: 'off'
- service: system_log.write
data:
message: The radio is now off!
Started with the radio boolean on.
Triggered automation.
Radio on. Variable on.
Boolean turns off in automation.
Triggered automation again.
Results from first automation.
I'm done. Radio off. Variable on.
The radio is now off!
Second instance runs.
Radio off. Variable off.
Manually turned the radio boolean on.
Second instance completes.
I'm done. Radio on. Variable off.
So thank you for your educated and as it turns out, correct guess.
Variables are evaluated at trigger time and conditions within the action block are evaluated at run time. So the fix for that is as I suggested, reset the variables within the action block so they get reevaluated at runtime. (I suppose I should have included that in the experiment, but I’m confident that will work.)
Variables defined outside the action
have global scope can be referenced by condition
and action
. If the variable if not needed by the condition
, only the action
, then I would define it in the action
exclusively.
I didn’t realize that was possible! I got into the habit of always declaring them outside of the action when they were introduced and never thought twice about it. Thanks for that tidbit!
FWIW, here’s one of the more complicated automations I’ve created recently. It’s part of a system to restoring active timers that were interrupted by a restart. Before the advent of variables, it would not be possible to write this as a YAML automation (the original version was a python_script). It serves as an example of how variables can be used.
-
The
modes
variable, whose scope is the entire action, is defined once, outside therepeat
. It could be defined outside theaction
but it’s not used anywhere other than within theaction
so that’s where I chose to define it. -
The
mode
andtimers_text
variables are defined within therepeat
and are redefined every repetition (just twice in all becausecount
is2
). -
The
timers
variable is defined withinchoose
and is based on thetimers_text
variable. -
The remaining three variables,
t
,id
, andd
, are defined within a nestedrepeat
and their values are based on other variables.
- alias: 'Timers Restore'
mode: single
trigger:
platform: homeassistant
event: start
action:
- variables:
modes:
- active
- paused
- repeat:
count: 2
sequence:
- variables:
mode: '{{ modes[repeat.index-1] }}'
timers_text: "{{ states('input_text.timers_' ~ mode) }}"
- choose:
- conditions: '{{ timers_text | length > 0 }}'
sequence:
- variables:
timers: "{{ timers_text.split(',') }}"
- repeat:
count: '{{ timers | count }}'
sequence:
- variables:
t: '{{ timers[repeat.index-1].split() }}'
id: 'timer.{{t[0]}}'
d: "{{ t[1]|int - (now().timestamp()|int if mode == 'active' else 0) }}"
- condition: template
value_template: '{{ d > 0 }}'
- service: timer.start
data:
entity_id: '{{ id }}'
duration: '{{ d }}'
- condition: template
value_template: "{{ mode == 'paused' }}"
- service: timer.pause
data:
entity_id: '{{ id }}'
Funny you brought that up. I saw that thread a few days ago and bookmarked it. I’ve been meaning to try it out. My own solution was a little bit… messy, so I ended up nuking it.
Aside question - how did you get the folds with the hidden text in that post? That really makes long posts a lot more readable!
In the menu, click the gear icon. The first choice is Hide Details
.
It creates a markdown summary
section.