Use state values / template in an automation `time` condition?

I am trying to create an automation that only runs during part of the day (easy), and make the start and end times configurable. I’m looking for the cleanest way to handle the second part.

Hard-coding the start and end times works as expected:

      - condition: time
        after: '07:00:00'
        before: '22:00:00'

To make it configurable, I’ve added two input_datetime helper / inputs:

input_datetime:
  pref_sync_hours_start:
    name: 'Sync Start'
    has_date: false
    has_time: true
    icon: mdi:timelapse
  pref_sync_hours_end:
    name: 'Sync End'
    has_date: false
    has_time: true
    icon: mdi:timelapse

What I would like to do is use these directly in the after: and before: elements, like so:

      - condition: time
        after: "{{ states('input_datetime.pref_sync_hours_start') }}"
        before: "{{ states('input_datetime.pref_sync_hours_end') }}"

That does not work. The error is:

Configuration invalid
Invalid config for [automation]: Invalid time specified: {{ states(‘input_datetime.pref_sync_hours_start’) }} for dictionary value @ data[‘condition’][0][‘conditions’][0][‘after’]. Got None. (See /config/configuration.yaml, line 16).

I believe this error means that before: and after: do not support template evaluation.

I can make it work with a template condition instead:

      - condition: template
        value_template: >
          {{ states('input_datetime.pref_sync_hours_start') < states('sensor.time') and
             states('sensor.time') < states('input_datetime.pref_sync_hours_end') }}

But I find it harder to read and parse in my head. before: and after: are so clear, and a complex conditional template is less so. (And this template is far from the most complex!)

Is there an easier way than using the template?

Note: I’ve also tried extracting the template calculation into a template sensor, and then just used the sensor’s state. That’s a bit more clear, but the semantic intent is spread across two configuration files, which I dislike.

Sandwich the current time between the start and end times.

        - condition: template
          value_template: >
            {{ states('input_datetime.pref_sync_hours_start') < states('sensor.time')  < states('input_datetime.pref_sync_hours_end') }}
1 Like

Good lord. I did not expect that to work. A similar construct in a “normal” programming language would be a syntax error, or a logic error. But, playing around in Developer Tools > Template, and with constants instead of states, it really does seem to work as “expected”…now that I know to expect it!

The result is a much easier to interpret condition clause:

      - condition: template
        value_template: >
          {{ states('input_datetime.pref_sync_hours_start') < 
             states('sensor.time') < 
             states('input_datetime.pref_sync_hours_end') }}

It’s obvious that you’re checking that the current time is between a start and end time. Exactly what I wanted.

I guess I’m going to have to read more of the Jinja docs, to better understand how the templating engine works. It has surprised me more than once now…

Thanks!

1 Like