Understanding automations with time delays and how to control them

Thanks for the great info, this is very helpful. The “single” vs. “restart” was the clue to getting my automation to work properly. A couple things I noticed:

  1. Originally I had one automation that detected a button press, and then used the “choose” feature of an action and checked the “device” - the light - to see if it was off, and if so run the timed cycle.

  2. The other choice in the action was if the light (device) was on, then turn it off.

The problem with the above was that if I pressed the button to turn the light on, then a minute later pressed the button to turn the light off, that worked. But pressing the button a third time to restart the timer caused the light to stay on indefinitely.

I recalled that if you want to see if something is “on or off” you check state not device. When I changed the condition to check state (on or off) the whole thing works properly. Not sure why that would make a difference but could someone confirm that if you want to have a condition based on the state of a device that you should check state and not the device itself?

Finally, I thought this was cool for the delay:

- delay: '{{ range(10,30)|random }}' gives a random 10-30 second delay.

If you’re interested, post your automations and we can review them and make suggestions.

Yes, I will actually because what I thought was the issue wasn’t. The light stayed on and never went off after the 3rd button press from my above scenario. One thing to ask though – is there a timeout for automations? I swear this all worked when I set my timer to 1 minute, but then when I made it the full 30 minutes the script failed (it never turned the device off after 30 mins.)

Note, I simplified the scenario when originally posting. The actual script is to run an air filter in a bedroom for 30 minutes. This is done manually when the “cat thinks outside of the box” if you know what I mean :slight_smile:

Anyway, here’s the script and I’m open to thoughts:

alias: 'Master Bedroom: Air filter 30 minutes'
description: ''
trigger:
  - device_id: b251a3bee8687b95b2fff6d
    domain: deconz
    platform: device
    type: remote_button_short_press
    subtype: turn_on
condition: []
action:
  - choose:
      - conditions:
          - condition: state
            entity_id: switch.mbr_air_filter_on_off
            state: 'off'
        sequence:
          - type: turn_on
            device_id: d8117da0fbe2652aa5d5c
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
          - delay:
              hours: 0
              minutes: 30
              seconds: 0
              milliseconds: 0
          - type: turn_off
            device_id: d8117da0fbe2652aa5d5c
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
      - conditions:
          - condition: state
            entity_id: switch.mbr_air_filter_on_off
            state: 'on'
        sequence:
          - type: turn_off
            device_id: d8117da0fbe2652aa5d5c
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
    default: []
mode: restart

Create a counter, increment on press, use switch case to set light modes, on last press in cycle, reset counter and programmatic call switch press event to start cycle again. If you want timed lights start a timer, separate automation for timer end to shut off lights and reset counter. The 2 automation setup with timer works great with motion sensors, you can even change timer duration in the automation and for different time lengths based on logic. Have multiple on sensors and automation call same timer with 1 off automation, etc…

I’m wondering if I am running into this issue and that’s why my 30 minute timers seem to fail. I might have been working on another automation while waiting for the 30 minute test to complete. If the automations were reloaded when I finished working on another one, I assume any that were pending a delay were stopped.

my 5 cents bro

I dont like using delay I think the logic get lost

I use timer

some happen turn timer ON

The last action in a automation

  action:
    .......
    - service: timer.start
      data:
        duration: '00:10:00'
      target:
        entity_id: timer.hangout

we can create a automation when finish

- id: 8e10272d-5447-433f-b7f8-f267eaa66fee
  alias: "Timerstop"
  trigger:
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.hangout
  action:
# do the Finished logic

we can check the state of it
in a condition

some happen BUT is the timer running

  condition:
    condition: and
    conditions:
      - condition: state
        entity_id: timer.hangout
        state: active

do a action

ie
washing get done timer starts and wife not home alexa tell me to hang it every 10 mins
when timer finish it start again ( one automation) until I open the washing door then time cancel (other automation)

Create an input_datetime that stores date and time. In the following example, I named it:

input_datetime.mbr_air_filter_on_off

Here’s the suggested automation. Its 30-minute time period can survive a restart because it employs a Time Trigger instead of a delay.

alias: 'Master Bedroom: Air filter 30 minutes'
description: ''
trigger:
  - device_id: b251a3bee8687b95b2fff6d
    domain: deconz
    platform: device
    type: remote_button_short_press
    subtype: turn_on
  - platform: time
    at: input_datetime.mbr_air_filter_on_off
condition: []
action:
  - variables:
      switch: switch.mbr_air_filter_on_off
      is_on: "{{ is_state(switch, 'on' }}"
  - choose:
      - conditions: '{{ trigger.platform == 'device' and not is_on }}'
        sequence:
          - service: switch.turn_on
            target:
              entity_id: '{{ switch }}'
          - service: input_datetime.set_datetime
            target:
              entity_id: input_datetime.mbr_air_filter_on_off
            data:
              timestamp: "{{ (now() + timedelta(minutes=30).timestamp()) | int(0) }}"
      - conditions: '{{ trigger.platform in ['device', time'] and is_on }}'
        sequence:
          - service: switch.turn_off
            target:
              entity_id: '{{ switch }}'
    default: []
