Manipulating Time in HASS to Act Before an Inputed Time

I am setting up an alarm clock with multiple integrations. I followed people’s posts (including notably this one.

I cannot figure out how to manipulate and act upon a time XX min before the time I input.

Because I am not using the sun, I cannot use offset. Because before, delay does not work.

Tried to figure out the helper automation, but it uses as_timestamp which seems to fail (right now with a simple light toggle to diagnose):

alias: Wake 1 Helper
 trigger:
   - platform: template
     value_template: >-
       {{ as_timestamp(states('sensor.time')) ==
       (as_timestamp(states('sensor.wake_time_1')) | int -(60*30)) | 
       timestamp_custom('%Y-%m-%d, %H:%M', True) }} 
 action:
   - service: light.toggle
     data:
       entity_id: living_room.couch_right

I tried a template in configurations.yaml but unsure if that is even a right path:

template:
  - sensor:
    - name: "wake_time_1_start"
      state: >
        {% set hr = states.sensor.time.state.split(":")[0] %}
        {% set mi = states.sensor.time.state.split(":")[1] %}
        {% if mi <31 %}
          {% set hr_start = hr-1 %}
          {% set mi_start = mi+30 %}
        {% else %}
          {% set hr_start = hr %}
          {% set mi_start = mi-30 %}
        {% endif %}
        {{ as_timestamp('hr_start:mi_start')| timestamp_custom('%Y-%m-%d, %H:%M', True) %}}

Help?

There have been some great additions to time-based templating since that post, such as timedelta() and today_at().

If your sensor returns a datetime string like 2022-03-27 17:30:11.017258-04:00
you can use the following:

alias: Wake 1 Helper
trigger:
  - platform: template
    value_template: >-
      {{ now() >= states('sensor.wake_time_1') | as_datetime - timedelta(minutes=60) }} 
action:

If your sensor returns a time string in “HH:MM” or “HH:MM:SS” format
you can use timedelta() as well, but with today_at():

alias: Wake 1 Helper
trigger:
  - platform: template
    value_template: >-
      {{ now() >= today_at(states('sensor.wake_time_1')) - timedelta(minutes=60) }} 
action:


Whether or not you should create a template sensor boils done to whether you are going to be using this specific time in a variety of automations. If it’s a one-off, don’t bother with the template sensor but if you think you’ll need to use it in multiple automations it makes sense to set up a sensor.

Thanks for the quick reply! I tried both and got the below for each:

Error evaluating 'template' trigger for 'Wake 1 Helper': TypeError: unsupported operand type(s) for -: 'NoneType' and 'datetime.timedelta' 

and

Error evaluating 'template' trigger for 'Wake 1 Helper': UndefinedError: 'today_at' is undefined

I should have posted it before, but my sensor.yaml is

- platform: mqtt
  name: "Light"
  state_topic: "pyportal/lux"
  unit_of_measurement: 'Lux'
- platform: template
  sensors:
    wake_time_1:
      friendly_name: 'Wake Time 1'
      value_template: "{{'{:02d}:{:02d}'.format(states('input_number.wakehour_1') | int, states('input_number.wakeminute_1') | int) }}"
- platform: time_date
  display_options:
    - 'time'

so I would have thought it would be HH:MM

Finally, how would you do the template if you don’t mind. YAML confuses me vs other languages.

You example should return a "HH:“MM” time string.

Is there a reason you aren’t using an Input Datetime helper instead of two Input Numbers?
Unless there is a reason to do it that way I would use a datetime instead… However, if I needed to do it with your current setup the sensor, in the current format, would look like:

template:
  - sensor:
      - name: "Wake Time 1"
        state: >
          {{'{:02d}:{:02d}'.format(states('input_number.wakehour_1') | int, states('input_number.wakeminute_1') | int(0)) }}
        availability: "{{ states('input_number.wakehour_1') | int('none') is number }}"

The set up of the second sensor depends on how you want to use it… do you want it to return the datetime of Wake Time 1 - 60 minutes or do you want a binary sensor that switches ‘on’ when it is reaches 60 minutes before Wake Time 1?


  - sensor:
      - name: "Wake Time 1 minus 60"
        device_class: timestamp
        state: >
          {{ today_at(states('sensor.wake_time_1')) - timedelta(minutes=60) }} 
        availability: "{{ states('sensor.wake_time_1') not in ['unavailable','unknown'] }}"

  - binary_sensor:
      - name: "Wake Time 1 minus 60"
        state: >
          {{ now >= today_at(states('sensor.wake_time_1')) - timedelta(minutes=60) }} 
        availability: "{{ states('sensor.wake_time_1') not in ['unavailable','unknown'] }}"

Well… because I didn’t know that existed is a pretty poor excuse. Especially when I have been on the doc page…

Both would work, but I was thinking binary. Thanks for explaining!

Ok. Now I’m lost and it is not working. I tried to simplify things down and just worry about time

  alias: Alarm Clock 1
  description: ''
  trigger:
  - platform: template
    value_template: "{{ now() == today_at(states('input_datetime.wakeup_1')) }}"
  condition:
    condition: template
    value_template: "{{ is_state('input_boolean.wakestatus_1', 'on') }}"
  action:
  - service: light.toggle
    target:
      entity_id: light.living_couch_right
#configuration.yaml
input_datetime:
  wakeup_1:
    name: Wakeup 1
    has_date: false
    has_time: true

Still getting an Template variable error: 'today_at' is undefined when rendering error and not sure how/where/why to use your availability lines. But am guessing that would solve it?

You can get that error if you are not using a recent version of Home Assistant.

What version of Home Assistant do you have?

As Taras comment today_at() is a kind of recent addition. It was added in version 2021.11

The availability configuration variable is used when setting up sensors to avoid some types of errors as well as abnormal sensor states. This isn’t fully implemented yet, so the state template is still rendered (but not shown as the state). Because of this, some errors will still be posted to the log. As far as I know, you can not use it in automations.

Also, while not completely necessary in all cases, it can be a good practice to use >= instead of == when comparing datetimes. That way you do not have to have an exact match down to the microsecond.

Thar be the other problem… Frontend version: 20211007.1 - latest. I will have to figure out how to update the docker.

Make sense re microsend, but what keeps it from being triggered multiple times?

Triggering only happens on the change of the rendered value, so when it changes from False to True. When now() updates at the start of every minute and the template renders as True, but it was already True it will not retrigger the automation.