Dont want the light to turn off unless it was turned on by a previous automation

So, what I want is: When I open the door, the light turns on, and 1 minute after I close the door the light turns off unless it was already on before I opened the door.
Im using this automations below:

  - alias: ligar sala estar quando abrir porta sala a partir do por do sol
    trigger:
      platform: state
      entity_id: binary_sensor.porta_sala
      to: 'on'
    condition:
      - condition: state 
        entity_id: sun.sun
        state: "below_horizon"
      - condition: state
        entity_id: light.sala_estar
        state: "off"
    action:
      - service: input_boolean.turn_on
        entity_id: input_boolean.porta_sala
      - service: light.turn_on
        entity_id: light.sala_estar
        
  - alias: desligar sala estar 1 minuto apos fechar a porta se a automação anterior foi ativada
    trigger:
      platform: state
      entity_id: binary_sensor.porta_sala
      to: 'off'
      for:
        minutes: 1
    condition:
      condition: state
      entity_id: input_boolean.porta_sala
      state: 'on'
    action:
      - service: input_boolean.turn_off
        entity_id: input_boolean.porta_sala
      - service: light.turn_off
        entity_id: light.sala_estar

I created a input_boolean in configuration.yaml

input_boolean:
  porta_sala:
    name: porta sala

so that, when the first automation is activated, the input_boolean turns on

action:
  - service: input_boolean.turn_on
    entity_id: input_boolean.porta_sala

Also, I used a condition to only activate the first automation if the light is off

  - condition: state
    entity_id: light.sala_estar
    state: "off"

and in the second one, I used a condition to only activate when the input_boolean is on.

condition:
  condition: state
  entity_id: input_boolean.porta_sala
  state: 'on'

So, in theory, if I turn on the light before I open the door, the first automation wouldnt activate because of the condition that the light should be off, and then the input_boolean wouldnt turn on and that wouldnt activate the second automation.
But, the light still goes off even when I turn it on before opening the door.

Hi.

The magic should be here the boolean. If you enable the light manually, the boolean or the other trigger will never be exectuted.

So just make a check if the light is already on. You can play with other booleans as well. But thats not needed at all.

For example: I have a light in a floor, I dont want to run the automation if the light is already on. Same for my bedroom and other locations.

cheers

fb

edit_example:

alias: LICHT - Schlafzimmer Ambient AN
description: Nach Sonnenuntergang
trigger:
  - platform: state
    entity_id: binary_sensor.fibaro_motion_schlafzimmer_home_security_motion_detection
    to: 'on'
condition:
  - condition: and
    conditions:
      - condition: or
        conditions:
          - condition: sun
            after: sunset
            after_offset: '-00:30:00'
          - condition: sun
            before: sunrise
      - condition: time
        after: '16:00'
        before: '22:59:59'
  - condition: state
    entity_id: light.licht_schlafzimmer_iris_1_2_zha_group_0x0004
    state: 'off'
action:
  - service: light.turn_on
    data:
      brightness_pct: 50
      color_name: white
    target:
      entity_id: light.licht_schlafzimmer_iris_1_2_zha_group_0x0004
  - service: input_boolean.turn_on
    data: {}
    target:
      entity_id: input_boolean.licht_schlafzimmer_ambient_boolean_on_off
mode: single
1 Like

I still dont get why mine isnt working, beside a few extra conditions, our automations are pretty much the same…

I’m a litle tipsy…

But I have a similar automation to that. Maybe this makes more sense to you.

ON:

alias: LICHT - Flur_Unten AN
description: Nach Sonnenuntergang
trigger:
  - platform: state
    entity_id: binary_sensor.fibaro_motion_flur_unten_home_security_motion_detection
    to: 'on'
  - platform: state
    entity_id: binary_sensor.lumi_lumi_sensor_magnet_aq2_on_off
    from: 'off'
    to: 'on'
    for: '00:00:00'
condition:
  - condition: or
    conditions:
      - condition: sun
        after: sunset
        after_offset: '-01:00:00'
      - condition: sun
        before: sunrise
  - condition: state
    entity_id: light.licht_flur_unten_1_2_zha_group_0x0003
    state: 'off'
action:
  - service: light.turn_on
    data:
      brightness_pct: 20
    target:
      entity_id: light.licht_flur_unten_1_2_zha_group_0x0003
mode: single

OFF:

