Only allow automation to trigger once a day?

To ensure an automation only executes once for any given day, simply use the following Template Condition.

condition:
  - "{{ state_attr(this.entity_id, 'last_triggered').date() < now().date() }}"
5 Likes

Good to know, thanks! I’ll implement this from now on :slight_smile:

Great, thanks for that. Do you have a solution if I want to retrieve the same automation once a day for two time slots?
To example:

  1. time slot 05:00 - 06:30 for me
  2. time slot 06:30 - 07:30 for my wife

I’m using the following template as a condition to see if the automation already has run that day. It basically converts the last triggered attribute to a y/m/d string and compares it to today’s date converted to a y/m/d string. This removes the remaining details from the date attribute. If you are not in UTC you also have to convert the last_triggered attribute to a local time. If the below condition is equel it means it already run that day.

{{ (state_attr('automation.morning_music_livingroom', 'last_triggered')|as_local).strftime('%Y-%m-%d')
  == now().date().strftime('%Y-%m-%d') }}

If you’re interested, you can reduce the template to this:

{{ (state_attr('automation.morning_music_livingroom', 'last_triggered')).astimezone() .date()
  == now().date() }}

Or just this:

{{ this.attributes.last_triggered.astimezone().date() == now().date() }}

EDIT

Correction. Adjust datetime for local timezone.

3 Likes

Hmm, that did not work for me.
Automation states for last_triggered date attribute have a long quotation e.g.“2024-02-13 10:49:51.748362+11:00”. I need to compare against only the date (yyyy-mm-dd) and not the rest, as I need to know if it already run today in my timezone and not UTC.

A datetime object’s date() method returns a date object (contains year, month, and day). What I overlooked to do was what your template did and that’s to initially convert UTC to local time.

I corrected the examples I had posted above.

I tested the first template using an automation that triggered yesterday and it correctly reported false today.

1 Like

I know it’s been a while, I was able to build a blueprint for this specific purpose:

Or you can try this excellent custom component:

Slightly cleaner:

{{ (state_attr('automation.living_room_temp_too_high', 'last_triggered')).date() != utcnow().date() }}

or shorter from a template condition within the automation:

{{ this.attributes.last_triggered.date() != utcnow().date() }}

(note the != to prevent re-running the same day, unlike above)

Without some form of timezone adjustment, I don’t believe that version of the template will produce a correct result for all circumstances.

In the following example, the automation triggered August 27 23:51 local time which is August 28 03:51 UTC owing to my local timezone being -4 hours. Observe the result of comparing its date to today’s date with and without timezone adjustment.

Here’s the Jinja2 code in case you want to experiment with it using your own data.

Click to reveal code
{% set x = 'automation.automatic_guest_bathroom_vanity_light' %}
{% set t = state_attr(x, 'last_triggered') %}

Automation triggered 
> August 27 23:51 *local* time
which is
> August 28 03:51 UTC
--------------------------------
{{ t| as_local }}
{{ t }}

Reported trigger date
with and without timezone adjustment
------------------------------------
{{ t.astimezone().date() }}
{{ t.date() }}

Current date as reported by now() and utcnow()
----------------------------------------------
{{ now().date() }}
{{ utcnow().date() }}

Check if trigger date is NOT today's date (August 28) 
Correct answer would be True.
-----------------------------------------------------
Without timezone adjustment: {{ t.date() != utcnow().date() }}
With timezone adjustment: {{ t.astimezone().date() != utcnow().date() }}

The example I had posted was in reply to a user’s requirement to check if the date is today so that’s why it uses the equivalence operator. If the requirement is to ensure it’s not today then, you’re absolutely correct, it should be != (or less than).

Good point; it would technically work on a daily basis --but not on your day– leading to confusing results, thanks!

I mainly wanted to clarify for search readers looking for a condition template (as suggested in several replies above)

Only if the trigger time doesn’t fall within the timezone’s offset range. The greater the offset, the more chance of the trigger time falling withing range and failing the Template Condition.

Exactly! Thanks for explaining it more thoroughly (for others :grin:)