Automation trigger from date in sensor atttribute

Hi,

I have a sensor with a date in an attribute in the following format:

‘2023-11-28’

How would I use a template to trigger an automation at 9am 1 month before the date in the sensor attribute?

trigger:
  - platform: template
    value_template: |
      {% set (y,m,d) = (state_attr('sensor.YOUR_SENSOR', 'DATE_ATTR')).split('-')|map('int') %}
      {{ now() >= today_at('9:00').replace(year=y, month= m+1, day=d) }}

EDIT: This is a dumb answer… :man_facepalming:

Thanks.

I had to change it to

{{ now() >= today_at('9:00').replace(year=y, month= m-1, day=d) }}

But have now noticed that if the month is January (1) It will give me an error as the result would be 0 which returns an error

ValueError: month must be in 1…12

How would I get around this? Also how would I then get it to trigger 1 week before? I would have the same problem as Im having now if I were to use d-7

“Months” are kind of dumb like that… Since they have varying numbers of days, you have to define what you want to happen when the number of days don’t match month-to-month.

The easiest and most “average” method would be to just use 30 days as the stand-in for months:

30 days prior:

{% set date = state_attr('sensor.YOUR_SENSOR', 'DATE_ATTR')%}
{{ now() >= (date | as_datetime | as_local - timedelta(days=30)).replace(hour=9) }}

A more complicated option would be as follows. This would trigger on the matching numeral day, except in cases where the sensor attribute’s day is higher than the previous month’s last day. In that case it will use the last day of the month.

{%- set date = state_attr('sensor.YOUR_SENSOR', 'DATE_ATTR')%}
{% set d = date.split('-')|last|int%}
{%- set date_dt = date|as_datetime|as_local %}
{%- set days_l_m = (date_dt.replace(day=1) - timedelta(days=1)).day %}
{%- set next_month = date_dt.replace(day=28) + timedelta(days=4) %}
{%- set days_t_m = (next_month - timedelta(days = next_month.day)).day %}
{% if days_l_m >= days_t_m %}
  {%- set target = date_dt - timedelta(days=days_l_m) -%}
{% elif d > days_l_m %}
  {% set target = (date_dt - timedelta(days=days_l_m+4)).replace(day=days_l_m) %}
{%- else -%}
  {% set target = date_dt - timedelta(days=days_l_m) %}
{%- endif -%}
{{ now() >= target.replace(hour=9) }}

EDIT: The above is probably a little better than the previous option.

Weeks are easy since they are a set number of days:

{% set date = state_attr('sensor.YOUR_SENSOR', 'DATE_ATTR')%}
{{ now() >= (date | as_datetime | as_local - timedelta(days=7)).replace(hour=9) }}

You can’t simply subtract 1 from the month value because some months are longer than others.

For example, if the sensor reports 2023-10-31 and you subtract 1 then you will get 2023-09-31 which is an invalid date (there are only 30 days in September).

Your best option is Didgeridrew’s ‘30 days prior’ example.

Thank you, I have created a sensor using your code and it works.

I have also just found another way which shows how many days until:

{{ (((as_timestamp(state_attr('sensor', 'attr'))-as_timestamp(now()))) | int /60/1440) | round(0) }}

But as I prefer a binary sensor I will use your method

{{ (state_attr('sensor', 'attr') | as_datetime | as_local - now()).days }}
1 Like