alias: LICHT - Flur_Unten AUS
description: Nach Sonnenuntergang
trigger:
  - platform: state
    entity_id: binary_sensor.fibaro_motion_flur_unten_home_security_motion_detection
    to: 'off'
    for: '00:02:00'
    from: 'on'
  - platform: state
    entity_id: binary_sensor.lumi_lumi_sensor_magnet_aq2_on_off
    from: 'on'
    to: 'off'
    for: '00:02:00'
condition:
  - condition: or
    conditions:
      - condition: sun
        after: sunset
        after_offset: '-01:00:00'
      - condition: sun
        before: sunrise
  - condition: state
    entity_id: light.licht_flur_unten_1_2_zha_group_0x0003
    state: 'on'
action:
  - service: light.turn_off
    data: {}
    target:
      entity_id: light.licht_flur_unten_1_2_zha_group_0x0003
mode: single

But while writing and copy and pasting… Do you ever turn the boolean off? Likely said I am a littly tipsy. Its corona and first vacation day :wink:

Are you sure the “input_boolean.porta_sala” is actually off?

Couldn’t this be done without the use of a boolean at all?

trigger: door opens

condition: light is off

action:
 - turn on light
 - wait 1 minute
 - turn light off

this way, the automation only runs if the light is off. If the light is already on, this automation never runs so the light doesn’t turn off after a minute.

It was my first idea but I couldnt make it work. Could you give me an example?

I tried

 - turn light on
 - delay 1 minute
 - turn light off
 - turn light on
 - for 1 minute

I dont know what code should I use for this…

Yes, the boolean goes on and off exactly when it should. But the second automation ignores the condition and activates even when the boolean is off.

trigger:
  - platform: state
    entity_id: binary_sensor.fibaro_motion_flur_unten_home_security_motion_detection
    to: 'off'
    for: '00:02:00'
    from: 'on'
  - platform: state
    entity_id: binary_sensor.lumi_lumi_sensor_magnet_aq2_on_off
    from: 'on'
    to: 'off'
    for: '00:02:00'
condidtion:
  - condition: and
    conditions:
      - condition: sun
        after: sunset
        after_offset: '-01:00:00'
      - condition: sun
        before: sunrise
  - condition: state
    entity_id: light.licht_flur_unten_1_2_zha_group_0x0003
    state: 'off'
action:
  - service: light.turn_on
    data:
      brightness_pct: 20
    target:
      entity_id: light.licht_flur_unten_1_2_zha_group_0x0003
  - delay:
      minutes: 1
  - service: light.turn_off
    target:
      entity_id: light.licht_flur_unten_1_2_zha_group_0x0003

Also changed condition to AND instead of OR. You only want the light to come on if BOTH are true.

I think the easiest way to do this is using the old method.

  - alias: ligar sala estar quando abrir porta sala a partir do por do sol
    trigger:
      platform: state
      entity_id: binary_sensor.porta_sala
      to: 'on'
    condition:
      - condition: state 
        entity_id: sun.sun
        state: "below_horizon"
      - condition: state
        entity_id: light.sala_estar
        state: "off"
    action:
      - service: script.turn_off_light
      - service: light.turn_on
        entity_id: light.sala_estar

then this script

turn_off_light:
  mode: restart
  sequence:
  - delay: "00:01:00"
  - service: light.turn_off
    entity_id: light.sala_estar

I honestly don’t like doing this method (or yours) after dealing with this issue for 5 years. Here’s what I’ve ran into over the years:

  1. No matter what, the light will turn off after the first door open. What happens when I open the door and keep it open for 2 minutes? It STILL turns off after 1 minute.

  2. What if you have a color bulb or the light is on at 50%? Wouldn’t you want to brighten the area to 100% with a ‘white’ and then return to the previous state?

  3. What happens if I don’t have lights on and I now want to keep them on? I have to wait a minute for them to turn off, then I have to turn them back on. Super annoying.

  4. What happens when you have multiple lights attached to a single door. I want to keep 1 on, the other off or vice versa?

I’ve solved all these problems, however the automation will probably scare you. If you’re up for the challenge, It’s posted below in the collapsed area:

EDIT: This might not work for you. I just realized it uses utility sensors I created with MQTT, so this method won’t work unless you integrate that. Either way, you have the code above that should work based on your requirements.

Click to see automation!

Main Automation - Handles the door illumination.

