Adding delay offset to input_datetime time on some dates

Hi

I have my apocryphal coffee machine turn on/off at particular times set by input_datetime helpers that I can tweak from the UI. I am just using a standard time trigger in the automation to turn it on/off.

I also have a workday sensor which tells me if today is a holiday.

I would like to turn on/off my coffee machine one hour later if today is a holiday. I currently achieve this by doubling all my datetime helpers and having conditions to test if the workday sensor is on. But this gets out of hand when I start adjusting them, since I have to remember to do it twice.

Is it possible to modify an input_datetime by “adding” some time offset to it? I would then be able to do something like. I could then have an automation which either sets this offset to zero for normal days and e.g. 1 hour for holidays, to be used across all my automations.

trigger:
- platform: time
- at: input_datetime.coffee_on + input.datetime.todays_delay   <--- pseudocode
...

Possible complications: my input_datetimes are times only (no dates) and I also need to use them with this offset in time conditions.

There’s a PR in the works to allow offsetting a Time Trigger.

If and when it gets implemented, your goal will be easier to achieve (sort of; based on my interpretation of the PR’s description, the offset will have to be a fixed value as opposed to an entity’s value).

Until that happens, you have to use a Template Trigger or, because you need to refer to it in triggers and conditions, create a Template Sensor and reference it in triggers and conditions.

Let me know if you need help creating the template for the Template Sensor.

Thanks!

It would be great if you could help me how to create a template which would test if the time now is equal to the time of some (time-only) input_datetime offset stored in another (time-only) input_datetime. I get completely lost with the fact that time-only input-datetimes are not easily interpretable as timestamps.

Here are two ways to do it (for Template Triggers).

The first method converts all times to strings and then compares them.

{{ (now().time()|string)[:5] == (state_attr('input_datetime.your_time', 'timestamp') - state_attr('input_datetime.your_offset', 'timestamp')) | timestamp_custom('%H:%M', false) }}

The second method converts the calculated time to a datetime object and then compares it to the current time.

{% set t = now().fromtimestamp(state_attr('input_datetime.your_time', 'timestamp') 
    - state_attr('input_datetime.your_offset', 'timestamp'), utcnow().tzinfo) %}
{{ (now().hour, now().minute) == (t.hour, t.minute) }}

Both work equally well but the first one has the advantage of brevity. The second one is longer because it has extra work converting the subtracted input_datetimes into a datetime object.

A few words on how it performs the datetime conversion:

  • now() returns a datetime object.
  • now().fromtimestamp() will convert the supplied Unix timestamp into a datetime object.
  • The timestamp we are providing represents a local time but it’s actually expressed as a UTC time with no timezone offset. We need to inform fromtimestamp() of this missing timezone offset so that’s why we supply it with the utcnow().tzinfo adjustment.

As seen from the two examples above, they’re a bit more challenging to work with if you want to handle them as datetime objects.


NOTE

If you want to create a Template Sensor, just use a variation of the first method:

{{  (state_attr('input_datetime.your_time', 'timestamp') - state_attr('input_datetime.your_offset', 'timestamp')) | timestamp_custom('%H:%M', false) }}

Hi @petro Could you please help me with what I am doing wrong? I am pulling my hair out now :frowning:

I am trying to subtract the values of two sensors which are in HH:MM format and I am using the following:

{{(states('sensor.A')|int - states('sensor.time')|int) | timestamp_custom('%H:%M') * 60}}

The result however is always 01:00. I am trying to get the result in minutes.

Thank you.

is sensor.time an integer?

I am not too sure. Its just the time sensor component I have added in my configuration.

an integer is a number without a decimal place. Is 10:00 an integer? Is any time for that matter an integer?

Its not an integer

Alright, then can you spot your first error? And possibly your second depending on what sensor.a outputs

Yeah integer.

Sensor.a outputs 20:32. So I tried this:

{{ as_timestamp(states('sensor.a')) - as_timestamp(states('sensor.time')) }}

But throws an error saying: TypeError: unsupported operand type(s) for -: 'NoneType' and 'NoneType'

see if you can use this thread to figure out how to parse HH:MM time strings.

1 Like

One thing to add here, is that with 2021.11 a new template filter is landing, which will allow you to do the simple thing of creating a datetime object from a time

today_as(states(`input_datetime.trigger_time`))

which will return a datetime with today’s date and the time specified in the helper.

Add datetime_today template method by Petro31 · Pull Request #57435 · home-assistant/core (github.com)

you’re welcome :wink:

Small world :ok_hand: