Re-run time-based automation if HA is down the first time

I have an automation which runs daily at 1 AM to save a value to a file.

If for some reason (power failure, HA crashes, etc.) it doesn’t run, I’d like to run it again later in the day. It doesn’t really matter what time it runs, because it’s storing a “yesterday” value. But it has to run at some point each day or yesterday’s data will be gone. And it can only run once each day or the data in the file will be duplicated.

Any suggestions would be appreciated!

Perhaps get some ideas from here.

1 Like

That pointed me in the right direction, thanks!!

The trick was to use the “last_triggered” value:

  condition:
    - condition: template
      value_template: "{{ now().strftime('%x') != state_attr('automation.burner_summary','last_triggered').strftime('%x') }}"

The way I read this, I think it won’t run if the last triggered date is today. Then I just set it to be triggered a few times each day. I’ll know tomorrow.

1 Like

Same idea but a little less code.

{{now().day != state_attr('automation.burner_summary','last_triggered').day}}
1 Like

Nice!! I was going to try that, but apparently HA operates at the quantum level.

The last_triggered value is sometimes a string, sometimes a datetime value, depending on whether or not you’ve looked at it. Sort of like Schrödinger’s cat.

Or something. At any rate, you can’t count on it being either a string, or a datetime.

This post was the ah-ha moment.

A few posts later, pnbruckner proved it.

Sure enough, when I ran his code in the template dev page, my other automations showed datetimes, but this one was a string. Later, after lots of futzing around with automations and templates, this one was back to a datetime.

So after a multi-hour lesson on how some of the various components of HA use dates, times and strings, I have something I hope will work:

- id: id_burner_summary
  alias: Burner Summary
  trigger:
  - at: '01:00:00'
    platform: time
  - at: '02:00:00'
    platform: time
  - at: '14:00:00'
    platform: time
  condition:
    - condition: template
      value_template: "{{ now().strftime('%x') != as_timestamp(states.automation.burner_summary.attributes.last_triggered) | timestamp_custom('%D') }}"
  action:
  - data_template:
      message: '{{ now().strftime(''%x'') }},{{ states.sensor.burner_on_yesterday.state
        }}'
    service: notify.burner_summary

I would have gone with “.day” but I couldn’t find the matching value for timestamp_custom. Maybe if the above works reliably I’ll re-visit it and dig up the full documentation on that.

1 Like

%d gives you just the day

Also, change your message to this:

  - data_template:
      message: "{{ now().strftime('%x') }},{{ states.sensor.burner_on_yesterday.state }}"

You can’t use single quotes inside single quotes. Gotta use double outside and single inside or single outside and double inside.

You can’t escape the internal quotes using \ ?

last_triggered can be represented as datetime or string?

Well that’s interesting … and troublesome.

I ran Phil’s code but it returned nothing, indicating none of my automations report last_triggered as string.

You can, but people don’t generally understand what that’s doing so I avoid it on the forums.

1 Like

Yes, @pnbruckner and I believe it’s a bug but the developer insists its correct. :man_shrugging:

Also, if you guys truely want to account for all situations in a template, this works:

{% 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 %}
{{ last_triggered }}

Where last_triggered is now a datetime object you can treat like now(). You may want to remove the {% elif last_triggered == None %} portion and properly handle it instead of setting it equal to now().

Doesn’t this PR correct the regression error? Version 0.89 restored the previous behavior, namely trigger.now is restored to using local time as opposed to UTC.

Which version of Home Assistant are you running?

If they are local, then the last : should be removed and the fmat should contain %z at the end. I always assumed it was not local. I don’t have any automations to check against so I’m just going off the provided timestamp strings.

EDIT: I lied, I have one. It’s stored in UTC, so the above code should work. This contains the string

This also made me realize that all these automations have been off since February…

:man_facepalming: Well, that’s embarrassing. I was thinking .day was day-of-year, not day-of-month. Thanks!!

At the point I wrote that I was so twisted up by all the various syntax rules for all the different components that I was pretty much just trying things until it worked. Which it did, so I left that part alone. I’ll clean it up once I prove the triggers and conditions are working.

There were no strings on any of my automations just before I posted, either. Now my boiler_summary is back to a string.

I’m convinced it’s got something to do with all the different ways I used to display or run it while I was debugging. Something changes it to a string somewhere along the way, and something changes it back. I’ve got no clue what that “something” might be.

It’s pretty easy to prove it changes back and forth. And I’d think, pretty hard to deny that’s a bug!

I haven’t run into that situation yet. I agree it’s best to cover all possibilities. But if it’s ever run once, like just by triggering it manually from the UI, wouldn’t that never happen?

Well, if the automation has never triggered and you restarted the system, it would be none. So yes, it shouldn’t ever be None if it’s triggered at some point. I don’t know if the last triggered is updated via manual triggers.

0.91.4

After reading all that about UTC vs local, I checked by setting up an automation to trigger a few minutes from the current local time. It kicked off as expected. So I’m guessing that fix worked.

It appeared to be, when I triggered it manually.

Yah but how is last_triggered stored for you? UTC or Local?

The example I provided might be wrong because my last triggered was sometime in feb which was an older version.

Me too. I’m running 0.89.1 and confirmed the automation’s last_triggered is in UTC.

Not sure what to make of all this now. CaptTom says he’s running 0.91.4 yet it would appear that sometimes an automation’s last_triggered is assigned a value that cannot be handled as datetime.

My understanding is an automation’s last_triggered attribute, when triggered, is written as a datetime. However, when HA restarts, it is saved and restored as a string. And it will stay a string until the next time the automation is triggered, at which time it will be overwritten as a datetime again.

The PR isn’t about an automation’s last_triggered attribute, which is always in UTC. It’s about the trigger variable, which was originally in HA’s local time zone, was accidentally changed to be in UTC for a while, and then “fixed” by the noted PR to be in HA’s local time zone again.

BTW, there’s a bug in my example template code. It should be:

{% for x in states.automation if x.attributes.last_triggered is not none %}
{{ x.object_id }}:
{{ x.attributes.last_triggered }} {{ x.attributes.last_triggered is string }}
{% endfor %}

Or, if you also want to see the automations that haven’t ever been triggered:

{% for x in states.automation %}
{{ x.object_id }}:
{{ x.attributes.last_triggered }} {{ x.attributes.last_triggered is string }}
{% endfor %}