Value Template Trigger not executing as expected

Preface: I have an automation that runs from midnight to 5am hourly to turn off our TVs. I have it run hourly because sometimes someone wakes up and may turn on a TV and this will turn them back off (I can think of a few other ways to handle this, but this is how I’m doing it for right now).

Anyways, I have another trigger on that automation that 10 minutes before the TVs turn off, it sends a notification to the TVs. This works for all time slots (1am, 2am, 3am, 4am, and 5am), except for midnight. I’ve tried coding aroudn this and according to the template tester, it should fire correctly at 23:50, but I never get a trace for that time slot.

Here is the code


platform: template
value_template: >
  {% set rightNow = now() %}

  {% set startTime = today_at(states('input_datetime.turn_off_tv_time')) -
  timedelta(minutes=10) %}

  {% set endTime = today_at('5:00') %}

  {% if startTime + timedelta(days=1) == rightNow %}
    {% set startTime = startTime + timedelta(days=1) %}
    {% set endTime = endTime + timedelta(days=1) %}
  {% endif %}


  {{ rightNow >= startTime 
    and rightNow <= endTime
    and rightNow.minute == startTime.minute }}
id: Notify TVs will be turning off

I’m thinking tha the IF is not working as expcted, but like I said, if I test it in the template tester it works. This:

{% set rightNow = today_at('23:50') %}
{{ rightNow }}
{% set startTime = today_at(states('input_datetime.turn_off_tv_time')) - timedelta(minutes=10) %}
{{ startTime }}
{% set endTime = today_at('5:00') %}
{{ endTime }}
{% if startTime + timedelta(days=1) == rightNow %}
  {% set startTime = startTime + timedelta(days=1) %}
  {{ startTime}}
  {% set endTime = endTime + timedelta(days=1) %}
  {{ endTime }}
{% endif %}
{{ rightNow >= startTime 
  and rightNow <= endTime
  and rightNow.minute == startTime.minute }}

returns this:

2024-05-31 23:50:00-04:00

2024-05-30 23:50:00-04:00

2024-05-31 05:00:00-04:00

  
  2024-05-31 23:50:00-04:00
  
  2024-06-01 05:00:00-04:00

True

So this says that at 23:50, it should return true and fire, but it does not.

I also have an issue with the 5am run to turn off the TVs not working as well, but I’ll save that one for after I fix this one as it’s a different template and most the time the TVs are off at 5am anyways.

You could use a time trigger instead of a template trigger.

platform: time
at:
  - "23:50:00"
  - "00:50:00"
  - "01:50:00"
  - "02:50:00"
  - "03:50:00"
  - "04:50:00"
{% set rightNow = now() %}
{% set startTime = today_at(states('input_datetime.turn_off_tv_time')) - timedelta(minutes=10) %}
{% set endTime = today_at('5:00') %}
{{ false if rightNow.minute != startTime.minute
else (startTime <= rightNow < today_at('23:59') or endTime > rightNow) }}

FWIW, I use a similar automation and just use a list of times like @atlflyer suggested above… However, my automation triggers on the hour then employees a Wait for Trigger with a timeout so users can kill or confirm the shutdown.

The reason I"m doing it the way I am is the start time can change based on a helper. I do agree that is a simpler approach though I might have to consider.

Thanks. Either way I’m still curious why the template doesn’t appear to work when it works in the template tester. I’m wonder if the IF statement is wrong or not being handled correctly.

{% if startTime + timedelta(days=1) == rightNow %} will only be true for 1 millisecond exactly one day after startTime… you would need to compare the dates not the full datetime objects.

If you need something more general than my previous post, which only works for spans that cross midnight, you could use something like:

{% set rightNow = now() %}
{% set startTime = today_at(states('input_datetime.turn_off_tv_time')) - timedelta(minutes=10) %}
{% set endTime = today_at('5:00') %}
{% if rightNow.minute != startTime.minute %}
  false
{% elif (endTime - startTime).days < 0 %}
  {{ endTime > rightNow or rightNow >= startTime }}
{% else %}
  {{ endTime > rightNow >= startTime }}
{% endif %}

Now that makes sense. I’m not sure why I didn’t think about ms and that makes complete sense. I’ll check our your suggestion and see how that goes. Thanks!

BTW, I ended up with this, which basicaly just makes sure that “now” and the start time are within the same minute.

{% set rightNow = now() %}
{% set startTime = today_at(states('input_datetime.turn_off_tv_time')) - timedelta(minutes=10) %}
{% set endTime = today_at('5:00') %}
{% if rightNow - (startTime+ timedelta(days=1)) < timedelta(minutes=1) %}
  {% set startTime = startTime + timedelta(days=1) %}
  {% set endTime = endTime + timedelta(days=1) %}
{% endif %}
{{ rightNow >= startTime 
  and rightNow <= endTime
  and rightNow.minute == startTime.minute }}

The important part is here:

{% if rightNow - (startTime + timedelta(days=1)) < timedelta(minutes=1) %}

I’m sure this is a more elegant way of doing this, but this allows me to control the start time via a helper (which my wife appreciates)

edit: this also explains why my script misses the 5am slot, because if it’s 1s past 5am it will be false. I’ll be using similar logic to fix that one.

That is what both my examples above do, just from the other direction…

Since 98% of the “now” minutes aren’t going to be equal to the “start” minute, I used that as a sort-of guard clause so the template can process just the minimum data most of the time.