Looping scripts

I need to have a script which continuously loops until another event stops the script. I followed the flashing lights example which executes it’s own script at the end but when I tried I get a warning that the script is already running and does nothing.

here is an example of what I tried…

test:
alias: Test script triggered
sequence:
- service: notify.notify
data_template:
message: ‘{{“script triggered”}}’
- delay:
seconds: 5
- alias: Loop script
service: script.turn_on
data:
entity_id: script.test

The log…
homeassistant.components.script: Script script.test already running.

1 Like

How about 2 scripts?

  • Script 1 just calls script 2
  • Script 2 does the looping then calls script 1

Either script 1 or 2 has a condition that stops execution when the condition is met.

3 Likes

I do it exactly like @aimc describes…I have to scripts:

  1. party_lights_loop
    Does the party lights stuff and calls script 2
  2. party_lights_pause
    Has a 3 second delay and starts script "1

If i want to cancel the loop I just call service.turn_off on both entities and it stops.

Works like a charm.

3 Likes

The proposed solution works, but I am still looking for a solution to make the first post example to works. I was using in the past a code like this https://home-assistant.io/cookbook/automation_flashing_lights/ (I also shared my work, this link is based on my config file), but it doesn’t work anymore from some newer version till today.
It seems the scripts does not allow anymore to call themselves from inside.
With some changes over the versions, we have to modify our code to accommodate, sometimes the modification should be in several places.

This is correct. It is not possible for a script to call itself and that is a good thing actually. So your version simply does not work anymore.

I am trying a variation of this script and so far it turns on once then off and it does not loop as I had hoped. I would greatly appreciate any assistance. Basically I want it this light (and eventually more and/or a siren) to loop flash until the alarm is set to “disarmed” via HA.

Currently the only trigger to activate the alarm sequence is a door sensor.

Here is the full automation (in automation.yaml) having issues formatting the dots are “-”:

- alias: Automation1
  trigger:
    platform: state
    entity_id: sensor.vision_unknown_type2022_id2201_alarm_level_5
    state: '255'
  condition:
    platform: state
    entity_id: alarm_control_panel.ha_alarm
    state: armed_away
  action:
    service: alarm_control_panel.alarm_trigger
    entity_id: alarm_control_panel.ha_alarm

- alias: Automation2
  trigger:
    platform: state
    entity_id: alarm_control_panel.ha_alarm
    state: 'triggered'
  action:
    service: script.turn_on
    entity_id: script.light_flash

- alias: Automation3
  trigger:
    platform: state
    entity_id: alarm_control_panel.ha_alarm
    state: 'disarmed'
  action:
    service: script.turn_off
    entity_id: script.light_flash

And here is the script (in configuration.yaml):

script:
  light_flash:
    alias: Light flash on
    sequence:
      - alias: Light Flash On
        service: homeassistant.turn_on
        data:
          entity_id: light.back_porch
      - delay:
          # time for flash light on
          seconds: 1
      - alias: Light Flash Off
        service: homeassistant.turn_off
        data:
          entity_id: light.back_porch
      - delay:
          # time for flash light off
          seconds: 1
      - alias: Loop Light
        service: script.turn_on
        data:
          entity_id: script.light_flash

Also, I keep seeing this error in my homeassistant.log:

16-09-08 20:16:38 homeassistant.components.automation: Please switch your condition configuration to use ‘condition’ instead of ‘platform’.

First of all…for the error in your log did you try actually doing what it says?..just replace “platform” with “condition” in your condition block…like it is stated in the documentation.

Secondly…what is this script? It should be like this…

script:
  light_flash:
    alias: Light flash on
    sequence:
      - service: homeassistant.turn_on
        data:
          entity_id: light.back_porch
      - delay:
          # time for flash light on
          seconds: 1
      - service: homeassistant.turn_off
        data:
          entity_id: light.back_porch
      - service: script.turn_on
        data:
          entity_id: script.light_loop
  light_loop:
    alias: Light flash loop
    sequence:
      - delay:
          # time for flash light off
          seconds: 1
      - service: script.turn_on
        data:
          entity_id: script.light_flash

I did not try it but it should work

1 Like

Thank you

