How I do granular control of automated lights

If you want simple motion-controlled lights, this will be overkill.

My goal was for lights (or anything else, but I’ll just call them lights) to be automated by motion, or doors opening (or anything else), which a non-technical person can easily override e.g. if they want a light to stay on, no automation will turn it off

I also want my automations to control groups of lights and for any light to be in any number of groups e.g. the porch light and floodlights come on if someone rings the doorbell at night, but the porch light and the foyer light come if you open the door

To make this work I created a timer for each light that I want to automate. To simplify templates, each timer uses the same name as its light e.g. switch.hall_light and timer.hall_light

Timers are implicit when you turn-on something for some period of time, but making them explicit gives us more control

Three automations do most of the work (code is below)

  1. Whenever a timer is started, an automation turns on its light
  2. whenever a timer is finished, an automation turns off its light
  3. Whenever a light goes off, an automation cancels its timer

Whenever a trigger occurs, (door is opened, alarm goes off, arrive home, motion sensed etc,) all I need to do is start timers for whatever lights I want to control. Each trigger can set different times for different lights. (I also have a rarely-needed override on my App that allows me to change the mode of any trigger to either: always, night-only, or off)

Triggers follow a few rules
A If the light is off, start a timer for it (and Automation 1 will turn it on)
B If the light is on with a timer running, extend the timer
C If the light is on with no timer running, do nothing

Rule C allows anyone to override any light just by turning it on (if it’s already on, they first turn it off (which kills the timer) then on which prevents it from being controlled by any automation

Manually controlling the light can be done with a wall switch, or with the app or voice control. The app and voice control are programmed to automatically turn off the light before it is turned on which (if it was already on) provides a nice blink so someone knows they have taken control of the light

On my app, the button for each light also shows the remaining time on its timer (if any) which lets anyone know if that light is on by automation or because someone turned it on

That’s it. Below is my code for the three automations. This could be improved to allow different domains (all my lights are switches, so I don’t have code for the light domain)

My triggers are mostly in Node Red, but anything should work if you follow the three rules.

- alias: "Timer Finished to Switch"
  mode: parallel
  trigger:
    - platform: event
      event_type: timer.finished
  action:
    - service: switch.turn_off
      data:
        entity_id: "switch.{{ trigger.event.data.entity_id.split('.')[-1] }}"

- alias: "Timer Started to Switch"
  mode: parallel
  trigger:
    - platform: event
      event_type: timer.started
  action:
    - service: switch.turn_on
      data:
        entity_id: "switch.{{ trigger.event.data.entity_id.split('.')[-1] }}"

- alias: "Switch State to Cancel Timer"
  mode: parallel
  trigger:
    - platform: state
      to: "off"
      entity_id:
        - switch.office_credenza
        - switch.office_desk
#
# etc. for every light that is automated 
# (for the state platform, I believe I need to # specify each entity id in the trigger
# please correct me if I'm wrong) 
#
  action:
    - service: timer.cancel
      data:
        entity_id: "timer.{{ trigger.to_state.entity_id.split('.')[-1] }}"
2 Likes