The metadata section is the configuration for doors. It also has notes on how to properly add a door to the configuration. Those were my notes to myself, but I’ll try to explain it here. Basically, you’ll be adding the following configuration to the metadata section of this automation. It requires a list of lights or switches and the duration the light will be on. The section name will be the door sensor that triggers it. You also need to add the triggering door sensor to the trigger list.

E.g. Your door sensor is binary_sensor.porta_sala, your light is light.sala_estar, and your duration is 60. I also left input_boolean.test_door and it’s accompanying switches in the automation so you can see what it looks like with multiple triggering entities.

- alias: Doors - Illuminate Door
  id: illuminate_doors_when_open
  mode: parallel
  trigger: 
  - platform: state
    entity_id:
    # - input_boolean.test_door
    - binary_sensor.porta_sala
    from: 'off'
    to: 'on'
  variables:

    # This is the metadata used to set all params for Illuminate door.
    # When you add an entity to the entities list for each door, you need to create
    # an accompanying script with the name `resume_{domain}_{object_id}: *resume_scene_after_duration`.
    # This script handles each 'timer' for each entity that is turned on.  Doing this gives
    # us the ability to cancel each 'resume' with a trigger of some sort (like double tap).
    # You also need to add the entity to the trigger in cancel_scheduled_resume_state.
    metadata: 
      binary_sensor.porta_sala:
        entities:
        - light.sala_estar
        duration: 60
      input_boolean.test_door:
        entities:
        - input_boolean.test_switch
        - input_boolean.test_switch_2
        duration: 10
    valid: >
      {{ trigger | default(none) is not none and trigger.to_state is defined and trigger.from_state is defined }}
    source: >
      {%- if valid %}
        {{ trigger.to_state.entity_id }}
      {%- endif %}
    timestamp: >
      {%- set datetime = datetime | default(now()) %}
      {{ as_timestamp(datetime) | timestamp_custom("%Y-%m-%dT%H:%M:%S.%f+00:00", datetime.tzinfo == 'UTC') }}
    object_id: >
      {{ source.split('.')[-1] }}
    sensor: > 
      sensor.{{ object_id }}_last_opened
    script: > 
      script.resume_{{ object_id }}
    last_opened: >
      {{ states(sensor) | default('') }}

    # Make entities object for scene
    current: >
      {%- if valid and source in metadata %}
        {{ metadata[source] }}
      {%- endif %}
    snapshot_entities: >
      {{ current.entities | default([]) }}
    action_data: >
      {%- macro kvp(k, v) %}{{ '"{}"'.format(k) }}: {{ '"{}"'.format(v) if v is string and not (v.startswith('{') or v.startswith('['))else v }}{% endmacro %}
      {%- macro coll(item, t='curly') %}{{ '{}{}{}'.format('{' if t == 'curly' else '[',item | join(', ') if item is iterable and item is not string else item, '}' if t == 'curly' else ']') }}{% endmacro %}
      {%- set ns = namespace(entities=[], scene_ids=[], scripts=[]) %}
      {%- set brightness = current.brightness | default(255) %}
      {%- for entity in snapshot_entities %}
        {%- set ns.scripts = ns.scripts + [ '"script.resume_{}"'.format(entity.replace('.','_'))] %}
        {%- set ns.scene_ids = ns.scene_ids + [ '"{}"'.format(entity.replace('.','_'))] %}
        {%- if entity.startswith('light.') %}
          {%- set ret = [kvp('state', 'on'), kvp('brightness', brightness)] %}
        {%- else %}
          {%- set ret = kvp('state', 'on') %}
        {%- endif %}
        {%- set ns.entities = ns.entities + [ kvp(entity, coll(ret)) ] %}
      {%- endfor %}
      {%- set ret = [ kvp('entities', coll(ns.entities | join(','))), kvp('scripts', coll(ns.scripts | join(','), 'list')), kvp('scene_ids', coll(ns.scene_ids | join(','), 'list'))] %}
      {{ coll(ret) }}
    duration: >
      {{ current.duration | default(0)}}
    delta: >
      {%- set last = as_timestamp(last_opened) %}
      {%- if last is not none %}
        {{ as_timestamp(timestamp) - as_timestamp(last_opened) }}
      {%- else %}
        {{ duration + 1 }}
      {%- endif %}
    in_duration: >
      {{ delta < duration }}

  condition: &sun_door_condition
  - condition: template
    value_template: "{{ valid }}"
  - condition: state
    entity_id: sun.sun
    state: "below_horizon"

  action:
  - choose:
    - conditions:
      - condition: template
        value_template: "{{ not in_duration }}"
      sequence:
      - repeat:
          count: "{{ action_data.scene_ids | length }}"
          sequence:
          - service: scene.create
            data:
              scene_id: "{{ action_data.scene_ids[repeat.index - 1] }}"
              snapshot_entities: "{{ snapshot_entities[repeat.index - 1] }}"

      - service: scene.apply
        data:
          entities: "{{ action_data.entities }}"
  
  - wait_template: "{{ is_state(source, 'off') }}"

  - repeat:
      count: "{{ action_data.scripts | length }}"
      sequence:
      - event: illuminate_door
        event_data:
          service: "{{ action_data.scripts[repeat.index - 1] }}"
          duration: "{{ duration }}"
          scene_id: "{{ action_data.scene_ids[repeat.index - 1] }}"