For the log error, I did not. Honestly it just did not look right but heh I’ll try it. For the script, I will definitely try it later to see - Thank You!

Thank you! The loop is now working once the alarm is triggered. I unfortunately have not figured out how to stop it once the alarm is back in ‘disarmed’ status but I will keep working on it.

You just need to script.turn_off those two scripts :slight_smile:
Cheers

That is what I tried, both combining it into 1 automation and splitting it into 2. So far the only thing that has worked is manually turning off the loop script. I’m sure it is something simple I am missing and will figure it out. The important thing is that is works to set and trigger the alarm.

Thank you again!

1 Like

This looks great and I’ll definitely try it out soon.

One question in the meantime: how would you add timer here that the loop continues for example for a minute or until it’s manually stopped?

What you would want for that is a asynchronous operation which is not possible with only scripts if I recall correctly. You could use a input_boolean and 3 scripts for that tho.
Script A:
-> Set input boolean to false, start script B
Script B:
-> Do stuff, call C
Script C:
Do stuff, call B

You would need one further automation which triggers on your input boolean if it has been off for X time.

Hope this helps.

~Cheers

I have an idea that is releated to this that i need help with.
I have a wallswitch that has 3 sates. “1” or “not connected” or “0”. The button is a momentary kind and bounces back to “not connected” and has “1” on one side and “0” on the other.

Im trying to create a series of scripts that uses this switch to toggle the lights on/off and also to have a brightness cycles/setter in it.

so this is the idea:

Script 1:
I get a “1” when I’m “0” then change light state to on.

Script 2:
I get a “1” when I’m “1”, then send me to Script 3

Script 3:
Check which way the value of the light level was last modified, or if the value is 1 or if the value is 255.
If the value is 255 then send me the script 5.
If the value is 1 then send me the script 4.
If last change of value upwards, send me the script 4.
If last change of value downwards, send me to Script 5

Script 4:
Check the current value and increase it by one and send me to Script 3

Script 5:
Check the current value and reduce it by one and send me to Script 3

Script 6:
I get a “1” and Script 3 or Script 4 or Script 5 is started so stop them scripts.

Script 7:
May I get a “0” then tell all the scripts to off and change the state of the lamp to off.

Is this even doable?

That’s getting pretty complex and is the type of task I designed AppDaemon to make a lot easier. Essentially you are trying to implement a complex if/then in multiple scripts - AppDaemon will let you code it in python as regular if/then/else constructs.

2 Likes

Oh sweet! Will try it out! Thank you!

How about this:

input_slider:
  test: {initial: 90, min: 3, max: 255}


automation:
  - alias: Mi Gateway smooth brightness
    trigger:
      - {platform: state, entity_id: input_slider.test}
      - {platform: state, entity_id: script.gw_brightness_worker, from: 'on'}
    condition: 
      condition: template
      value_template: '{{ (states.light.gw.attributes.brightness|int - states.input_slider.test.state|int)|abs > 4 }}'
    action: {service: script.gw_brightness_worker}
 

script:
  gw_brightness_worker:
    sequence:
      - service: light.turn_on
        data_template:
          entity_id: light.gw
          brightness: >
            {% set cur = states.light.gw.attributes.brightness | int %}
            {% set step = 4 %} {% if cur > states.input_slider.test.state|int %} {% set step = -step %} {%endif%}
            {{ cur + step }}
      - delay: {milliseconds: 30}

The slider sets the desired brightness and automation runs the script every time this slider changes and when the script finishes its iteration until actual brightness is almost the same as a slider state.

This is far from the ideal and much more suitable for AppDaemon.
Is there an AppDaemon script which simulates the transition?
I think all the lights that don’t support hardware transition should do software transition if this option is specified in light.turn_on's data.

2 Likes

It seems like the recursive loop is a very elegant solution. Why is not allowing that a good thing?

I have no idea why I said that…So here we are both wondering what past me meant…because having two scripts call each other is really bad if you want to stop the recursive thing happening because you have to stop both scripts.

Only thing I could think of as of right now is a script is allowed only to be run once at any given time (which actually is something I want to be changed) so it would be hard to do that recursively I guess.

~Cheers

1 Like

Thanks, just making sure I wasn’t missing something.

1 Like