How to stop template-based automation from triggering every other second

Dear community,

I am working on an automation for opening and closing window shutters based on UV-index. The old version of my script just works fine (Automation trigger based on sensor.openweathermap_uv_index).

As the api only delivers the uv-index every 60min, the automation is triggered only once per 60min.

I am planing to change from the uv-index to a room-temperature-sensor. (D1mini with some DHT-sensor and Tasmota) Those sensors provide data every other minute.

Question: how do I prevent the automation from triggering the shutters every other minute. Especially, when temperature values are hopping around a defined threshhold?
In state-triggered automations, I can use the for-x-minuttes-element. How can I use this in a numeric-state-trigger, which is changing every other minute? or can I use the "for: ‘00:15:00’ " in a template-based condition?

any help is very much appreciated.

my current automation:

alias: Dach Rollo Management v2
description: |-
  Based on UV-index, window shutters are opened/closed in 4 steps.
  no number -> stop 
  0 - 2.5 -> fully open
  2.5 - 3.5 -> 1/3-closed
  3.5 - 4.5 -> 50%-closed
  4.5 - 5.5 -> 2/3-closed
  5.5+ -> 100%-closed
trigger:
  - platform: state
    entity_id:
      - sensor.openweathermap_uv_index
    for:
      hours: 0
      minutes: 15
      seconds: 0
condition: []
action:
  - choose:
      - conditions:
          - condition: template
            value_template: '{{ not is_number(states(''sensor.openweathermap_uv_index'')) }}'
        sequence:
          - stop: UV-Index liefert keine Zahlenwerte.
            error: true
      - conditions:
          - condition: template
            value_template: >-
              {* If UV-Index low and position of shutter not fully open, then
              call service *} {{ 2.5 >
              states('sensor.openweathermap_uv_index')|float(0) and not ( 100 >=
              state_attr('cover.lukarne_rollo', 'current_position') >= 95 ) }}
        sequence:
          - service: script.dach_rollos_auf
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 3.5 > states('sensor.openweathermap_uv_index')|float(0) >= 2.5
              and not ( 71 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 61 ) }}
        sequence:
          - service: script.dach_rollos_33_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 4.5 > states('sensor.openweathermap_uv_index')|float(0) >= 3.5
              and not ( 55 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 45 ) }}
        sequence:
          - service: script.dach_rollos_50_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 5.5 > states('sensor.openweathermap_uv_index')|float(0) >= 4.5
              and not ( 38 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 28 ) }}
        sequence:
          - service: script.dach_rollos_66_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ states('sensor.openweathermap_uv_index')|float(0) >= 5.5 and
              not ( 5 >= state_attr('cover.lukarne_rollo', 'current_position') )
              }}
        sequence:
          - service: script.dach_rollos_zu
            data: {}
    default:
      - stop: no significant change in state
mode: single

If your value is continuously changing this may never trigger.

This example will only run every 15 minutes at most:

alias: Dach Rollo Management v2
description: |-
  Based on UV-index, window shutters are opened/closed in 4 steps.
  no number -> stop 
  0 - 2.5 -> fully open
  2.5 - 3.5 -> 1/3-closed
  3.5 - 4.5 -> 50%-closed
  4.5 - 5.5 -> 2/3-closed
  5.5+ -> 100%-closed
trigger:
  - platform: state
    entity_id:
      - sensor.openweathermap_uv_index
