Find the error in: automation last_triggered with now() or timestamp templates

No, I am aware of that, was simply trying to give another example of the use of the now() template.

Lol, never heard of that before either … will look that up too :wink:

so, one more question then before I take that extra class: if I wouldn’t use state_atrr() but states.entity_id.attributes.last_triggered, would that go?

As a matter of fact it was designed like that…to be populated after getting called, and stays like that during runtime of course. I havent run into operational issues. I only noticed just now, because of some change in the logic of my setup… So you’re right.

Also, this should work too for a datetime object instead of default()

{% set last_triggered = state_attr('automation.low_light__hallway_motion_sensors','last_triggered') or now() %}
{{ (now() - last_triggered).total_seconds() > 120 }}

Ive tried that too, but it doesn’t evaluate to a true or false in the dev-template

nor does:

{% set last_triggered = state_attr('automation.low_light__hallway_motion_sensors','last_triggered') or now() %}
{{ (now() - last_triggered).total_seconds() > 120 }}

all empty in the dev_template

and

error:
plate>", line 2, in top-level template code TypeError: unsupported operand type(s) for -: 'datetime.datetime' and 'str'

second one resolves to false for me.

That means that last_triggered is not a datetime object, but a string. So you need to convert the string into a datetime object.

EDIT: Just confirmed, its a string. Gotta convert it using strptime

well, that’s not very ‘easy’ anymore… compared to my original timestamp template

  {{ (as_timestamp(now()) - 
      as_timestamp(state_attr('automation.low_light__hallway_motion_sensors','last_triggered')) 
      | default(0) | int > 120) }}

and I cant get that to show up true of als either.

Have some template using strptime doing their job:

          {{ (now().strftime("%d-%m-%Y")) == 
          (as_timestamp(strptime(states('sensor.trash_gft'), "%d-%m-%Y")) - 
          (1 * 86400 )) | timestamp_custom("%d-%m-%Y") }}

but they all use as_timestamp to start with, while I would like the now()…bit lost really.

to explain a bit better why I was trying to find the issue, heres another automation that works just perfectly, and has the exact same format:

  - condition: template
    value_template: >
      {{ (now() - 
          state_attr('automation.boiler_switch','last_triggered')|default(0)).total_seconds() > 240 }} 

have a look:

somehow the low_light automation throws in the T in the last_triggered, where the other don’t…
Would you know why that is the case?

After manually triggering the automation the T disappears and I get an evaluation, rendering the same format:

you must be getting lucky. That’s still a string

do this and see what you get

{{ state_attr('automation.boiler_switch','last_triggered') * 2 }}

I bet your result will be the date&time twice. Meaning its a string. So… the proper way to do this is:

{% set dt = strptime(state_attr('automation.boiler_switch','last_triggered')[:-6],"%Y-%m-%dT%H:%M:%S.%f")

That will return a timestamp in utc.

in fact it doesnt…

while:

Well, it looks like that one is a datetime object. Not sure why they are different. Anyways, if you see a T in your return or it is multiplied by 2 as in you see the date twice, it’s a string. You can also just check the type

{{ state_attr('automation.boiler_switch','last_triggered') is string }}

apparently they are not. It is a matter of being triggered or not, and hence getting set. at startup this is the situation:

after triggering manually (the set conditions aren’t yet met):

so, I need a safeguard for the case the automation hasn’t been triggered yet. And that s why I had the default(0) in there, but that obviously isn’t correct.
Id hate to have it triggered at startup , simply for ‘hacking’ this, I want the automation template to be correct in itself.

What would you do? Other than use the as_timestamp or Find the error in: automation last_triggered with now() or timestamp templates - #4 by petro? Can I take out the default(0) without pain. Seems not to hurt when triggered already, and not to do anything if not…

I need to fix both. The boiler switch seems to behave alright, but it is saved by the fact it triggers on the binary_sensor.workday_sensor, which is set on each startup, so the automation is triggered automatically… I think.

Edit triggering on workday cant be it. Ive added that to the automaton, without result, as I have done with all triggers of the boiler_switch… what is happening here? It keeps saying it never got triggered, even after adding the home assistant startup event… only a manual trigger causes it to showup in the dev-template.

So, I would check to see if it’s a string inside the template. If so convert it. I’d also check to see if it’s None, then just use now(). And lastly assume it’s a datetime object.

{% set last_triggered = state_attr('automation.boiler_switch','last_triggered') %}
{% if last_triggered is string %}
{% set last_triggered = strptime(last_triggered[:-6],"%Y-%m-%dT%H:%M:%S.%f") %}
{% elif last_triggered == None %}
{% set last_triggered = now() %}
{% endif %}
{{ (now()-last_triggered).total_seconds() > 120 }}

That should always work. And if for some reason you need to add another elif, you can pretty easily. Just always overwrite last_triggered and you’ll be good.

All this to avoid using as_timestamp(now())?

“Ease” :wink:

as_timestamp() would have the same issue. In fact, as_timestamp would only affect the last line.

{{ (as_timestamp(now())-as_timestamp(last_triggered)) > 120 }}

Yep, but couldn’t resist some ribbing though! :slight_smile:

1 Like

HI, and thanks again!

this does evaluate to true, when my automation has been triggered. Then again, my own template

        value_template: >
          {{ (now() - 
              state_attr('automation.low_light__hallway_motion_sensors','last_triggered')).total_seconds() > 120 }} 

does too. It doesnt at startup. NO return:

individual test:

It seems to boil down to the quest for the answer why my boiler automation does populate the last_triggered attribute and why the low_light automation doesn’t.
I use restore state for automations, and both are ‘on’.

couldn’t it be, the last_triggered only gets populated if and when the automation truly gets to the action part? I mean, if it is stopped during the condition section, it has in fact been triggered, but no action follows. Would the last_triggered be set in that case? Ive always assumed it would, but maybe this is an edge case ?

just for summarizing the issue:

this works fine:

        value_template: >
          {{ as_timestamp(now()) - 
              as_timestamp(state_attr('automation.low_light__hallway_motion_sensors','last_triggered')) >120 }}

while this doesnt do anything

      - condition: template
        value_template: >
          {{ (now() - 
              state_attr('automation.low_light__hallway_motion_sensors','last_triggered')).total_seconds() > 120 }} 

haha, keep that ribbing, probably rubbing, coming…
while in the act, please think along ? :wink:
appreciated though, love some positive sarcasm

Cringe-worthy …

2 Likes

please let me get back on this automation @petro
Ive given up using the now() variant when needing the last_triggered attribute. It simply would only work if triggered once before… the as_timestamp variant works solidly.

Still have a second issue though.

Ive setup the automation to trigger every 5 minutes:

    trigger:
      - platform: time
        minutes: '/5'
        seconds: 00

I would expect the following template to max on 5 minutes, ie 300, because of that:

      {{ as_timestamp(now()) - 
          as_timestamp(state_attr('automation.low_light__hallway_motion_sensors','last_triggered')) }}

but it only records the timestamp of the automation being actually executed:

is that to be expected? Or does it mean my trigger isn’t working.

could be the trigger is somewhat magical, because I tested another variant with this trigger:

trigger:
  - platform: time
    minutes: '/1'

and it triggered each second…

must add this system is on 84.3 so the new time_pattern isn’t yet needed.

Update

thought id try something that has always lingered in my mind after @NotoriousBDG shared his thoughts on another automation technique: put all conditions in the action part. This was mainly to be able to test the conditions.

I can confirm this also actually updates the last_triggered attributes correctly now. Apparently the last_triggered is in fact last_run, or last_came_into_action…

anyways, extra note to my self: when in need for an automation last_triggered template in an automation, have the conditions set in the action part, so one can truly work with the last_triggered attribute, not depending on the actual full actionability of the automation conditions…

it also enables the possibility using now(), with which I started this thread. So it all boils down to HA/the automation not setting the attribute last_triggered before it arrives at the action part. Which is a real architectural issue imho.

Yeah, once you go into the action section, the “last_triggered” updates. Guilty of the same mistake a few days ago :sweat_smile:

Sorry if I misunderstood your code and necroposting, but the searcher led me here when trying to figure out why my | default(0) doesn’t work for nested as_timestamp(state_attr(<stuff>))

{{ as_timestamp(state_attr("automation.podsumowanie_grzalka_fotowoltaika", "last_triggered") | default(0)) }}

Well, the issue was, as_timestamp() doesn’t like integers, so you have to provide a date format. A foolproof way of getting 0 out of that, regardless of your timezone, is to use or "1970-01-01T00:00:00+00:00" I also tried to use default("1970-01-01T00:00:00+00:00") but no dice. I spent way too much time on this, so I hope it helps another poor soul.

{{ as_timestamp(state_attr("automation.podsumowanie_grzalka_fotowoltaika", "last_triggered") or "1970-01-01T00:00:00+00:00") }}