Setting duration of timer with data_template not working

Got an automation that turns on the lights based on motion sensors and sets the brightness_pct depending of time of day(sensor). I get the brightness to work using data_template that reads the sensor but I also want the duration to be set depending of time of day, 2 minutes during day and 10 seconds during evening/night. But I can’t get the timer to work. I can start the timer with different duration from the GUI but not from the automation. What am I doing wrong?

configuration.yaml:

timer:
  hallway:
    duration: '00:02:00' 

automation.yaml:

- alias: 'Motion in hallway'
  trigger:
    - platform: state
      entity_id:
        - binary_sensor.hall_rorelse_hall_334
        - binary_sensor.hall_rorelse_entre_315
      to: 'on'
  action:
    - service: light.turn_on
      data_template:
        entity_id: light.hall_spotlights_hall_128
        brightness_pct: >-
          {%- if is_state("sensor.time_of_day", "Day") -%}
            100
          {%- elif is_state("sensor.time_of_day", "Evening") -%}
            10
          {%- elif is_state("sensor.time_of_day", "Night") -%}
            10
          {%- endif -%}
    - service: timer.start
      data_template:
        entity_id: timer.hallway
        duration: >-
          {%- if is_state("sensor.time_of_day", "Day") -%}
            '00:02:00'
          {%- elif is_state("sensor.time_of_day", "Evening") -%}
            '00:00:10'
          {%- elif is_state("sensor.time_of_day", "Night") -%}
            '00:00:10'
          {%- endif -%}
1 Like

Try removing the quotes around your times (in your duration template only). It’s possible that the template is resolving a double quote. I.E. "'00:00:00'". That would result in an invalid time format.

That worked! Thanks a lot @petro !

Passing the duration like 00:02:00 without citation mark did the trick :smile:

1 Like

I’m curious if this automation works as intended. I’ve personally never tried the " - service: timer.start" but have a few automations with “action:- delay:”

The problem is that the timer doesn’t reset. if I use a motion sensor, it doesn’t matter if it sense motion, it will turn off at the exact amount of time after it first saw motion. does this implementation fix that issue?

No. In my opinion, using a delay is the best way to have a motion timer. Have the delay in a script and cancel the script before calling it. It acts like a timer in the way you expect:

trigger:
- platform: state
  state: 'on'
  entity_id: binary_sensor.motion_blah
action:
- service: script.turn_off
  entity_id: script.delay_off
- service: light.turn_on
  entity_id: light.my_light
- service: script.delay_off
  data:
    duration: "00:02:00"
    light: light.my_light
delay_off:
  sequence:
    - delay: "{{ duration }}"
    - service: light.turn_off
      data_template:
        entity_id: "{{ light }}"
    

Thank you!

I’m assuming the 2nd box is what I put in my script.yaml

Yeah. This will essentially ‘start a timer’ every time motion occurs. Once the timer ends, the light will turn off.

I noticed this is for a “light.”… mine are “switch.”
do I need to create 2 scripts? (1 for each)? if I want to use it for both types?

You can or you can just add a second service after the light to turn off a switch. Or make a service_template that switches between switch or light based on the provided entity_id.

how does one make a service_template?

Heres the templating documentation:

Heres the blurb about creating service templates:

I really like this implementation. I’ve had several timers that resets before going on again, but having only one script to make the delay, and canceling it in any automation, it will cancel the delays for others lights as well?

Only cancels the specified script.

I wanted to clarify julupanter’s question.

If I write multiple automations for different lights (as in your example above), you are saying that it will only cancel the delay script for the corresponding light (even though you don’t specify the entity_id during script.turn_off)? If that’s really the case curious how it tracks the association.

It handles it through the context object

Keep in mind that only works if you have parallel on. You can read up on all of this in the automation run mode section

Thanks for the quick response.

I think I must still be missing something, or it doesn’t work.

I have the following motion sensor triggered automation:

alias: Foyer (motion light)
description: ''
trigger:
  - type: motion
    platform: device
    device_id: 8a04a2f0969ece71db7f543afdf9a45c
    entity_id: binary_sensor.4_in_1_sensor_home_security_motion_detection_3
    domain: binary_sensor
condition: []
action:
  - service: script.turn_on
    target:
      entity_id: script.1644636513894
    data:
      variables:
        entity_id: light.downstairs_hallway_foyer_chandelier
        illumination_sensor: sensor.4_in_1_sensor_illuminance_3
        brightness: 100
  - service: script.turn_on
    target:
      entity_id: script.1644636513894
    data:
      variables:
        entity_id: light.downstairs_hallway_stair_landing
        illumination_sensor: sensor.4_in_1_sensor_illuminance_3
        brightness: 80
  - service: script.turn_on
    target:
      entity_id: script.1644636513894
    data:
      variables:
        entity_id: light.stairs_main_light
        illumination_sensor: sensor.4_in_1_sensor_illuminance_3
        brightness: 100
mode: restart

With script.1644636513894 run in parallel:

alias: Motion Light
sequence:
  - condition: template
    value_template: '{{ states(entity_id) == ''off'' }}'
  - condition: template
    value_template: '{{ states(illumination_sensor)|float < 125 }}'
  #- service: script.turn_off
  #  target:
  #    entity_id: script.light_auto_off
  #  data: {}
  - service: light.turn_on
    target:
      entity_id: '{{ entity_id }}'
    data:
      brightness_pct: '{{ brightness }}'
  # - wait_template: '{{ is_state(''script.light_auto_off'', ''off'') }}'
  - service: script.turn_on
    target:
      entity_id: script.light_auto_off
    data:
      variables:
        entity_id: '{{ entity_id }}'
mode: parallel
max: 10

And the delay off:

alias: Light Auto Off
sequence:
  - delay:
      hours: 0
      minutes: 0
      seconds: 15
      milliseconds: 0
  - service: light.turn_off
    target:
      entity_id: '{{ entity_id }}'
mode: parallel
max: 10

As it is it works, but wouldn’t correctly reset the timer when new motion is detected (however, due to my light off condition, I don’t think this would work as I want it to either ways).

However, I am trying to understand how the script.turn_off works as you described. I.e. if I enable the commented lines the script.turn_off seems to cancel (randomly) one of the other three paralell running light_auto_off scripts, and also wait for whatever light_auto_off script is already running. Seems like some race conditions are happening. But the main point is that script.light_auto_off refers to any other instance of that script running in parallal for both the turn_off and the wait template, which shouldn’t be the case if I understand your comment correctly.

Any clarifying thoughts on this anyone?

Is it correct that each script is only identified by its name/id and thus stopping it would just stop an arbitrary instance of it independently of where it’s called from?

Looking back through my own scripts, it’s clear that my comment here was wrong:

To handle situations like this, I use anchors and call each script differently. Here’s an example:

resume_input_boolean_test_switch: &resume_scene_after_duration
  mode: restart
  fields:
    duration:
      description: Duration that we have to wait before sending the notification
      example: 60
    scene_id:
      description: Id of the scene
      example: scene_a_or_b
  sequence:

  - delay: "{{ duration }}"

  - service: scene.turn_on
    target:
      entity_id: scene.{{ scene_id }}

resume_input_boolean_test_switch_2: *resume_scene_after_duration
resume_switch_foyer: *resume_scene_after_duration
resume_switch_garage_entry: *resume_scene_after_duration
resume_switch_garage_cans: *resume_scene_after_duration
resume_light_dining_room_chandelier: *resume_scene_after_duration
1 Like

Great, thanks. That makes sense.