condition: []
action:
  - choose:
      - conditions:
          - condition: template
            value_template: '{{ not is_number(states(''sensor.openweathermap_uv_index'')) }}'
        sequence:
          - stop: UV-Index liefert keine Zahlenwerte.
            error: true
      - conditions:
          - condition: template
            value_template: >-
              {* If UV-Index low and position of shutter not fully open, then
              call service *} {{ 2.5 >
              states('sensor.openweathermap_uv_index')|float(0) and not ( 100 >=
              state_attr('cover.lukarne_rollo', 'current_position') >= 95 ) }}
        sequence:
          - service: script.dach_rollos_auf
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 3.5 > states('sensor.openweathermap_uv_index')|float(0) >= 2.5
              and not ( 71 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 61 ) }}
        sequence:
          - service: script.dach_rollos_33_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 4.5 > states('sensor.openweathermap_uv_index')|float(0) >= 3.5
              and not ( 55 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 45 ) }}
        sequence:
          - service: script.dach_rollos_50_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 5.5 > states('sensor.openweathermap_uv_index')|float(0) >= 4.5
              and not ( 38 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 28 ) }}
        sequence:
          - service: script.dach_rollos_66_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ states('sensor.openweathermap_uv_index')|float(0) >= 5.5 and
              not ( 5 >= state_attr('cover.lukarne_rollo', 'current_position') )
              }}
        sequence:
          - service: script.dach_rollos_zu
            data: {}
  - delay: 
      minutes: 15
mode: single
max_exceeded: silent # suppress 'already running' warnings

Automation reload or Home Assistant restarts will reset the automation allowing the next trigger.

Hi @tom_l ,

Thank you very much for your quick response.

So simple, adding a delay at the end to prevent the next triggering of the automation to start.

Does this work, even if there are “stops” in the automation?
Will there be a queue building up or are the triggers, which are happening during the delay, omitted?

Edit: remembered the docs…
Automation Modes - Home Assistant

No. That would exit out of the automation without inserting a delay. You only have the one choose action so you can inset the delay before each stop. Which ever action is picked would then start the delay. It’s up to you what to do if no action is picked (default action) you may or may not want the delay to prevent it triggering again for 15 minutes.

Nope no queue, and this line max_exceeded: silent means you don’t even get warnings in the log that the automation was triggered again but is currently running in single mode.

If you want to have stops in your automation as well you can add this as the condition instead of using a delay:

condition: "{{ this.attributes.last_triggered < now() - timedelta(minutes=15) }}"

This condition will stop the automation from executing if its been less then 15 minutes since the last time it was triggered. Functions identically to tom_l’s suggestion just a different approach that doesn’t depend on mode: single to stop other runs. Then your automation can have stops or whatever else in it.

Please note that if you use this it must actually be the condition of the automation, not a condition step in the sequence. Once the automation reaches the sequence it counts as being triggered so this will only work if its used in the condition field.

2 Likes

One thing to note about this method:

Is that if your choose action does not perform any action, it will still have to wait for the uv_index to update after 15 minutes.

Whereas using a delay before your stop actions will allow the the automation actions to run the choose action on the next uv_index update - if you have no delay in the no action (default) part of your choose. So this way you only get the 15 minute wait if an action was performed. You may or may not want this.

1 Like

You could create an input_select with options: 0, 33, 50, 66, 100 and stop. Then create an automation to set those values according to the sensor:

- alias: UV change then set input
  trigger:
  - platform: state
    entity_id: sensor.openweathermap_uv_index
  action:
  - service: input_select.select_option
    entity_id: input_select.uv_to_percentage
    data:
      option: >
        {% if 0 < states('sensor.openweathermap_uv_index') < 2.5 %}
          0
        {% elif 2.5 < states('sensor.openweathermap_uv_index') < 3.5 %}
          33
        [...]
        {% else %}
          stop
        {% endif%}

Then you can add that input_select in your main automation as a trigger and set it to only trigger when it has changed its state for 15 minutes.

alias: Dach Rollo Management v2
description: |-
  Based on UV-index, window shutters are opened/closed in 4 steps.
  no number -> stop 
  0 - 2.5 -> fully open
  2.5 - 3.5 -> 1/3-closed
  3.5 - 4.5 -> 50%-closed
  4.5 - 5.5 -> 2/3-closed
  5.5+ -> 100%-closed
trigger:
  - platform: state
    entity_id:
      - sensor.input_select.uv_to_percentage
    for:
      hours: 0
      minutes: 15
      seconds: 0
[....]

Ah yes that’s true. The minute it enters the sequence it counts as being triggered even if nothing happens. So yea that would be the con to this approach, good point.

