Automation option that checks if entity is not unavailable and repeats action

Issue:
I have many Shelly switches to control lightning, appliances etc. Some of them are in areas where WIFI is not that good and they are unavailable sometimes. This is a issue, because when automation tries to for example turn off the lights and it’s unavailable, nothing happens and automation ends.

I have mitigated this for some of my automations like pool heating, because it’s crucial to turn it off when electricity price is too high. For that i use wait_template like this:

        sequence:
          - wait_template: "{{not is_state('switch.pool_heater', 'unavailable')}}"
            continue_on_timeout: true
          - type: turn_on
            device_id: c6d83e9536c7d12ee2bfe51f477eaaa1
            entity_id: switch.pool_heater
            domain: switch

This works nicely, but for example if I want to to automation where I want to switch on/off all my outdoor lights (total 5 entities) it become’s quite complex. I cant have one sequence entry to switch them all but have wait_tepmplate + turn on for each of them. And as it’s sequence, processes don’t run in parallel. Do have five automations is even less efficient.

My ask
Would be nice if there would be a option "try until entity becomes abailable) in automation. Maybe here:

Couldn’t this result in HA hanging completely - if devices were powered off, for example?

Don’t forget to vote for your own feature request.

This have been suggested soo many times and a search should have brought up several threads with explanation on how to do it in the current setup and the limitations on doing it as a builtin feature.

I searched, but seems that i did not find the topic or topics explaining that. Could you point me to the right topic?

1 Like

Thanks, i’ll read them.

Also this looks promising: Improving automation reliability

Also maybe using parralel sequence in automation can achieve this:

action:
    - parallel:
        sequence:
          - sequence:
              - wait_template: "{{ not is_state('light.balcony_lights', 'unavailable') }}"
                continue_on_timeout: true
              - service: light.turn_on
                entity_id: light.balcony_lights
          - sequence:
              - wait_template: "{{ not is_state('light.pergola_lightning', 'unavailable') }}"
                continue_on_timeout: true
              - service: light.turn_on
                entity_id: light.pergola_lightning
          - sequence:
              - wait_template: "{{ not is_state('light.front_entrance_outdoor_lights', 'unavailable') }}"
                continue_on_timeout: true
              - service: light.turn_on
                entity_id: light.front_entrance_outdoor_lights
          - sequence:
              - wait_template: "{{ not is_state('light.front_yard_lights', 'unavailable') }}"
                continue_on_timeout: true
              - service: light.turn_on
                entity_id: light.front_yard_lights
          - sequence:
              - wait_template: "{{ not is_state('light.back_yard_outdoor_lightning', 'unavailable') }}"
                continue_on_timeout: true
              - service: light.turn_on
                entity_id: light.back_yard_outdoor_lightning

As you can see, there are several existing Feature Requests along the same lines requesting some form of “retry”. So far, none have been fulfilled.

Here’s what I currently suggest as a means of performing an action more than once, but no more than a certain number of times before conceding failure (to avoid trying indefinitely). The example uses a simple repeat - until to turn off a switch. It gives up after 5 attempts.

Here’s a slightly more sophisticated version that is more responsive than the linked example, because it uses a wait_for_trigger, instead of a fixed delay, for each iteration of the repeat. It tries to lock the door lock but no more than twice.

- repeat:
    sequence:
      - service: lock.lock
        target:
          entity_id: lock.door_lock
      - wait_for_trigger:
          - platform: state
            entity_id: lock.door_lock
            from: unlocked
            to: locked
        timeout: "00:00:04"
   until:
     - condition: template
       value_template: >-
         {{ is_state('lock.door_lock', 'locked') or
           repeat.index >= 2 }}

FWIW, I use this method for just one device in my home. Just like in the example, it’s a door lock and when its batteries are weak it takes more than one attempt to lock the door.

The lock isn’t able to report its battery level. However, when it takes more than one try to lock it, my version of the example also notifies me that the batteries may be weak because it took two attempts to lock the door.

