Wait template for a state change

I am trying to have a wait_template to wait for any state change.
would something like this work?

  - wait_template: '{{ states.sensor.my_time_to_home.state == "" }}'

Nope, nothing will work in this case unless you store the state prior to going into the wait template.

The correct path you would need to follow would be:

  1. store state
  2. wait til state changes from stored state.

Unfortunately, wait templates can’t do that by themselves. What you could do is create a script and pass the current state to the script.

script:

script:
  my_wait_automation:
    sequence:
      - wait_template: "{{ not is_state(my_entity, my_state) }}"

then in your automation:

  action: 
    - service: script.my_wait_automation
      data_template:
        my_entity: sensor.my_time_to_home
        my_state: "{{ states('sensor.my_time_to_home') }}"

Basically, you pass the current state to the script. Then the script will wait til that state changes. You cannot do this in a single action because the variables won’t pass from the previous service. This is the only way to pass a variable from 1 service to another, which is what you need.

EDIT:
So what we are doing in the action section is making 2 new variables that are passed to the script. This is done automatically because we are storing the variables in the data. All data items are passed into the script and can be used. In our case, we are using variable my_entity and my_state. You can name these anything you want. I try not to use names that home assistant uses for regular data, like brightness or entity_id because you will overwrite those attributes if that already exists in the data. It shouldn’t exist because this is a script, but it could in certain scenarios. Anyways, once the variables are passed to the script, you can use them by just calling the variable anywhere in a template, ANY template in ANY service.

1 Like

I do like the idea of not having to create an input_text or something to hold the initial state, but I don’t think a script (or the action part of an automation) will wait for an invoked script to finish, but rather will continue on in parallel. So I’m not sure this will do it, unless the remaining steps of the “caller” are moved into the “callee” after the wait_template.

I was trying to imply that he would finish his automation inside the script. I had no intention of going back to the automation. I probably should have specified that.

1 Like

This might be a silly question but…
Can the template (temporarily) set the value into something (even empty it) and when the component updates the wait_template triggers?

I have seen some templates here in the forum, using the SET argument… I am not very good at this, but it sounds like something…

Actually @pnbruckner you answered one of my posts using the SET argument!

no because the whole wait template gets executed. You’d always be looping with the states being the same because you’d get the state then check the state. That’s why you have to get the state prior to checking the state. So the loop is only checking the state.

EDIT: If you set the state in a prior service, then get the state in the wait template that could work. I’ve never done set outside python scripts or components. So I can’t help you there.

The wait_template works by evaluating (i.e., “rendering”) the template. If it results in true, then it will complete and the next step (if any) in the script will be executed. If it results in anything but true, then it will wait for any of the referenced entities to cause a state_changed event, at which time it will start again. So the template may (and probably will) be evaluated/rendered multiple times. If you use a SET statement, you’re setting a variable whose context is the single execution of the template. Which means the next time it runs that will be gone and it will be set again with the new value. So a template SET statement won’t help here (at least in that way.)

You can either use @petro’s technique, or you could use an input_text to save the state and compare against in the wait_template, something like this:

- service: input_text.set_value
  entity_id: input_text.prev_state
  data_template:
    value: "{{ states('sensor.my_time_to_home') }}"
- wait_template: >
    {{ not is_state('sensor.my_time_to_home', states('input_text.prev_state')) }}

Yep, you pretty much have to store the state. Both methods are viable and both methods have there drawbacks, which are pretty much identical. With the method I provided you’re going to have an extra script floating around your environment. If you do @pnbruckner you’re going to have an extra input_text floating around your environment. @pnbruckner’s method will be easier to read because the code is all in one place. I’d probably go with that one.

1 Like

I thought I understood this well enough to have a wait_template pause until a camera recording was completed. But it sure looks like the automation is not waiting and immediately plowing on through the rest of the automation (based on timestamps of the files created).

EDIT: Solved! The issue wasn’t with wait_template but learning that saving a “recording done” flag following a service call to camera.record isn’t going to work. That’s because the recording is done asynchronously which means the recording_done flag is set immediately, therefore - pointless.

Meanwhile, back to square one trying to get folder_watcher to cooperate with wait_template.

Dear Gary very thanks for your private reply. It’s true, so I post your message in copy with my answer.

Me:
“Hi, I saw that you too are looking for a way to know when the camera.record service finishes writing the video file. I need it to send the file via telegram without putting a delay of seconds. I am also trying to understand how to extend the time of the camera.record service not linked to a time frame but decided by a sensor when to stop recording. Have you solved these problems? thanks so much if you can help me”