It seems weird to introduce another entity to manage this when there’s options for rate limiting within the same automation. That being said if you’re going to do this, you definitely don’t need to introduce two new entities (another automation AND an input select). Just use a template sensor:

template:
  - sensor:
      - name: UV to Percentage
        state: >-
          {% if 0 < states('sensor.openweathermap_uv_index') < 2.5 %}
            0
          {% elif 2.5 < states('sensor.openweathermap_uv_index') < 3.5 %}
            33
          [...]
          {% else %}
            stop
          {% endif%}

Then trigger off sensor.uv_to_percentage.

Input helpers are basically for when you want to be able to change something manually from the UI which doesn’t seem like something the author wants to do. If the state is completely managed via a template, a template sensor is a better choice.

1 Like

And wouldn’t just polling every 15 minutes do what the OP wants? just replacing the trigger.

alias: Dach Rollo Management v2
description: |-
  Based on UV-index, window shutters are opened/closed in 4 steps.
  no number -> stop 
  0 - 2.5 -> fully open
  2.5 - 3.5 -> 1/3-closed
  3.5 - 4.5 -> 50%-closed
  4.5 - 5.5 -> 2/3-closed
  5.5+ -> 100%-closed
trigger:
  - platform: time_pattern
    minutes: "/15"
condition: []
action:
  - choose:
      - conditions:
          - condition: template
            value_template: '{{ not is_number(states(''sensor.openweathermap_uv_index'')) }}'
        sequence:
          - stop: UV-Index liefert keine Zahlenwerte.
            error: true
      - conditions:
          - condition: template
            value_template: >-
              {* If UV-Index low and position of shutter not fully open, then
              call service *} {{ 2.5 >
              states('sensor.openweathermap_uv_index')|float(0) and not ( 100 >=
              state_attr('cover.lukarne_rollo', 'current_position') >= 95 ) }}
        sequence:
          - service: script.dach_rollos_auf
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 3.5 > states('sensor.openweathermap_uv_index')|float(0) >= 2.5
              and not ( 71 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 61 ) }}
        sequence:
          - service: script.dach_rollos_33_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 4.5 > states('sensor.openweathermap_uv_index')|float(0) >= 3.5
              and not ( 55 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 45 ) }}
        sequence:
          - service: script.dach_rollos_50_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ 5.5 > states('sensor.openweathermap_uv_index')|float(0) >= 4.5
              and not ( 38 >= state_attr('cover.lukarne_rollo',
              'current_position') >= 28 ) }}
        sequence:
          - service: script.dach_rollos_66_zu
            data: {}
      - conditions:
          - condition: template
            value_template: >-
              {{ states('sensor.openweathermap_uv_index')|float(0) >= 5.5 and
              not ( 5 >= state_attr('cover.lukarne_rollo', 'current_position') )
              }}
        sequence:
          - service: script.dach_rollos_zu
            data: {}
    default:
      - stop: no significant change in state
mode: single

It would, but it would also needlessly trigger every 15 minutes at night when not needed. Time pattern triggers are rarely the best way to do something.

Hi all,

thank you very much for your different approaches to this. I am not shure, if I understood all of it to full extend and when to use which approach.

For my current implementation with the openweathermap-UV-index, I like the idea of the 15min-delay. The API does provide data every 60min, so the delay is just a small security feature to prevent the shutters to jump around, if I missed something in the configuration. (Checking not only the state of the UV-index, but also the position of the shutters before calling the service, is my second approach to stop unnecessary calls of services.)

When switching to an indoor temperature sensor, I will probably implement a state-template-sensor, as proposed by @CentralCommand. That’s something, I have done before and feel comortable with. (-> Switching a fan on and off with an automation)
Hm, while writing this post, I realize that there is a big difference between a fan and a window shutter. For the use case of opening and closing of a shutter, the delay is probably more effective and easier to implement.

Again: thank you all for your valluable input. It’s very much appreciated!

1 Like