Only allow automation to trigger once a day?

so in the end I solved it completely differently. In configuration.yaml, a global boolean variable is defined. When the temperature drops once it reports. The transformation turns off. The boiler heats up above the set limit and the variable is switched on.

configuration.yaml

input_boolean:
  notify_boiler:
    name: NotifyBoiler
    initial: ON

automation on only sound:

talias: Teplota bojler 68
description: ''
trigger:
  - platform: time_pattern
    minutes: /1
condition:
  - condition: time
    after: '08:00:00'
    before: '22:00:00'
    weekday:
      - mon
      - tue
      - wed
      - thu
      - fri
      - sat
      - sun
  - condition: state
    entity_id: input_boolean.notify_boiler
    state: 'on'
  - condition: numeric_state
    entity_id: sensor.bojler
    below: '68'
action:
  - service: tts.voicerss_say
    data:
      entity_id: media_player.obyvaci_pokoj_speaker
      message: >-
        Voda v bojleru má nedostatečnou teplotu {{states('sensor.bojler')}}
        stupňů celsia. Šetřete teplou vodou!!
  - service: input_boolean.turn_off
    target:
      entity_id: input_boolean.notify_boiler
    data: {}
mode: single


automation reset event:

alias: Teplota bojler reset stavu
description: ''
trigger:
  - platform: time_pattern
    minutes: /10
condition:
  - condition: numeric_state
    entity_id: sensor.bojler
    above: '72'
action:
  - service: input_boolean.turn_on
    target:
      entity_id: input_boolean.notify_boiler
    data: {}
mode: single

thank you for the response :slight_smile:

Why have you chosen to use Time Pattern Triggers when the automation can clearly be triggered exclusively when desired events occur (and not needlessly and repeatedly every X minutes)?

I don’t know why yet, but the numerical condition doesn’t want me to work. The timer will check it safely. I know this is not the best solution.

So I am using the default filter but the automation keeps on triggering when the binary sensor turns to on I.e. when motion is detected.

Not sure if the condition is really working.

I think its new. Now you can add the action “Wait for time to pass (delay)”!

1 Like

Working, but testing on automation show error:
“template value should be a string for dictionary value @ data[‘value_template’]. Got None”

Open Issue on GitHub: https://github.com/home-assistant/frontend/issues/12282

1 Like

I actually do this by creating a input_boolean helper. It turns off at midnight and turns on with the specific automation that should only be run once. Then use input_boolean’s state = off as a condition for it. :slight_smile:

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:)