I am somewhat new to home automation and one area I am struggling with, is eliminating the fight between user actions and automations over the controlled entities (i.e. Light)
i.e. User turns light off from switch, but motion based automation turns it back on, right after that.
We are both right, but user action shall prevail.
Which are the suggested ways to address fight over devices?
Only thing I can think of is to use timers to see what happened recently to figure wether your automation should run. E.g. if the light is turned off and motion was off for longer than x time (motion didnāt turn it off) then start a timer āmanual offā. If the timer manual off is running, do not turn the light on using motion.
But first think if you can make the motion detection logic smarter so you wonāt have to fight it. If you need to fight it a lot, then the automation is not helping but annoying. Also, it may be annoying that if one person uses the manual switch to turn the light off, a few second later someone else is wondering why motion detection isnāt working.
Good question. It got me thinking about why Iāve never really liked motion-activated lights inside. Simply put: What if I want the lights off?
I picture myself getting up at night to go to the bathroom, or walking through a hall to reach another room. I donāt want (in the first case) or need (in the second case) the lights on. Or I might be watching TV or otherwise engaged in an activity which shouldnāt be illuminated
Without automation, I wouldnāt have to touch the switch. Iād just leave it off. If an automation makes it any harder than that (like, having to go turn it off after it came on unwanted) thatās a fail.
I first think hard: do I need it and will it work reasonably well. For instance on the staircase to the top floor it is really dark sometimes. So I did put one there, but I only turn it on at a light glow setting on the dimmer to make it acceptable at night. If I walk past to go to the bathroom, I do not want to trigger it by accident. So I pointed it to have minimal chance on false triggers.
Then I put in extra conditions: not when it is light enough, not when the light is already on, not when the house is set on sleep mode for more than 5 minutes. I never go there when we are supposed to be in bed, but maybe right after I put the house in sleep mode. And then I automated the buttons: if I use those for on, and the light is dim from the motion, I turn it on much brighter and kill the timer that turns it off when motion ends. By the way, I only set the timer on motion, so if the light was already on it wonāt go off either.
That way I have full manual control if I want, but light if Iām carrying some stuff to the top floor.
I very rarely automate lights since they are very dynamic, examples of which can be found above.
the only way lighting can be functionally automated is if the behavior can be reliably modeled by the behavior being consistent.
a few examples for me are:
my deck light is always on from sunset to 1 am. Or if after 1 am itās still dark out and the door to the deck is open.
I turn my computer room light on manually. After 30 minutes if there is no motion I have my Echo device ask if HA should turn off the light. If I say yes or there is no response then the light goes off. Otherwise (me saying no) I reset the 30 minute timer. (I had a hard time remembering to turn the light off if I left āfor a minuteāā¦ )
my garage lights only need to be on if one of the garage doors are open or if there is motion in the garage. I also control that behavior with an actionable notification, as well, so the lights donāt turn off if Iām under the car.
I have a select entity for every room. Its state is on (automation in control), off (automation disabled until specifically turned back on, primarily at night) and override (automation disabled temporarily, state times out and reverts to on after 30 min of inactivity or 2 hours of continuous activity). The presence lights automation checks this before changing anything in a room.
The select entity itself is also automated. They are all trigger template selects and listen for any changes in lights in their room. When a light changes it checks the context. If user_id is set then the changes was initiated by a user via either HA or Google assistant. Is parent_id is set then the change was initiated by an automation. If neither is set then the change was initiated externally (in my house that means someone pressed the light switch on the wall). If the source was not an automation then the select becomes state override if it was on for a while.
Similar if someone goes to sleep in a room. Then the select entity in that room becomes state off. Until it is detected that everyone in that room is awake then it goes back to on.
Honestly havenāt really had any issues with it. Well at least not with that part. My main problem is simply a lack of a good way to detect occupancy downstairs since we have an open floor plan and canāt use motion sensors due to cats. Still working on that. Upstairs works extremely well though, good occupancy sensors and detecting overrides is very reliable.
So I actually only have one single automation for my presence lights and its surprisingly simple. The real work around checking context and such is actually in the controllers (the trigger template selects I mentioned earlier), hereās those:
The controllers are the ones watching for sleep changes, light changes, etc. and checking context to automatically set themselves in the correct state (on, off or override). The automation then simply listens for presence events and calls the correct scene/script if the controller lets it:
- id: a6ff604da4c843d98102bbcf0240e890_automation_presence_lights
alias: Presence lights
description: Turn on and off rooms based on presence, light level and current overrides
mode: parallel
max: 25
trace:
stored_traces: 15
variables: !include_dir_named /config/common/auto/room_presence
trigger:
- id: input_change
platform: state
entity_id: !include_dir_merge_list /config/common/auto/room_presence/inputs
to: ['off', 'on', 'override']
from: ['off', 'on', 'override']
- platform: state
entity_id:
- binary_sensor.away_lights_active
- switch.emergency_override
from: 'on'
to: 'off'
condition: "{{ not is_state('switch.emergency_override', 'on') }}"
action:
alias: Loop through rooms
repeat:
for_each: >-
{{ ([area_name(trigger.entity_id)] if trigger.id == 'input_change' else rooms) | list }}
sequence:
- variables:
entities: "{{ area_entities(repeat.item) }}"
controller: "{{ controllers | select('in', entities) | first }}"
detector : "{{ detectors | select('in', entities) | first }}"
light_sensor: "{{ light_sensors | select('in', entities) | first }}"
off_scene: "{{ off_scenes | select('in', entities) | first }}"
on_script: "{{ on_scripts | select('in', entities) | first }}"
- alias: Is room controller on and sensors in a valid state
if:
- "{{ is_state(controller, 'on') }}"
- "{{ states(detector) in ['on', 'off'] }}"
- "{{ states(light_sensor) in ['on', 'off'] }}"
then:
alias: Room is occupied
if: "{{ is_state(detector, 'on') }}"
then:
service: "{{ on_script }}"
else:
alias: Room is unoccupied
service: scene.turn_on
data:
entity_id: "{{ off_scene }}"
transition: 2.5
Some things to clarify about my setup here:
/config/common/auto/room_presence looks like this
Each of those files has a list of entity IDs for that type of thing (except rooms.yaml which has a list of rooms). So when you see !include references to that folder above, thatās whatās in there. Remember that !include_dir_named uses the file names to make a dictionary (controllers, detectors, etc.) whereas !include_dir_merge_list merges all the files in that folder into one big list
When the trigger for this automation is in one of the rooms with a controller then the automation just changes that room. If its not (either because I manually triggered the automation or it was an area-less event like us arriving home) then it loops through all the rooms and sees if thereās anything to do.
This is because I wanted the automation to be stateless, to put my whole house in the right state lights-wise every time it is run and not actually depend on the trigger. But I found performance wasnāt great like that, I would walk into a room and if that room happened to be at the end of the list there was a noticeable delay before the lights turned on as it processed the other rooms. So it can still operate statelessly but usually just processes the room the presence event came from.
If my smoke/co detectors say there is an emergency then lights turn on full blast and emergency_override turns on, thatās why that condition is there. And then after that turns off the trigger fires and this reprocesses all the rooms.
Why do I have scripts to turn rooms on and scenes to turn them off? Because off is trivial (everything ā off) but on isnāt. The reason is because of light levels and google assistant. When presence lights turns lights on it sets them to 50%. But what if someone has set one light above that manually? Then donāt lower it. Only make lights brighter or adjust automation changed lights. However I also expose the scripts to google assistant and if someone says āKitchen onā then it should forcibly set the lights to 50% regardless of what theyāre currently at. So my scripts handle that. Theyāre all basically the same, hereās an example:
room_on_bedroom:
alias: Room on - Bedroom
icon: mdi:lightbulb-group
mode: single
max_exceeded: silent
variables:
lights: "{{ state_attr('light.bedroom', 'entity_id') }}"
outlets: switch.bedroom_tv_outlet
bright: "{{ is_state('binary_sensor.bright_bedroom', 'on') }}"
sequence: &room-on-sequence
parallel:
- if: "{{ outlets is defined and outlets | count > 0 }}"
then:
alias: Turn on outlets
service: switch.turn_on
data:
entity_id: "{{ outlets }}"
- sequence:
- variables:
auto_change: "{{ not (not context.parent_id or context.user_id) }}"
- choose:
- alias: Change initiated by automation and room is bright
conditions: "{{ auto_change and bright }}"
sequence:
alias: Lights off
service: light.turn_off
data:
entity_id: "{{ lights }}"
- alias: Change initiated by automation and room is dark
conditions: "{{ auto_change }}"
sequence:
- alias: Filter out lights brighter then 50%
variables:
low_lights: >-
{% set e_lights = expand(lights) %}
{{ e_lights
| selectattr('state', 'eq', 'off')
| map(attribute='entity_id') | list
+ e_lights
| selectattr('state', 'eq', 'on')
| selectattr('attributes.brightness', 'lt', 127)
| map(attribute='entity_id') | list
+ e_lights
| selectattr('state', 'eq', 'on')
| selectattr('attributes.brightness', 'gt', 127)
| selectattr('context.user_id', 'none')
| rejectattr('context.parent_id', 'none')
| map(attribute='entity_id') | list }}
- alias: Lights to 50%
service: light.turn_on
data:
entity_id: "{{ low_lights }}"
brightness: 127
default:
alias: Always set lights to 50% if change is user initiated
service: light.turn_on
data:
entity_id: "{{ lights }}"
brightness: 127
room_on_guest_room:
alias: Room on - Guest Room
icon: mdi:lightbulb-group
mode: single
max_exceeded: silent
sequence: *room-on-sequence
variables:
lights: ["light.guest_room"]
outlets:
- switch.guest_room_left_monitor_outlet
- switch.guest_room_right_monitor_outlet
bright: "{{ is_state('binary_sensor.bright_guest_room', 'on') }}"
The sequence is literally an anchor like Iām showing for guest room in all the others, the only difference is what lights and outlets are in that room and what decides if its already bright in there.
Also note that in here I also check context. Thatās how I determine if this script was started by automation or by a human (either clicking a button or telling google assistant to run it). Or if the lights were last changed by a human or by automation.
This is a lot I know. Feel free to ask if you have other questions. I thought about putting together a package but I feel like a lot of this is tied to my particular rooms and things so Iām not sure how useful that would be. Iāll think about it though.
I generally use occupancy to handle these types of things. Iāll turn it on when occupancy is detected, turn it off when it has expired after some time (timer). If its actioned while the occupancy is already set (before the timer expires at the exit), then leave it.
Occupancy: I use box/wasp appdaemon in conjuntion with things like ātv onā and other activity in the room to formulate if a room is occupied.
Iāve also used wait for logic to detect if the switch was toggled during the timer and if that is the case, I extend the timer significantly because I assume the user wanted it to stay that way. I still use the timer though with an extended amount of time to put it back on automation after some hours just incase it was forgotten.
Lastly, iāve used triple double tabs during a short frequency to toggle a āmanual onlyā operation until its manually turned back on. My light switches have an LED on them, and I keep that off while its on automatic and ON when it is manual so I can āseeā it. The LED becomes the manual switch override.
hi Mike,
I have to say my head is spinning by trying to understand what youāre doing. This is an absolute compliment
I am trying to put together the triggers like you did in Presence lights, but I stumble across this declaration for entity_id:
trigger:
- id: input_change
platform: state
entity_id: !include_dir_merge_list /config/common/auto/room_presence/inputs
to: ['off', 'on', 'override']
from: ['off', 'on', 'override']
I am getting errors trying to get the !include to work, and I am wondering if is because I shall also have the package āhackā in place. Talking about the the wildcard state triggers solution you are mentioning in the forum.
To use that !include directive the folder /config/common/auto/room_presence/inputs would need to exist on your system. And every file in it would need to be a yaml file containing a list of entity IDs. They each would look like this:
Oh I see the problem. !include does not work in the GUI editor for automations and scripts, even in YAML mode.
You can enter that in your automations.yaml file but tbh that wonāt really work either. It will save and load if you do that but as soon as you change any automation in the GUI it will rewrite that file completely. And when it does it will suck in the contents of the yaml files in config/auto/inputs and replace the !include with a hard-coded list.
If you want to use !include in an automation you can only do so in a YAML-only automation. You can follow the directions here to see how to make a separate set of automations that is only editable in YAML and canāt be modified in the GUI. Thatās the only way to use any of the !include directives in there, otherwise you will have to insert the list of entity IDs directly in the GUI/YAML.
EDIT: Other then that your file and folder structure is fine. You donāt have to use my wildcard state triggers project. Everything you have is good other then it doesnāt work in the GUI.