Gary:
"Hi Sergio,

In a nutshell, you add this to your configuration yaml which initializes the recording-in-progress flag and defines the folder and file type to monitor for new file creations…

input_boolean:
  video_recording:
    initial: off

folder_watcher:
  - folder: "/media/recordings"
    patterns:
      - '*.mp4'

Then you can set up an automation, such as this:

  alias: MP4  Folder Watcher
  trigger:
    platform: event
    event_type: folder_watcher
    event_data: {"event_type":"created"}
    
  action:    # when  mp4 is modified, recording is complete.   Set recording flag to off.
    - service: input_boolean.turn_off
      entity_id: input_boolean.video_recording

So with that in place, you can now set up your automation to run the camera.record service and set the recording in progress flag…

   - service: input_boolean.turn_on
     entity_id: input_boolean.video_recording

immediately after, add this bit of code to wait for it to complete…

    # wait for mp4 file to finish (recording off)... (as triggered by folder_watcher automation)
    - wait_template: "{{ is_state('input_boolean.video_recording', 'off') }}"

Then following you can send your alerts/telegram notices, etc.

The camera.record service only accepts a duration and lookback. I don’t know of any way to tell it to start recording for an indefinite time with an external interrupt to stop. Lastly, I’m happy to help, but it’s best IMO to ask these types of questions on the public forum instead of private msg because they often help others."

Me:

I had found a solution similar to yours by copying and pasting solutions found around. First of all I created an automation to create .mp4 files with unique names:

alias: telegram send video
description: ''
trigger:
  - platform: state
    entity_id: binary_sensor.sensor_magnet_on_off
    to: 'on'
    from: 'off'
condition:
  - condition: state
    entity_id: input_boolean.telegram_video
    state: 'off'
action:
  - service: script.telegram_video_door_opened
    data_template:
      nome_file: 'CAMERA_{{ now().strftime("%Y%m%d-%H%M%S") }}.mp4'

then the rest in the script:

alias: telegram_video_door_opened
sequence:
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.telegram_video
  - service: camera.record
    data:
      filename: '/video/{{nome_file}}'
      duration: 10
      lookback: 1
    target:
      entity_id: camera.foscam1
  - wait_for_trigger:
      platform: event
      event_type: folder_watcher
      event_data:
        event_type: created
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.telegram_video
  - delay:
      hours: 0
      minutes: 0
      seconds: 2
      milliseconds: 0
  - service: telegram_bot.send_video
    data:
      file: '/video/{{nome_file}}'
      caption: '{{ now().strftime("%H:%M.%S") }}'

What do you think about this solution? should I do as you say?
thanks so much for your help.
Sergio

Hi Sergio,

I was on the move over the weekend so didn’t see your reply until now. At a quick glance, it looks to me like a workable solution. The key of course is the wait sequence following camera.record using folder_watcher for new mp4’s being created.

I’m trying to get my script wait till the_entity changes its state but it fires right away. I think I did exactly the way described in the thread.
Script that’s being called:

notify_on_state_changed:
  alias: "Notify on state changed"
  mode: parallel
  fields:
    the_entity:
      description: "Entity that will notify its state change"
      example: light.tv_lights
    the_state:
      description: "Initial state of entity at the beginning"
      example: "off"
  sequence:
    - service: notify.mobile_app_s20fe
      data_template:
        message: "You'll get reminder once {{state_attr(the_entity,'friendly_name')}} changes its state. Current state is {{ the_state }}"
    - wait_template: >-
        {{ not is_state(the_entity, the_state) }}
    - service: notify.mobile_app_s20fe
      data_template:
        message: "State of {{state_attr(the_entity,'friendly_name')}} changed to {{ states(the_entity)}}"

Caller:

      - type: 'custom:button-card'
        template: card_binary_sensor_alert
        variables:
          ulm_icon_hold_service: "script.notify_on_state_changed"
          ulm_icon_hold_service_data:
            the_entity: binary_sensor.bedroom_window_contact
            the_state: "{{ states('binary_sensor.bedroom_window_contact') }}"

Perhaps anyone know why the script doesn’t wait? If I use input_text instead of the_state, it will wait just fine, but for some reason solution with input_text doesn’t work well for me

the frontend doesn’t support jinja templates.

Man, you’re truly learn something every day… Changed it for js template and it works like a charm:

ulm_icon_hold_service_data:

            the_entity: binary_sensor.bedroom_window_contact

            the_state: '[[[ return states["binary_sensor.bedroom_window_contact"].state ]]]'

Thanks!