Template with if then for x minutes

I have an automation I’m trying to set up but am getting stuck at the end.

- id: automaticdoorlights
  alias: Lights - Doors
  description: ''
  trigger:
  - entity_id: binary_sensor.kid1_closet_door_sensor, binary_sensor.kid2_closet_door_sensor
    platform: state
  - entity_id: binary_sensor.kid1_closet_door_sensor, binary_sensor.kid2_closet_door_sensor
    for: 0:01:00
    from: 'off'
    platform: state
    to: 'on'
  action:
  - data_template:
      entity_id: '{{ trigger.entity_id.replace("binary_sensor", "light").replace("_door_sensor",
        "_light") }}'
      transition: 2
    service_template: '{% if "trigger.for" == "0:01:00" %}light.turn_off{% elif trigger.to_state.state
      == "on" %}light.turn_on{% elif trigger.to_state.state == "off" %}light.turn_off{%
      endif %}'

It’s a contact sensor on a closet door with a light that should turn on when it’s opened and turn off when it’s closed. That part all works fine. I also want the light to turn off if the door is left open for a minute. I have the trigger set up, and I have the if/then statement part recognizing the for part, but I’m guessing that the issue is that part of the statement is returning a string and part is returning an integer but I’m not 100% sure. Does anyone have advice?

Thanks in advance.

This depends on what you need in terms of help and maintainability.
The general way this is done is the switch brings the light on, the light coming on starts a timer script that ‘delays’ the required time and turns the light off.
If the switch closes before then it turns the timer script off and turns the light off.

A simpler way of doing it is just to have the delay in the automation that fires when turning the light on and another that just turns the light off. Note this can have unanticipated consequences eg you open the door, close it 30 secs later, then 5 seconds later open the door again and the light just goes off. Hence why we do the first.

How much detailed help do you need ?

According to the documentation for a State Trigger, trigger.for returns a timedelta object (not a string value).

A timedelta object has three attributes:

Attribute Value
days Between -999999999 and 999999999 inclusive
seconds Between 0 and 86399 inclusive
microseconds Between 0 and 999999 inclusive

Based on that information, change your initial if test to this:

{% if trigger.for.seconds|int == 60 %}

or

{% if trigger.for.seconds|int >= 60 %}

if you want to hedge your bets.


EDIT

If you wish, you can re-write your templates like so:

  action:
  - data_template:
      entity_id: "light.{{ trigger.to_state.object_id.replace('_door_sensor','_light') }}"
    service_template: "light.turn_{{ 'off' if trigger.for.seconds|int >= 60 else trigger.to_state.state }}"

Sorry, I disregarded his code and just went for achieving the easiest ways to accomplish the need. :man_shrugging:

You could also use this as a base. I use a similar concept for my garden lights. Turning the lights on and off when the door opens and closes, but also turning it off after a fixed time.

Yea but I wanted this in 1 automation. I think MuttsTaras solution is gonna be the one! Thank you I’ll test later today.

Edit, sorry Taras solution is the one I’m trying. They jumbled together on my phone.

The for: option is an implicit timer.

In my opinion, the use of explicit timers, or delays, is just a longer way to achieve the same thing. You currently have a single automation that, with a little tweaking, should get the desired result.

@broyuken1 I understand the desire to reduce the number of automations (I just went through an excercise to do this and Inow have 192 automations instead of 190 (so that worked out well ! :face_with_symbols_over_mouth: ) but i did manage to chop out 6 scripts (from 58 down to 52))
But I’m not sure there is an actual need. Sometimes having, clear, well defined automations/scripts is a great boon as you spend less time deciphering them and maintanence becomes much easier.

You will need to ‘adjust’ to suit (you have a separate switch from timer and maybe you don’t need a confiruable time delay) but : - (again the benfit is that the automation is always ready to run and the script never gets confused and turns the light off early)

automation:
  #name: Light WC Off Delay
  - alias: au_light_wc_offdelay
    trigger:
      - platform: state
        entity_id: light.fibdim2_wc_level
        to: 'on'
    action:
      - service: script.sc_light_wc_timer
  #name: Switch WC Off Cancels Timer
  - alias: au_switch_wc_offcancelstimer
    trigger:
      - platform: state
        entity_id: light.fibdim2_wc_level
        to: 'off'
    action:
      - service: script.turn_off
        entity_id: script.sc_light_wc_timer

script:
  sc_light_wc_timer:
    alias: Light WC Timer Script
    sequence:
      - delay: "00:{{ states('input_number.in_light_wc_timer') | int }}:00"
      - service: light.turn_off
        entity_id: light.fibdim2_wc_level

@123,
I’m lazy and have all my lights (and timed switches) are in the same format. (never bothered changing them)
I’ve seen the for: option but I’m not sure how you’d you’d apply it in this case as the switch is separate from the light. And can you template the for: ?
So you could have a semi-complex automation to turn the light on and off using a service template
But then you’d need another automation to monitor the light on for: time to introduce the off switch
So 2 (or 3 without the service template) Automations vs 2 & 1 script ??? what have I missed ?

Edit: Equally I could introduce a service template on my switch on automation to dispense with the switch off Automation

Yes, see State Trigger and you should probably create a separate topic to discuss your specific requirements.

No, I don’t need it, its a corolliary to the OP’s topic (in case he needed to template the delay)

Tried it, but I’m getting the following error in my logs.

2020-03-19 14:51:33 ERROR (MainThread) [homeassistant.components.automation] Error while executing automation automation.lights_doors. Error rendering template for call_service at pos 1: UndefinedError: 'None' has no attribute 'seconds'

The entity id works great, but the service seems to be breaking at the “for”.

Also note, I set up a second automation to send a push notification to my phone with the same data and that populates correctly if the for has a value. If it doesn’t, it makes the sound like a message was received but there is no notification.

  - data_template:
      message: "light.turn_{{ 'off' if trigger.for.seconds|int >= 60 else trigger.to_state.state }}"

My mistake; that error occurs when the first trigger occurs (the one without the for:) and the template attempts to access something that doesn’t exist at that moment (namely trigger.for.seconds).

Replace it with this:

  action:
  - data_template:
      entity_id: "light.{{ trigger.to_state.object_id.replace('_door_sensor','_light') }}"
    service_template: "light.turn_{{ trigger.to_state.state if trigger.for == None else 'off'}}"

It works on a simpler principle:

  • If trigger.for is None then it was the first trigger that occurred.
  • Otherwise it’s the second trigger that occurred.
1 Like

That’s a much smarter way to handle it, works amazing thank you!

1 Like

Glad to hear it’s working now.

Please mark my previous post with the Solution tag. This will automatically place a link under your first post that leads to the Solution post. It will also place a check-mark next to the topic’s title that signals to other users that this topic has an accepted solution. All of this helps others, who may have a similar question, find answers.

1 Like