Door event handler

This handles everything so that it’s async. Meaning, you can add other doors to the previous automation and it’ll still work without waiting for other door “timers”. You don’t need to configure anything here. It’ll just run in the background.

- alias: Doors - Illuminate Event Handler
  id: illuminate_door_event_handler
  mode: parallel
  trigger:
  - platform: event
    event_type: illuminate_door
  variables:
    data: >
      {{ trigger.event.data | default({}) }}
    service: >
      {{ data.service | default }}
    duration: >
      {{ data.duration | default }}
    scene_id: >
      {{ data.scene_id | default }}
    valid: >
      {{ true if service and duration and scene_id else false }}
  condition: *sun_door_condition
  action:
  - service: "{{ service }}"
    data:
      duration: "{{ duration }}"
      scene_id: "{{ scene_id }}"

Door cancel event handler

This automation allows you to cancel the turn off events by just using the switch. If you have a switch that supports double tap actions, change the trigger to a double tap trigger. I do not have switches that support this, so I have to turn the light off then on in order for it to stay on.

- alias: Doors - Cancel Scheduled Resume State
  id: cancel_scheduled_resume_state
  mode: parallel
  trigger:
  - platform: state
    entity_id:
    - light.sala_estar
    # - input_boolean.test_switch
    # - input_boolean.test_switch_2
  variables:
    valid: >
      {{ trigger | default(none) is not none and trigger.to_state is defined and trigger.from_state is defined }}
    source: >
      {%- if valid %}
        {{ trigger.to_state.entity_id }}
      {%- endif %}
    script: >
      {{ 'script.resume_{}'.format(source.replace('.','_')) }}
  condition: *sun_door_condition
  action:
  - service: script.turn_off
    target:
      entity_id: "{{ script }}"

Scripts

Unfortunately, this method requires a script for every light. Without it, the duration doesn’t work and the automations will sit and wait until the lights turn off. We don’t want them to wait, we want the automations to continue (remember async). The script needs to be named resume__<object_id>. So if your entity_id is light.sala_estar, then the script name will be resume_light_sala_estar. The nice thing is, if you can use anchors to duplicate the script with a single line. That’s shown below with the test switches and the script for your light.

# Script 1:  The 'anchor'
resume_light_sala_estar: &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 }}

# Script 2:  Using the 'anchor'
resume_input_boolean_test_switch: *resume_scene_after_duration
# Script 3:  Using the 'anchor' again
resume_input_boolean_test_switch_2: *resume_scene_after_duration

You can checkout the automation in my github. It’s essentially the same however it manages 3 doors.

automations:

scripts:

1 Like

Sooooo, through all the time that Ive been trying to make this work, my dad failed to mention that he had a scene to turn that light off via ewelink :roll_eyes:
My automation works perfectly, and so does all the others…
Anyway, I really didnt need all the trouble with the input_boolean, like @atomicpapa said, so I kept it simple, now that everything works the way it should.

  - alias: ligar sala estar quando abrir porta sala a partir do por do sol
    trigger:
      platform: state
      entity_id: binary_sensor.porta_sala
      to: 'on'
    condition:
      - condition: state 
        entity_id: sun.sun
        state: "below_horizon"
      - condition: state
        entity_id: light.sala_estar
        state: "off"
    action:
      - service: light.turn_on
        entity_id: light.sala_estar
      - delay:
          minutes: 1
      - service: light.turn_off
        entity_id: light.sala_estar

Im so sorry for the trouble and thank you guys for your time!

3 Likes