WTH isn’t there a "queue last" or similar option for script modes?

I am often in a situation where what I want a script or automation mode that is essentially “queue 1 call and keep only the most recent call.” A simple example is a script that sets the brightness of a specific light. If it is called multiple times in succession while still running, the ideal thing would be to finish the current call and then start a new call with only the most recent brightness rather than setting all the settings in between in sequence or, worse, dropping the most recent calls once a queue is filled.

Sometimes “restart” works for this purpose, but sometimes a script has other effects where it would be undesirable to cancel it. The difference between this and a queue of length 1 is that a second call while it’s still running is currently dropped, and I would like that call to replace the old one in the queue. You could generalize this to a “stack,” keeping the most recent n calls (analogous to a queue of length n). I don’t personally have many uses for stacks bigger than 1, but maybe others do, and this would work for my purposes.

[Edit: In a response I created an example which I think makes it clearer; copy/pasted it here.]
Let’s assume I have a script that sets a light to a brightness and then waits 5 seconds. I then call the script 4 times rapidly, in order A B C D, with different brightness (say, 63, 127, 191, 255). My goal would be that A runs to completion, after which D runs to completion, and B and C are dropped. I assume this would be done by holding the most recent call in a single-call buffer, replacing it with a new call when it comes in and the original is still running. So the sequences is:

  1. A starts running, sets brightness to 63, and continues for 5 seconds, during which…
  2. B gets put in the buffer while A is still running.
  3. C replaces B in the buffer while A is still running.
  4. D replaces C in the buffer while A is still running.
  5. A completes, and D immediately runs, setting brightness to 255 (and then sleeps 5 seconds).

And apologies if there’s a way to do this now and I just haven’t found it. Thanks!

Scripts and Automations have a current attribute. You can put that in a condition that requires current to be 1.

I think that should work in your case.

To test you could create a template condition that writes:
{{ is_state_attr('script.<name>','current',1)}}

I guess this you can also use the ‘this’ approach, but I am not sure. So testing by mentioning the actual script is the safest.

The this approach: {{is_state_attr(this.entity_id, 'current',1)}}

1 Like

Thanks for the idea! I’m not quite seeing how this does what I’m hoping to do here. I think adding that condition will simply make it not run if it’s already running, which would be equivalent to the “Single” mode except wouldn’t produce a warning.

Maybe it’s easier if I give an example. Let’s assume I have a script that sets a light to a brightness and then waits 5 seconds. I then call the script 4 times rapidly, in order A B C D, with different brightness (say, 63, 127, 191, 255). My goal would be that A runs to completion, after which D runs to completion, and B and C are dropped. I assume this would be done by holding the most recent call in a single-call buffer, replacing it with a new call when it comes in and the original is still running. So the sequences is:

  1. A starts running, sets brightness to 63, and continues for 5 seconds, during which…
  2. B gets put in the buffer while A is still running.
  3. C replaces B in the buffer while A is still running.
  4. D replaces C in the buffer while A is still running.
  5. A completes, and D immediately runs, setting brightness to 255 (and then sleeps 5 seconds).

I think with the condition, only A runs. But apologies if I’m misunderstanding!

Here is a little PoC Script that runs the first and the last, but not anything in between. I used another script to run the PoC 4 times in a row.

alias: PoC run last in queue
sequence:
  - if:
      - condition: template
        value_template: |-
          {{
             is_state_attr(this.entity_id, 'current',1)
          }}
    then:
      - action: persistent_notification.create
        metadata: {}
        data:
          title: Queue length
          message: "Current length is: {{ state_attr(this.entity_id, 'current') }}"
      - delay:
          hours: 0
          minutes: 0
          seconds: 10
          milliseconds: 0
    else:
      - action: persistent_notification.create
        metadata: {}
        data:
          title: Queue length:I'm not last in line
          message: "Current length is: {{ state_attr(this.entity_id, 'current') }}"
description: ""
mode: queued
max: 10

The result:

2 Likes