Automation based on template trigger only activated once

I have the following automation that I expected to toggle the light on my desk every minute

alias: Test time trigger
description: ""
trigger:
  - platform: template
    value_template: |2-
       {% set t = now() %}
       {{ not t.second }} 
condition: []
action:
  - type: toggle
    device_id: c4792938aa12840e6dbe8d4d9cf6d3a8
    entity_id: switch.desk_light
    domain: switch
mode: single

However it only toggled the light the first time and not on subsequent minutes. When viewing the automation in the visual editor, every minute a blue bar would appear above the trigger saying TRIGGERED but the action does not occur.

Is there some configuration to specify that the automation should repeat? What have I overlooked?

I realise there are simpler ways to trigger every minute but my actual needs are more complex - this is just a test of using timers in templates

What I actually want is a trigger for my kettle at 6:30 Monday, 6:55 Tuesday, 6:30 Wed, 6:55 Thu, 6:30 Fri, not at all Sat/Sun. Is there a way I can pass these times as configuration to a template? Is there a better way of doing this than a template trigger?

I realise this is technically 2 questions so happy for answers to just the first :slight_smile:

Why not just a time trigger?

description: ""
mode: single
trigger:
  - platform: time
    at: "06:30:00"
  - platform: time
    at: "06:55:00"
condition: []
action:
  - choose:
      - conditions:
          - condition: time
            weekday:
              - mon
              - wed
              - fri
            before: "06:35:00"
        sequence:
          - service: switch.turn_on
            data: {}
      - conditions:
          - condition: time
            weekday:
              - tue
              - thu
            after: "06:50:00"
        sequence:
          - service: switch.turn_on
            data: {}

Yes, that’s pretty neat and looks like it would definitely work. It hadn’t occurred to me that you could layer the trigger and the conditions like that.

However it’s not very concise as the time needs to be included in both the trigger and the conditions (giving a maintenance overhead, albeit a small one and some unnecessary complexity)

As a Python developer I can see myself using (abusing?) the template triggers extensively so I would still like to know why my original example only triggered once

Because template triggers fire when the template changes from false to true, and templates with now() in them evaluate at the top of each minute.

So first time you ran it, it is likely that the seconds were non-zero, so the template was false. Next run would have been evaluated at the top of the minute, so {{ not 0 }} is true, trigger fires once.

Subsequent runs are also at 0 seconds, template remains true and does not fire again.

1 Like

Yep that makes perfect sense. I suspected it was some implicit behaviour I wasn’t aware of (I’m new to this). Thanks!

So… instead of making a code that just triggers when it should your idea is to trigger every minute.

This is not programming, this is configuration. You do not win anything by making things concise and complex.

DRY version:

alias: Switch kettle on in the morning
id: 40befea9-7291-4ce6-b3ea-7e41293f6abf
trigger:
  - platform: time
    at: "06:30:00"
    id: mwf
  - platform: time
    at: "06:55:00"
    id: tt
condition:
  - or:
    - "{{ trigger.id == 'mwf' and now().weekday() in [0,2,4] }}"
    - "{{ trigger.id == 'tt' and now().weekday() in [1,3] }}"
action:
  - service: switch.turn_on
    entity_id: switch.YOUR_KETTLE

Make a Schedule entity and configure it with the desired times and days. Then create a simple automation that turns on the kettle whenever the schedule is on.

alias: example 
trigger:
  - platform: state 
    entity_id: schedule.kettle
    from: 'off'
    to: 'on'
condition: []
action:
  - service: switch.turn_on
    target:
      entity_id: switch.kettle

You can can create a Schedule entity either via the UI (as a Helper) or via YAML.

My original solution was to check that I understood how template timers work. It did its job as I didn’t understand them, it took @Troon to set me straight. This is I reckon the most concise solution to my problem

alias: Test time trigger
trigger:
  - platform: template
    value_template: |2-
       {% set t = now() %}
       {% set config = [[0, 6, 30], [1, 6, 55], [2, 6, 30], [3, 6, 55], [4, 6, 30]] %}
       {% for item in config if t.weekday() == item[0] and t.hour == item[1] and t.minute == item[2] %}True{% endfor %}
  - service: switch.turn_on
    entity_id: switch.YOUR_KETTLE

However @Troon solution is far more readable and IMHO the better solution - @Hellis81 I’ll agree with you concise isn’t always better :slight_smile:

The disadvantage of your approach (maybe only from an elegance point of view unless your system is weak or busy) is that the system is evaluating that template at the top of every minute in order to run four times per week — 0.04% efficient. Mine and @Hellis81’s trigger 14 times per week (28% efficient), and as usual @123 wins with a 100% efficient once-a-day trigger that doesn’t fire at the weekend if you set the schedule up correctly.

Yep that’s a fair point. I don’t think a time calculation trigger once a minute would tax any real world system (even an arduino) but, seeing as we are just point scoring 3 working solutions, I’m happy to concede the concise solution is neither readable nor efficient.

If we’re golfing, don’t care about efficiency, and if you have sensor.time set up:

trigger:
  - platform: template
    value_template: "{%set t=states('sensor.time')%}{{now().weekday()in{t:[],'06:30':[0,2,4],'06:55':[1,3]}[t]}}"

Updated shorter version taking advantage of the “even days” situation:

trigger:
  - platform: template
    value_template: "{%set w=now().weekday()%}{{states('sensor.time')==['06:30','06:55'][w%2]and w<5}}"

Note that your template above only produces True or nothing — not sure that’ll work.

I guessed Home Assistant follows the python approach of if it ain’t ‘true’ it’s false - and it does. It’s a shortcut but that is the essence of golf, right? :wink:

Speaking of which, I don’t think I can squeeze it any more than your last solution - which is also more efficient as it uses hashing instead of a brute force loop so it’s most likely O(1) instead of O(n)

hat

I can :smiley:

trigger:
  - platform: template
    value_template: "{{now().timestamp()//300%2016 in[83,366,1230,1523,1806]}}" 

Definitely not readable, but it’s fun to think about all the different ways to solve this. This one occurred to me walking home from the supermarket.

Divide the UNIX epoch timestamp by 300 to get number of five minute blocks since the start of 1970. Take the modulo of 2016 (number of 5 min blocks in a week) which gives you an offset from an arbitrary starting point which is the same each week. Then look for one of the magic numbers corresponding to the days / times you want.

EDIT: I think daylight saving time will mess this up, and there’s no obvious way around that. If you live somewhere that doesn’t do summer / winter time, it’ll be fine.

A very short swing indeed. Repeated every minute until it eventually lands a ‘hole in 1440’. :wink:

1 Like