Migrate occupancy light blueprint to a single occupancy binary input

This commit is contained in:
Bogdan Bagno
2026-06-20 00:41:27 +01:00
parent 79dfcc348e
commit d35db4b5bf
+26 -54
View File
@@ -1,15 +1,14 @@
blueprint: blueprint:
name: Occupancy Lighting with Manual Override name: Occupancy Lighting with Manual Override
description: > description: >
Turns lights on when any presence sensor, motion sensor, or door sensor Turns lights on when an occupancy group sensor indicates presence. Turns
indicates occupancy. Turns lights off when all sensors are inactive for lights off when the group becomes inactive for the configured delay.
the configured delay.
A physical switch input (e.g. Shelly in detached mode) toggles the light A physical switch input toggles the light on any flip and suppresses
and suppresses sensor-based automation for a configurable period using a sensor-based automation for a configurable period using a timer helper.
timer helper.
Create one timer helper per room and pass it to the blueprint. Create a 'Binary Sensor Group' helper for your room's sensors, and one
timer helper per room.
domain: automation domain: automation
input: input:
light_target: light_target:
@@ -19,29 +18,12 @@ blueprint:
entity: entity:
domain: light domain: light
presence_sensors: occupancy_group:
name: Presence sensors name: Occupancy Sensor / Group
default: [] description: Select a single binary sensor or a Binary Sensor Group helper containing this room's sensors.
selector: selector:
entity: entity:
domain: binary_sensor domain: binary_sensor
multiple: true
motion_sensors:
name: Motion sensors
default: []
selector:
entity:
domain: binary_sensor
multiple: true
door_sensors:
name: Door sensors
default: []
selector:
entity:
domain: binary_sensor
multiple: true
switch_input: switch_input:
name: Physical switch input name: Physical switch input
@@ -56,15 +38,15 @@ blueprint:
domain: timer domain: timer
override_duration: override_duration:
name: Override duration (seconds) name: Override duration (minutes)
default: 1800 default: 30
selector: selector:
number: number:
min: 60 min: 1
max: 86400 max: 1440
step: 60 step: 1
mode: box mode: box
unit_of_measurement: seconds unit_of_measurement: minutes
off_delay: off_delay:
name: Off delay (seconds) name: Off delay (seconds)
@@ -80,29 +62,18 @@ blueprint:
mode: restart mode: restart
variables: variables:
presence_entities: !input presence_sensors occupancy_entity: !input occupancy_group
motion_entities: !input motion_sensors
door_entities: !input door_sensors
timer_entity: !input override_timer timer_entity: !input override_timer
duration_minutes: !input override_duration
trigger: trigger:
- id: occupancy_change - id: occupancy_change
platform: state platform: state
entity_id: !input presence_sensors entity_id: !input occupancy_group
- id: occupancy_change
platform: state
entity_id: !input motion_sensors
- id: occupancy_change
platform: state
entity_id: !input door_sensors
- id: manual_switch - id: manual_switch
platform: state platform: state
entity_id: !input switch_input entity_id: !input switch_input
from: "off"
to: "on"
- id: timer_finished - id: timer_finished
platform: event platform: event
@@ -113,14 +84,10 @@ trigger:
action: action:
- variables: - variables:
override_active: "{{ is_state(timer_entity, 'active') }}" override_active: "{{ is_state(timer_entity, 'active') }}"
occupied: > occupied: "{{ is_state(occupancy_entity, 'on') }}"
{{
(presence_entities | length > 0 and expand(presence_entities) | selectattr('state', 'eq', 'on') | list | count > 0) or
(motion_entities | length > 0 and expand(motion_entities) | selectattr('state', 'eq', 'on') | list | count > 0) or
(door_entities | length > 0 and expand(door_entities) | selectattr('state', 'eq', 'on') | list | count > 0)
}}
- choose: - choose:
# Case 1: Manual physical switch flipped
- conditions: - conditions:
- condition: template - condition: template
value_template: "{{ trigger.id == 'manual_switch' }}" value_template: "{{ trigger.id == 'manual_switch' }}"
@@ -131,13 +98,16 @@ action:
target: target:
entity_id: !input override_timer entity_id: !input override_timer
data: data:
duration: !input override_duration # We multiply by 60 because timer.start data maps natively to HH:MM:SS or raw seconds
duration: "{{ duration_minutes * 60 }}"
# Case 2: Occupancy changed, but manual override is currently active (Do Nothing)
- conditions: - conditions:
- condition: template - condition: template
value_template: "{{ trigger.id == 'occupancy_change' and override_active }}" value_template: "{{ trigger.id == 'occupancy_change' and override_active }}"
sequence: [] sequence: []
# Case 3: Occupancy detected and override is NOT active
- conditions: - conditions:
- condition: template - condition: template
value_template: "{{ occupied }}" value_template: "{{ occupied }}"
@@ -145,6 +115,7 @@ action:
- action: light.turn_on - action: light.turn_on
target: !input light_target target: !input light_target
# Default Case: No occupancy detected / timer finished -> sequence handles turning off
default: default:
- delay: - delay:
seconds: !input off_delay seconds: !input off_delay
@@ -155,3 +126,4 @@ action:
}} }}
- action: light.turn_off - action: light.turn_off
target: !input light_target target: !input light_target