Add window rooms template

This commit is contained in:
2026-07-26 10:56:43 +01:00
parent 09db152a61
commit a48020c985
2 changed files with 181 additions and 1 deletions
+5 -1
View File
@@ -87,7 +87,11 @@ action:
occupied: "{{ is_state(occupancy_entity, 'on') }}"
- choose:
# Case 1: Manual physical switch flipped
# Case 1: Manual physical switch flipped (either direction).
# The Shelly's edge input mode has already flipped the relay locally -
# HA must NOT issue a light.turn_on/off here, or it will fight the
# person's manual action. We only start the override timer so that
# occupancy/lux logic stays out of the way for the configured window.
- conditions:
- condition: template
value_template: "{{ trigger.id == 'manual_switch' }}"
@@ -0,0 +1,176 @@
blueprint:
name: Occupancy Lighting with Manual Override (Window Rooms)
description: >
Turns lights on when an occupancy group sensor indicates presence AND
the room is dark enough (lux below threshold). Turns lights off when
the group becomes inactive for the configured delay.
A physical switch toggle suppresses sensor-based automation for a
configurable period using a timer helper. This automation never
commands the light directly in response to the switch - it assumes
your switch/relay (e.g. a Shelly in edge/detached input mode) already
controls the light locally and instantly, independent of Home
Assistant. HA only watches for the switch event to start the override
window, so it never fights a manual on/off.
Create a 'Binary Sensor Group' helper for your room's occupancy
sensors, a 'Sensor Group' helper (mean or min) for your room's lux
sensors if you have more than one, and one timer helper per room.
domain: automation
input:
light_target:
name: Light
selector:
target:
entity:
domain: light
occupancy_group:
name: Occupancy Sensor / Group
description: Select a single binary sensor or a Binary Sensor Group helper containing this room's sensors.
selector:
entity:
domain: binary_sensor
illuminance_sensor:
name: Illuminance Sensor / Group
description: Select a lux sensor (e.g. Apollo R-Pro1 LTR390) or a Sensor Group helper averaging multiple lux sensors in this room.
selector:
entity:
domain: sensor
device_class: illuminance
illuminance_threshold:
name: Darkness threshold (lux)
description: Lights will only turn on for occupancy if measured lux is below this value. Typical indoor daylight near a window is 300-1000+ lux; a dim room is under 50 lux. Tune to taste.
default: 50
selector:
number:
min: 0
max: 2000
step: 1
mode: box
unit_of_measurement: lux
switch_input:
name: Physical switch input
description: >
Select the switch/relay's INPUT entity (e.g. a Shelly's input
binary_sensor reporting the physical toggle), NOT the light entity
itself and not a mirror of the light's on/off state. If this is
wired to something that also changes state whenever this
automation calls light.turn_on/off, you'll get a feedback loop
where the automation's own actions look like manual switch events.
selector:
entity:
domain: binary_sensor
override_timer:
name: Override timer
selector:
entity:
domain: timer
override_duration:
name: Override duration (minutes)
default: 30
selector:
number:
min: 1
max: 1440
step: 1
mode: box
unit_of_measurement: minutes
off_delay:
name: Off delay (seconds)
default: 5
selector:
number:
min: 0
max: 300
step: 1
mode: box
unit_of_measurement: seconds
mode: restart
variables:
occupancy_entity: !input occupancy_group
illuminance_entity: !input illuminance_sensor
lux_threshold: !input illuminance_threshold
timer_entity: !input override_timer
duration_minutes: !input override_duration
trigger:
- id: occupancy_change
platform: state
entity_id: !input occupancy_group
- id: manual_switch
platform: state
entity_id: !input switch_input
- id: timer_finished
platform: event
event_type: timer.finished
event_data:
entity_id: !input override_timer
# Re-evaluate if it gets dark while someone is already sitting in the room
- id: illuminance_change
platform: state
entity_id: !input illuminance_sensor
for:
seconds: 10
action:
- variables:
override_active: "{{ is_state(timer_entity, 'active') }}"
occupied: "{{ is_state(occupancy_entity, 'on') }}"
is_dark: "{{ states(illuminance_entity) | float(9999) < lux_threshold }}"
- choose:
# Case 1: Manual physical switch flipped (either direction).
# The Shelly's edge input mode has already flipped the relay locally -
# HA must NOT issue a light.turn_on/off here, or it will fight the
# person's manual action. We only start the override timer so that
# occupancy/lux logic stays out of the way for the configured window.
- conditions:
- condition: template
value_template: "{{ trigger.id == 'manual_switch' }}"
sequence:
- action: timer.start
target:
entity_id: !input override_timer
data:
# We multiply by 60 because timer.start data maps natively to HH:MM:SS or raw seconds
duration: "{{ duration_minutes * 60 }}"
# Case 2: Occupancy or lux changed, but manual override is currently active (Do Nothing)
- conditions:
- condition: template
value_template: "{{ (trigger.id in ['occupancy_change', 'illuminance_change']) and override_active }}"
sequence: []
# Case 3: Occupancy detected, override NOT active, and room is dark enough
- conditions:
- condition: template
value_template: "{{ occupied and is_dark }}"
sequence:
- action: light.turn_on
target: !input light_target
# Default Case: Not occupied, or occupied-but-bright-enough, or timer finished -> sequence handles turning off
default:
- delay:
seconds: !input off_delay
- condition: template
value_template: >
{{
not is_state(timer_entity, 'active')
and (not is_state(occupancy_entity, 'on') or states(illuminance_entity) | float(9999) >= lux_threshold)
}}
- action: light.turn_off
target: !input light_target