Trigger automation 15 minutes before date_time stored in input_datetime

Okey, I have this in my configuration.yaml file:

sensor:
  - platform: time_date
    display_options:
      - 'time'
      - 'date'
      - 'date_time'
      - 'date_time_iso'
      - 'time_date'
      - 'time_utc'
      - 'beat'

input_datetime:
  flemming_phone_next_alarm_date_and_time:
    name: Flemmings neste alarm
    has_date: true
    has_time: true

I want to trigger an automation 15 min before the above input_datetime.

Example:
If input_datetime is 2019-11-02 15:45:00 I want the automation to trigger 2019-11-02 15:30:00.
If input_datetime is 2019-11-02 00:05:00 I want the automation to trigger 2019-11-01 23:50:00.

By the way, checking the template I see the formatting of sensor.date_time and my input_datetime is not the same:
{{ states.sensor.date_time.state }} show as 2019-10-30, 13:30
{{ states.input_datetime.flemming_phone_next_alarm_date_and_time.state }} show as 2019-10-30 13:30:00

Tried to google, and I find examples on time and date separate, but not with them together, and with trigger in “past-time”

As you are storing the date in your input datetime it’s actually quite easy. Try this in the template editor:

value_template: >
  {% set alarm_time = as_timestamp(states('input_datetime.flemming_phone_next_alarm_date_and_time')) %}
  {% set time_now = as_timestamp(states('sensor.date_time').replace(',', '')) %}
  {{ time_now >= ( alarm_time - 900 ) }}

Edited: see Phil’s comment below.
Edit2: Removed extra parentheses.

One of the annoying things about sensor.date_time is that you can’t use it directly in as_timestamp() because of the comma. But you can do this:

  {% set time_now = as_timestamp(states('sensor.date_time').replace(',', '')) %}
3 Likes

Amended my template. Thanks.

1 Like

Thanks, well, It did not work in the template editor (if it should)
Error rendering template: TemplateSyntaxError: unexpected ‘}’, expected ')'

Actually, I never tried it before (and it might be new), but you can use sensor.date_time_iso directly in the as_timestamp() function.

EDIT: I checked. The date_time_iso option was added in 0.91. Must have overlooked it. :slight_smile:

I think there’s an extra parenthesis in the last line. Try:

  {{ time_now >= ( alarm_time - 900 ) }}

Apologies. There was an extra ( left in front of “time_now…” I missed when cleaning up the template of extraneous junk. Fixed.

Looks better.
This:

value_template: >
  {% set alarm_time = as_timestamp(states('input_datetime.flemming_phone_next_alarm_date_and_time')) %}
  {% set time_now = as_timestamp(states('sensor.date_time').replace(',', '')) %}
  {{ time_now >= ( alarm_time - 900 ) }}

{{ alarm_time }}
{{ time_now }}

Result in this:

value_template: >
  
  
  False

1572705900.0
1572442200.0

Looks ok? What is 900 present? seconds?

Timestamps are in seconds since the epoch date ( January 1, 1970 at 00:00:00).

15 minutes * 60 = 900 seconds.

I get this error, what do I have to change?

TypeError: unsupported operand type(s) for -: 'NoneType' and 'int'

And the code that generates this error looks like? :wink:

Hint: this error means, you are comparing to different types of values, one being without a type (none) and one being an integer (int). But that’s general, that can be the reason, but without the code…

@paddy0174 Sorry for being unclear, I just copied the code above from @tom_l from oct ‘19 in the template editor.
It looks like the alarm_time definition is not compatible (anymore? It worked oct ‘19).

I know that sounds picky, but please post “your” exact code. Copy it and paste it here. The reason is rather un-exciting, the copied code may have some indentation errors or other funny things like that. :wink: :slight_smile:

Just from the top of my head, I’d say there has something changed in the definiton of one of your times or HA is now checking the type “more exactly”. Maybe one of your sensors has changed in type or state.

I’d try to check your code in the template editor, one by one. Taking the code from @tom_l from the Oct '19 and check the outcome.

Just like flemingss did, so you could see the outcome:

value_template: >
  {% set alarm_time = as_timestamp(states('input_datetime.flemming_phone_next_alarm_date_and_time')) %}
  {% set time_now = as_timestamp(states('sensor.date_time').replace(',', '')) %}
  {{ time_now >= ( alarm_time - 900 ) }}

{{ alarm_time }}
{{ time_now }}

I always use something like:

{% set minutes_reduction = 15 %}
{% set seconds_reduction = timedelta(minutes=minutes_reduction).seconds %}
{% set new_time = current_time - seconds_reduction %}
{{ new_time | timestamp_custom('%H:%M:%S', False)  }}

For the first line you could use someting like the line below to use an input_number to set the minutes instead:

{% set minutes_reduction = states('input_number.minutes_offset')|int %}

I just copied and pasted the code, adjusted the

input_datetime.flemming_phone_next_alarm_date_and_time

into

input_datetime.wakeup_time

final code in the editor:

value_template: >
  {% set alarm_time = as_timestamp(states('input_datetime.wakeup_time')) %}
  {% set time_now = as_timestamp(states('sensor.date_time').replace(',', '')) %}
  {{ time_now >= ( alarm_time - 900 ) }}

{{ alarm_time }}
{{ time_now }}

This is my input_datetime.wakup_time entity definition:

@misterdaan Will try this when I get home, thanks!

Thanks for the detailed response. :+1: The problem is, you are trying to compare different things. Why this worked until now I can’t say. In your case time_now and alarm_time are timestamps, where the “900” is an integer. You can’t calculate with that.

Would you mind trying this in the template editor and see if it works for you:

{% set alarm_time = (state_attr('input_datetime.wakeup_time', 'timestamp') | int) - 900 %}
{% set time_now = as_timestamp(states('sensor.date_time').replace(',', '')) | int %}
{{ time_now >= alarm_time }}

@123 Sorry for notifying you, but could you please take a look here and see if I’m totally wrong? It seems a little off to filter and typecast all these. Thank you very much! :slight_smile:

{{ now().ctime()[11:16]  >= (state_attr('input_datetime.wakeup_time', 'timestamp') - 900) | timestamp_custom('%H:%M', false) }}

On the left hand side:

  • now().ctime() produces a string like this: Wed Aug 11 13:17:15 2021
  • We only want the time as hours and minutes so we use [11:16] to slice it out of the string.

On the right hand side:

  • We get the input_datetime’s value as a timestamp then subtract 900 seconds from it.
  • The result of the subtraction is converted to a time string with timestamp_custom.

You would think that it would be more elegant to compare the two times as datetime objects. The current time is easily expressed as a datetime object by now(). The challenge is to express the time-only input_datetime as a datetime object. It’s complicated by the fact it has no date and stores its time as local time and not with respect to UTC (as does an input_datetime with date and time).

The following works but is longer than comparing times as strings:

{{ now() >= now().replace(hour=state_attr('input_datetime.wakeup_time', 'hour'), minute=state_attr('input_datetime.wakeup_time', 'minute')) - timedelta(minutes=15) }}
2 Likes

@123 @paddy0174 Thanks for the detailed response, learned a lot in the process. Will try when I get at home tonight and post the result!

Is there a way/site to get more knowledge about this kind of manipulating different types of varables? The official docs are not always beginner frendly in this respect. Also the strict rules about indentations, comma’s, brackets etc is not immediately clear to a non-programmer like me.