mode: single
1 Like

OK, thank you for the date/time option script. I don’t fully understand it but I’m willing to give it a try. In the meantime, I am playing with a timer for this for the experience and also because it seems that timers survive automation restarts (but not server restarts which I’m less concerned about).

Here’s my attempt at making this work, however, there’s a bug in it that I can’t seem to find. The automation runs as expected, press the button and the timer starts and the filter comes on, press it again and the air filter turns off and the timer stops.

The problem lies with when the timer finishes (counts down to 0:00) this script seems to start it again and the filter never turns off. The second trigger is what calls this script again, and option #1 should run since the state of the timer is “finished” – although that option never gets picked based on the trace of the script. I’m going to guess that the event that fires when the timer finishes triggers this script, but by the time the “choose” action is run the timer is “idle” not “finished.” But I can’t prove that theory.

So I made another automation that is triggered by the event and it just turns off the air filter. This two-script solution works (after I remove the event trigger for the finished timer from the first one).

I’d like to understand why the single script here isn’t working though:

alias: 'Master bedroom: Air filter 30 minutes (timer)'
description: ''
trigger:
  - device_id: b251a3bee8687b95b2fff6d
    domain: deconz
    platform: device
    type: remote_button_short_press
    subtype: turn_on
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.mbr_air_filter
condition: []
action:
  - choose:
      - conditions:
          # timer finished, just turn off filter
          - condition: state
            entity_id: timer.mbr_air_filter
            state: finished
        sequence:
          - type: turn_off
            device_id: d8117da0fbe2652aa5d5c7d
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
      - conditions:
          # filter is off so turn it on and start timer
          - condition: state
            entity_id: timer.mbr_air_filter
            state: idle
        sequence:
          - type: turn_on
            device_id: d8117da0fbe2652aa5d5c7d
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
          - service: timer.start
            data:
              duration: '00:01:00'
            target:
              entity_id: timer.mbr_air_filter
      - conditions:
          # button pressed while timer is active, turn fan off and stop timer
          - condition: state
            entity_id: timer.mbr_air_filter
            state: active
        sequence:
          - type: turn_off
            device_id: d8117da0fbe2652aa5d5c7d
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
          - service: timer.cancel
            target:
              entity_id: timer.mbr_air_filter
    default: []
mode: single

I figured it out! It now works perfectly and I don’t need a second event to turn off the filter. It’s all done in this one event:

  1. Press the button to start the 30 minute timer and turn on the air filter.
  2. If I change my mind, press the button to turn the filter off and cancel the timer.
  3. After 30 minutes the air filter turns off automatically.

So here’s some new things I learned here:

  1. The event part of the trigger (when the timer finishes) can be given a “trigger_id”.
  2. In the action → choose section I can look for this trigger_id and act upon it (turn off the filter).
  3. I also learned that in the action → choose options, the first one matches starting at the beginning.

For #3 - I had that option last (trigger_id matches from the event) and it didn’t work, most likely because one of the other options could also match. Once I moved it first everything works perfectly!

Note the two triggers to start this automation, either a button press or the timer finishes.

Here’s the final automation:

alias: 'Master bedroom: Air filter 30 minutes (timer)'
description: ''
trigger:
  - device_id: b251a3bee8687b95b2fff6d7
    domain: deconz
    platform: device
    type: remote_button_short_press
    subtype: turn_on
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.mbr_air_filter
    id: timer_complete
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: timer_complete
        sequence:
          - type: turn_off
            device_id: d8117da0fbe2652aa5d5c7
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
      - conditions:
          - condition: state
            entity_id: timer.mbr_air_filter
            state: idle
        sequence:
          - type: turn_on
            device_id: d8117da0fbe2652aa5d5c7
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
          - service: timer.start
            data:
              duration: '00:30:00'
            target:
              entity_id: timer.mbr_air_filter
      - conditions:
          - condition: state
            entity_id: timer.mbr_air_filter
            state: active
        sequence:
          - type: turn_off
            device_id: d8117da0fbe2652aa5d5c7d
            entity_id: switch.mbr_air_filter_on_off
            domain: switch
          - service: timer.cancel
            target:
              entity_id: timer.mbr_air_filter
    default: []
mode: single
2 Likes

It’s still vulnerable to a Reload Timers (which is a required operation if you ever create another timer and it will happen automatically if you create the new timer via the UI) and, of course, a restart. The version I posted above survives a restart and is more concise; it’s simply a more efficient design pattern.

However, if you are adamant about using a timer, you might be interested in implementing the following system for restoring active (and paused) timers after a restart:


