With the 'new' functions in automations, can I now loop an automation?

Hi,

I have an automation that are triggered by a motion detection.
What I want to achieve are;

  1. Turn on the automation, upon state = on it will automatically run the automation
  2. The automation should be looping until I turn off the automation

Can this be achieved?

Why do I want to loop the automation? I have a TTS message being broadcasted as an alarm over my media_player entities and I want to have the message being re-read until I turn of the automation.

Hereā€™s an example of automation that does that:

- alias: looper
  initial_state: false
  trigger:
    platform: state
    entity_id: automation.looper
    from: 'off'
    to: 'on'
  action:
    repeat:
      while:
        - condition: template
          value_template: '{{ repeat.index <= 50 }}'
      sequence:
        - service: persistent_notification.create
          data_template:
            title: 'Looper {{now().timestamp()|timestamp_local}}'
            message: 'Looper has triggered.'
        - delay: '00:00:10'
  • It uses initial_state: false to ensure that, upon startup, the automation is off.
  • It is triggered when the state of automation.looper (thatā€™s its own entity_id) changes from off to on.
  • It creates a persistent_notification, waits 10 seconds, then repeats this operation.
  • The repetitions continue for a maximum of 50 times or until automation.looper is turned off (whichever comes first). You could make it repeat indefinitely but itā€™s a better practice to include a self-limiting safeguard.

For your purposes, you will need to replace persistent_notification with your preferred service (to call TTS).

5 Likes

OMG @123, you really made my day! All I wanted in a simple reply!
Runs smoothly :pray:

For my curiosity, how do I make it run indefinitely ?

1 Like

I believe if you do this it will run indefinitely because the condition always evaluates to true.

    repeat:
      while:
        - condition: template
          value_template: '{{ true }}'

My preference would be to use the template in the original example and simply change the maximum value from 50 to something higher like 500. Thatā€™s sufficiently ā€œindefiniteā€ for most applications yet has a definitive end. However, you know your requirements best so if you need a never-ending loop, you can use {{ true }}.

NOTE
If the automation is looping and you restart Home Assistant, the initial_state: false option will cause the ā€œindefiniteā€ looping to stop (because the automation is set to off on startup).

3 Likes

Hello 123;

I am trying to use your automation to send a series of increase/decrease commands to reduce the temperature of a vaporizer from an input_number slider. It should send the command and update a sensor showing the temperature. I canā€™t seem to get it to loop, though it will send the command to the device once and doesnā€™t affect the same sensor. The same code attached to a button works flawlessly to do both, but as the vaporizer requires a series of events to decrease or increase temperature beyond a few presets, I was hoping to automate for fine tuning.

Here is the code I elaborated from your example:

- alias: temp_decrease_loop
#  initial_state: false
  trigger:
    platform: state
    entity_id: input_number.vape_target_temp
  condition: "{{ (states.sensor.arizer_vape_temp.state | int) > (states.input_number.vape_target_temp.state | int ) }}"
  action:
    repeat:
      while:
        - condition: template
          value_template: '{{ (states.sensor.arizer_vape_temp.state | int) > (states.input_number.vape_target_temp.state | int ) }}'
      sequence:
        - service: shell_command.arizer_temp_decrease
        - service: input_number.set_state
          data_template:
            entity_id: input_number.vape_actual_temp
            value: '{{ states.input_number.vape_actual_temp.state | float - 1 }}'
        - delay: '00:00:02'

The woking button code is this:

- id: 'Momentary Temp Decrease'
  alias: 'Momentary Button Temp Decrease'
  trigger:
    platform: state
    entity_id: switch.momentary_decrease_temperature
    from: 'off'
    to: 'on'
  condition:
    condition: state
    entity_id: switch.arizer_power_toggle
    state: 'on'
  action:
  - service: shell_command.arizer_temp_decrease
  - service: input_number.set_value
    data_template:
      entity_id: input_number.vape_actual_temp
      value: '{{ states.input_number.vape_actual_temp.state | float - 1 }}'

Any idea why this wonā€™t work?

I see one sensor and two input_numbers but I donā€™t know how they interact. The while checks one input_number but the action sets another. Unfortunately I donā€™t understand how this is supposed to work.

Ah, well input_number.vape_target_temp is the slider that I intend to use to fine-tune the temperatures. input_number.vape_actual_temp is the input number that gets increased or decreased by increments of +/- 1 with button clicks - it can also be set by some pre-set temperature buttons. However, these preset temperatures arenā€™t to my liking so I would rather be able to set it with an automation that handles the button clicks of +/- 1.

The sensor.arizer_vape_temp is just a front-end display read-out of the input_number.vape_actual_temp.

So I ended up getting ti working. I think the delay had bad indentation or somethingā€¦ it works now! Thanks for your help though.

- alias: temp_decrease_loop
  trigger:
    platform: state
    entity_id: input_number.vape_target_temp
  condition: "{{ (states.sensor.arizer_vape_temp.state | int) > (states.input_number.vape_target_temp.state | int ) }}"
  action:
    repeat:
      while:
        - condition: template
          value_template: '{{ (states.sensor.arizer_vape_temp.state | int) > (states.input_number.vape_target_temp.state | int ) }}'
      sequence:
        - service: shell_command.arizer_temp_decrease
        - service: input_number.set_value
          data_template:
            entity_id: input_number.vape_actual_temp
            value: '{{ states.input_number.vape_actual_temp.state | float - 1 }}'
        - delay: 
           milliseconds: 500

I do however have another question about the looping function; Is it possible to add an action to this that happens once before or after the loop?

Sorry for late reply! Yes, you simply include service calls before and after the repeat section.

  action:
  - service: persistent_notification.create
    data:
      title: 'This is a service call before the repeat section.'
      message: 'Hello!'
  - repeat:
      while:
      - condition: template
        value_template: '{{ (states.sensor.arizer_vape_temp.state | int) > (states.input_number.vape_target_temp.state | int ) }}'
      sequence:
      - service: shell_command.arizer_temp_decrease
      - service: input_number.set_value
        data:
          entity_id: input_number.vape_actual_temp
          value: '{{ states.input_number.vape_actual_temp.state | float - 1 }}'
      - delay: 
          milliseconds: 500
  - service: persistent_notification.create
    data:
      title: 'This is a service call after the repeat section.'
      message: 'Goodbye!'

Thanks Taras!

Wow, great solution. Until i found this post it wasnā€™t so easy.
For flashing siren with pause i had to write 3 scripts and 2 automations. Incredible good jobTaras!
Happy anniwersary with Home Assistant to Me :wink: