Automation trigger based on time remaining of a helper timer

I created a helper timer that is easily set, paused, and otherwise manipulated via service calls. Works great!

I want to trigger other events/automations based on the amount of time remaining while the timer runs. For example, change the light color when there’s 5 minutes left on a 30-minute timer. Can’t figure out how to trigger these. The only options available in the UI are Duration and Restore.

I couldn’t find much info in the documentation, and I’m happy to use yaml if needed. Tried this without success:

platform: state
entity_id:
  - timer.kids_bath_fan_timer
attribute: remaining
to: "00:05:00"

What’s the best way to implement this?

The remaining attribute doesn’t update live, it updates when the timer is pause, cancelled, or finishes. I think the closest you can get (though not super accurate due to how templates based on now() update) is to use a template trigger:

trigger:
  - platform: template
    value_template: |
      {% set t_finish = state_attr('timer.kids_bath_fan_timer','finishes_at') %}
      {{ false if t_finish is none else t_finish | as_datetime - now() <= timedelta(minutes=5) }}

this one’s a tough request (at least for me)… an interesting puzzle on how to do this at all cleanly. i have a way for you, but it’s more complicated and messy than @Didgeridrew 's one liner template…

but template sensors like that only update once at minute, and not necessarily on the minute boundary you may want…

if i had to do this i think i’d create a “5 minute left timer”… and that timer was set each time the main timer was started or restarted… cancelled when the main timer was cancelled or finished. and when stated, set the “5 minute left timer” again:

much easier if you can count on the timer never pausing and restarting… but anyways, here’s what i got for ya:

alias: handle test timer start
trigger:
  - platform: event
    event_type: timer.started
    event_data:
      entity_id: timer.test_timer
  - platform: event
    event_type: timer.restarted
    event_data:
      entity_id: timer.test_timer
condition: []
action:
  - service: timer.start
    target:
      entity_id: timer.five_min_left_timer
    data:
      duration: >
        {{ (strptime( state_attr('timer.control4_heartbeat_received',
        'remaining'), '%H:%M:%S') - timedelta(minutes=5)).time()}}

and this:

alias: handle test timer stop events
trigger:
  - platform: event
    event_type: timer.finished
    event_data:
      entity_id: timer.test_timer
  - platform: event
    event_type: timer.cancelled
    event_data:
      entity_id: timer.test_timer
  - platform: event
    event_type: timer.paused
    event_data:
      entity_id: timer.test_timer
condition: []
action:
  - service: timer.cancel
    target:
      entity_id: timer.five_min_left_timer

Didn’t realize this would be so complicated. Yikes!

For full context, I’m looking to DIY a fancy bath fan timer using a Zooz ZEN32 scene switch Zooz 800 Series Z-Wave Long Range Scene Controller Switch ZEN32 800LR - The Smartest House . The four scene buttons will set the fan to run for 5, 10, 15, or 30 minutes. And I want the scene button LEDs to update as it progresses.

For example, when there’s a 30min request, we illuminate the 30min button and leave the others off. When there’s 15min left on the timer, the 15min button’s LED should turn on and the others turn off. And so on for the 10- and 5-minute buttons.

@Digeridrew might be on the right track by focusing on the finishes_at time, assuming the now() timedeltas are precise enough.

@armedad ‘s solution also gives me an idea. The desired function here will always be in 5-minute blocks between 5 and 30min. So all I need to do is define the number of iterations through a 5-minute loop, and perhaps update the number of iterations with new inputs as necessary.

Gonna noodle on these for a bit.

now() and timedeltas are precise for when they are called. the issue you’re going to have is that the sensors you write will update only on minute granularity. so it can be in the extreme 59 seconds off. but averaged 30secs off. if that’s ok, then his method is definitely simpler!

if you think you will always only start and stop, then you can simplify my approach a bit.