NOTE

The following simple tutorial explains the process of transforming a simple automation, vulnerable to restarts, into one that can perform the correct action even after a restart:

1 Like

Actually i think its very strange in HA that you cant do the most common task like a “delay” on a switch very easy. If you need to write 20 lines of code to do a simple “delay” there must be something wrong in HA. All time and delay related tasks should be very easy to do.

Implementing a time delay can vary from a single line to multiple lines; it depends on the application.

1 Like

Hello,
I’m pretty lost.
I would like to do the same thing: push a Hue button will put my radiator in preset_mode comfort for 30min, and come back to preset mode eco. The automation works, but stops after the delay of 30min.

I’ve created an input datetime (input_datetime.smart_button_on_radiateur_sdb), but I don’t know how to use it in your automation.

My current automation:

alias: "[SDB] Smart button hue - ON seche serviette SDB"
description: ""
trigger:
  - device_id: 7e5cf7e64f980dad2bef72477b8773d1
    domain: hue
    platform: device
    type: initial_press
    subtype: 1
    unique_id: 7c729056-ec48-46ef-b051-df22fbaa0aa2
condition: []
action:
  - service: climate.set_preset_mode
    target:
      entity_id: climate.radiateur_sdb
    data:
      preset_mode: comfort
  - delay:
      hours: 0
      minutes: 30
      seconds: 0
      milliseconds: 0
  - service: climate.set_preset_mode
    data:
      preset_mode: eco
    target:
      entity_id: climate.radiateur_sdb
mode: single

Use dmcentire’s example.

It seems very complicated for me in regards of what you have made that should be used for my case:

alias: 'Master Bedroom: Air filter 30 minutes'
description: ''
trigger:
  - device_id: b251a3bee8687b95b2fff6d
    domain: deconz
    platform: device
    type: remote_button_short_press
    subtype: turn_on
  - platform: time
    at: input_datetime.mbr_air_filter_on_off
condition: []
action:
  - variables:
      switch: switch.mbr_air_filter_on_off
      is_on: "{{ is_state(switch, 'on' }}"
  - choose:
      - conditions: '{{ trigger.platform == 'device' and not is_on }}'
        sequence:
          - service: switch.turn_on
            target:
              entity_id: '{{ switch }}'
          - service: input_datetime.set_datetime
            target:
              entity_id: input_datetime.mbr_air_filter_on_off
            data:
              timestamp: "{{ (now() + timedelta(minutes=30).timestamp()) | int(0) }}"
      - conditions: '{{ trigger.platform in ['device', time'] and is_on }}'
        sequence:
          - service: switch.turn_off
            target:
              entity_id: '{{ switch }}'
    default: []
mode: single

So don’t use it. Try dmcentire’s example.

Too complicated for me, :disappointed: my action are preset mode, no on off. And I don’t understand his automation and all sequences

I tried this, but I got an error with the input_datetime.set_datetime function in the action section:

Error rendering data template: UndefinedError: 'datetime.timedelta object' has no attribute 'timestamp'

Something changed in HA syntax?

There are missing parentheses in that example’s template. It would appear you are the first person to detect that error in over 2 years!

Change this:

{{ (now() + timedelta(minutes=30).timestamp()) | int(0) }}

to this:

{{ ((now() + timedelta(minutes=30)).timestamp()) | int(0) }}

So I revisited my automation and I guess I don’t do any of what was originally sorted out in this thread. Here’s my current “run the air filter for 30 mins” code, along with the ability to stop it with an additional button press. I just use a timer to countdown the time.

alias: "Master bedroom: Air filter 30 minutes"
description: ""
trigger:
  - platform: device
    domain: mqtt
    device_id: 80037f3661ddac4
    type: action
    subtype: 4_single
    discovery_id: action_4_single
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.mbr_air_filter
    id: timer_complete
condition: []
action:
  - choose:
      - conditions:
          - condition: trigger
            id: timer_complete
        sequence:
          - type: turn_off
            device_id: ef36fa9d247036d3
            entity_id: switch.tasmota_switch_relay_1
            domain: switch
      - conditions:
          - condition: state
            entity_id: timer.mbr_air_filter
            state: idle
        sequence:
          - type: turn_on
            device_id: ef36fa9d247036d3
            entity_id: switch.tasmota_switch_relay_1
            domain: switch
          - service: timer.start
            data:
              duration: "00:30:00"
            target:
              entity_id: timer.mbr_air_filter
      - conditions:
          - condition: state
            entity_id: timer.mbr_air_filter
            state: active
        sequence:
          - type: turn_off
            device_id: ef36fa9d247036d3
            entity_id: switch.tasmota_switch_relay_1
            domain: switch
          - service: timer.cancel
            target:
              entity_id: timer.mbr_air_filter
            data: {}
    default: []
mode: single