Automation Stop IF Action Fails

Hello, i have and automation for my alarm system.
I have one problem, when some action won’t work (Lannouncer for example) the automation stop to run and everyting is after Lannouncer won’t work, for example won’t turn on my siren for example.
Someone have some solution?
I have many automation and with different devices that have this problem.
Also with telegram notification / mobile phone ecc.

- id: '1564681991925'
  alias: 0.2Allarme Triggered
  trigger:
  - entity_id: alarm_control_panel.allarme
    platform: state
    to: triggered
  condition: []
  action:
  - data:
      message: Attenzione! Allarme INTRUSI!!!
    service: notify.lannouncer
  - data:
      message: "Attenzione!!! ALLARME SCATTATO!!:   {% for state in states.binary_sensor\
        \ -%}\n{% if state.state == 'on' and state.name not in ['Router Antenna Studio',\n\
        'Router Studio'] %}\n {{ state.name }}\n {%- endif -%}\n {%- endfor -%}\n"
    service: notify.telegram
  - data:
      data:
        push:
          sound:
            critical: 1
            name: Alarm Alert Effect.wav
            volume: 1
      message: "Attenzione!!! ALLARME SCATTATO!!: {% for state in states.binary_sensor\
        \ -%}\n{% if state.state == 'on' and state.name not in ['Router Antenna Studio',\n\
        'Router Studio'] %}\n {{ state.name }}\n {%- endif -%}\n {%- endfor -%}\n"
    service: notify.mobile_app_iphone_di_stefano_augusto
  - data:
      data:
        push:
          sound:
            critical: 1
            name: Alarm Alert Effect.wav
            volume: 1
      message: "Attenzione!!! ALLARME SCATTATO!!: {% for state in states.binary_sensor\
        \ -%}\n{% if state.state == 'on' and state.name not in ['Router Antenna Studio',\n\
        'Router Studio'] %}\n {{ state.name }}\n {%- endif -%}\n {%- endfor -%}\n"
    service: notify.mobile_app_iphone_di_micol
  - data:
      entity_id: switch.0x000d6ffffee3a23f_switch
    service: switch.turn_off
  - data:
      entity_id: switch.0x000d6ffffedd6f8e_switch
    service: switch.turn_on
  - data:
      data:
        method: alarm
      message: FILE1
    service: notify.lannouncer
  hide_entity: true

Put the actions that are likely to fail in a script and call that as a service.
The script will run and actions failing in it will not affect the automation actions.

Thanks tom for your reply.
i have tried but if the action in the script fail the automatin won’t continue…

I’d first try putting any step that might fail at the end of the actions, if the order doesn’t matter. Of course, if there is more than one step that might fail, this isn’t a perfect solution.

The other possibility is to put each action that might fail into its own script and then call those scripts from the automation’s action. This is similar to what @tom_l suggested, but in addition to putting each potentially failing step into its own script, I’d put a small delay at the beginning of each of those scripts. Something like:

script:
  script_1:
    sequence:
      - delay:
          milliseconds: 1
      - data:
          message: Attenzione! Allarme INTRUSI!!!
        service: notify.lannouncer

When an automation (or whatever) calls a script, it will wait until the script “returns.” If the script fails while the automation is waiting, then the automation aborts, too, (and any remaining action steps will not be executed.) But, …

A script that does not contain any delay or wait_template steps will not return until all the steps have completed. However, if the script contains a delay or a wait_template (that does not immediately complete), when that step is executed the script will “suspend”, and more importantly, will “return” to the automation (or whatever) called it. At that point the automation will continue executing any remaining action steps. The script will effectively run asynchronously. So, when the delay completes the next step will be executed. However, even if that step fails, although it will cause any remaining steps in the script to be aborted, it will no longer affect the automation that called it.

So, the end result is, instead of calling each of the potentially failing steps synchronously, the above solution executes them asynchronously, meaning any failing step will be isolated and not affect the overall automation.

Now having said all this, I haven’t tried this myself. This is just based on my understanding of how the code currently works.

BTW, note that delay steps work by adding the delay value to the current time, and then waiting for the next time_changed event to happen that is at or after that time. Since time_changed events happen only once every second, a 1 mS delay can take anywhere from 0.001 S to 1.001 S. To put that another way, the delay will always be at least the specified amount, or up to one second more. So note that the solution I suggest above might add up to a second of delay before the actions put into scripts are executed. I would assume that’s ok, but just wanted to make sure you were aware of this side effect.

UPDATE: It turns out the technique of adding a small delay to the beginning of the script is, and never was, needed. (And, BTW, that behavior has changed starting with release 0.113 anyway!) I didn’t appreciate at the time I originally made this post that the calling script has a choice of whether or not to wait for the called script to finish. This is now documented. See: Waiting for Script to Complete. This also affects whether or not the calling script will abort if the called script causes an error.

UPDATE: By now all of this explanation is completely out of date. The script and automation behavior has changed dramatically. Please see the docs for how they work, and especially how errors are handled.

6 Likes

Thanks a lot @pnbruckner your approach is ingenius!!

I got linked here from another thread but…

Wait! What?
I never knew this. I have always been under the impression the automation carries on synchronously with the script. I have countless wait templates that wait for scripts to end. Looks like I can get busy code pruning…

(I’ve read your caveats…)

Did you mean to say “asynchronously”?

Here you have to be careful. wait_templates will check the state of the script via the State Machine, not directly. First, a script’s state will only update (in the State Machine) to 'on' if/when it executes a delay or wait_template that causes it to suspend. If the script does not have any of these steps, then it’s state will stay 'off'. Second, it will take a non-insignificant amount of time for the state of the script to update in the State Machine. So, even if the script does have a delay or wait_template that will cause its state to change to 'on', it won’t happen instantaneous, so if you have:

- service: script.xyz
- wait_template: "{{ is_state('script.xyz', 'off') }}"

it’s possible for the wait_template to complete before the state of the script changes to 'on'.

You also can’t do this:

- service: script.xyz
- wait_template: "{{ is_state('script.xyz', 'on') }}"
- wait_template: "{{ is_state('script.xyz', 'off') }}"

because it might go 'on' then 'off' before the first wait_template is executed, resulting in the caller getting “hung” (unless you add a timeout.)

There’s really no good, foolproof way to check when a script has completed, other than something like setting an input_boolean, starting the script, then waiting for the input_boolean to turn off, which would be done as the last step in the script.

HA’s script component is very basic and leaves a lot to be desired.

1 Like

Yes, we discussed something similar to this a while ago.

It does surprise me that HA isn’t better in this respect. Home automation does rather rely on things happening in the right sequence, which kind of has aa a pre-requisite the OS itself knowing exactly what is going on and when.

Having said that of course… I probably couldn’t have done it any better!

2 Likes