Without specifying a value for timeout, that example will wait forever (when the light is unavailable). In other words, there’ll be an instance of the automation that remains in-progress indefinitely, waiting until the light is no longer unavailable (or until Home Assistant is restarted and purges all in-progress automations and scripts).

When using wait_template and wait_for_trigger, it’s important to use timeout. It can be made even more robust by checking the wait variable’s state afterwards. It reports if the entity’s desired state-change occurred or if it timed out. Based on its value, a decision can be made about what to do next.

As this automation runs at least 4 times a day i’t ok, if it will wait the unavilable, because automation is in restart mode.

As for now I tried the Parallelizing actions, so that each light has it’s own wait_template + light on/of sequence.

alias: Outdoor Lights Automation (UUS)
description: ""
trigger:
  - platform: sun
    event: sunset
    id: Sunset
  - platform: time
    at: "23:00:00"
    id: Night (23:00)
  - platform: time
    at: "07:00:00"
    id: 7am
  - platform: sun
    event: sunrise
    id: Sunrise
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: Sunset
        sequence:
          - parallel:
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_entrance_outdoor_lights',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.front_entrance_outdoor_lights
              - sequence:
                  - wait_template: "{{ not is_state('light.balcony_lights', 'unavailable') }}"
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.balcony_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_yard_lights', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.front_yard_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.back_yard_outdoor_lightning',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.back_yard_outdoor_lightning
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.pergola_lightning', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.pergola_lightning
                    data:
                      brightness_pct: 100
      - conditions:
          - condition: trigger
            id: Night (23:00)
        sequence:
          - parallel:
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_entrance_outdoor_lights',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.front_entrance_outdoor_lights
              - sequence:
                  - wait_template: "{{ not is_state('light.balcony_lights', 'unavailable') }}"
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.balcony_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_yard_lights', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.front_yard_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.back_yard_outdoor_lightning',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.back_yard_outdoor_lightning
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.pergola_lightning', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.pergola_lightning
      - conditions:
          - condition: trigger
            id: 7am
          - condition: sun
            before: sunrise
        sequence:
          - parallel:
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_entrance_outdoor_lights',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.front_entrance_outdoor_lights
              - sequence:
                  - wait_template: "{{ not is_state('light.balcony_lights', 'unavailable') }}"
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.balcony_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_yard_lights', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.front_yard_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.back_yard_outdoor_lightning',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.back_yard_outdoor_lightning
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.pergola_lightning', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_on
                    target:
                      entity_id: light.pergola_lightning
                    data:
                      brightness_pct: 100
      - conditions:
          - condition: trigger
            id: Sunrise
        sequence:
          - parallel:
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_entrance_outdoor_lights',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.front_entrance_outdoor_lights
              - sequence:
                  - wait_template: "{{ not is_state('light.balcony_lights', 'unavailable') }}"
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.balcony_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.front_yard_lights', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.front_yard_lights
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.back_yard_outdoor_lightning',
                      'unavailable') }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.back_yard_outdoor_lightning
              - sequence:
                  - wait_template: >-
                      {{ not is_state('light.pergola_lightning', 'unavailable')
                      }}
                    continue_on_timeout: true
                  - service: light.turn_off
                    target:
                      entity_id: light.pergola_lightning
    default: []
mode: restart

I could have made two scripts - outdoor lights on and outdoor lights off, for a neater automation, but nevertheless it should work.

I haven’t used it but there is a custom integration that claims to do what you want:

1 Like

Yes, trying this one as well.

Any plans to fix that eventually?


BTW, the default value for continue_on_timeout is true so it’s unnecessary to specify it twenty times in your automation.

There’s sufficient repetition in your automation to merit the use a script to control a light (pass the light’s entity_id as a variable). A script can be run in parallel mode. Just be sure to call it with the script.turn_on service call.