Skip to content

Commit e9fdb34

Browse files
committed
Add Scene Cycle Controller
1 parent 3ce673a commit e9fdb34

File tree

1 file changed

+172
-0
lines changed

1 file changed

+172
-0
lines changed
+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
blueprint:
2+
name: Scene Cycle Controller
3+
description: >
4+
Controls multiple lights using a set of scenes. A primary button cycles through scenes (excluding motion scenes).
5+
Optional PIR or presence sensors trigger a motion scene with auto-off functionality. Scenes reset to the beginning
6+
if lights are turned off by other means (e.g., central light-off command).
7+
domain: automation
8+
input:
9+
cycle_button:
10+
name: Cycle button
11+
description: Button to cycle through scenes.
12+
selector:
13+
entity:
14+
domain: binary_sensor
15+
off_button:
16+
name: Off button
17+
description: Button to activate the "off" scene.
18+
selector:
19+
entity:
20+
domain: binary_sensor
21+
pir_sensor:
22+
name: Motion or presence sensor (optional)
23+
description: Optional motion or presence sensor for triggering a motion scene.
24+
selector:
25+
entity:
26+
domain: binary_sensor
27+
device_class: motion | presence
28+
default: null
29+
illuminance_sensor:
30+
name: Illuminance sensor (optional)
31+
description: Sensor to check room brightness for PIR-triggered lighting.
32+
selector:
33+
entity:
34+
domain: sensor
35+
device_class: illuminance
36+
default: null
37+
illuminance_threshold:
38+
name: Illuminance threshold
39+
description: Maximum illuminance level to allow automatic lighting.
40+
default: 50
41+
selector:
42+
number:
43+
min: 0
44+
max: 1000
45+
unit_of_measurement: lx
46+
scenes:
47+
name: Scenes
48+
description: List of scenes to cycle through (excluding motion and off scenes).
49+
selector:
50+
entity:
51+
domain: scene
52+
multiple: true
53+
motion_scene:
54+
name: Motion scene (optional)
55+
description: Scene to activate when motion is detected.
56+
selector:
57+
entity:
58+
domain: scene
59+
default: null
60+
off_scene:
61+
name: Off scene
62+
description: Scene representing all lights off.
63+
selector:
64+
entity:
65+
domain: scene
66+
auto_off_delay:
67+
name: Auto-off delay
68+
description: Time in seconds before the motion scene is turned off automatically.
69+
default: 300
70+
selector:
71+
number:
72+
min: 0
73+
max: 3600
74+
unit_of_measurement: seconds
75+
76+
mode: restart
77+
78+
variables:
79+
cycle_button: !input cycle_button
80+
off_button: !input off_button
81+
pir_sensor: !input pir_sensor
82+
illuminance_sensor: !input illuminance_sensor
83+
illuminance_threshold: !input illuminance_threshold
84+
scenes: !input scenes
85+
motion_scene: !input motion_scene
86+
off_scene: !input off_scene
87+
auto_off_delay: !input auto_off_delay
88+
cycle_scenes: >
89+
{{ scenes | reject('eq', motion_scene) | list }}
90+
91+
trigger:
92+
- platform: state
93+
entity_id: !input cycle_button
94+
to: "on"
95+
- platform: state
96+
entity_id: !input off_button
97+
to: "on"
98+
- platform: state
99+
entity_id: !input pir_sensor
100+
to: "on"
101+
- platform: state
102+
entity_id: !input off_scene
103+
104+
action:
105+
- choose:
106+
# Handle cycle button: cycle through scenes (excluding motion scene)
107+
- conditions:
108+
- condition: trigger
109+
id: cycle_button
110+
sequence:
111+
- variables:
112+
current_scene: >
113+
{% set most_recent_scene = cycle_scenes | map('states', 'scene') | sort(reverse=true) | first %}
114+
{{ cycle_scenes.index(most_recent_scene) if most_recent_scene in cycle_scenes else -1 }}
115+
next_scene: >
116+
{% set scene_count = cycle_scenes | length %}
117+
{{ (current_scene + 1) % scene_count if current_scene >= 0 else 0 }}
118+
- service: scene.turn_on
119+
target:
120+
entity_id: "{{ cycle_scenes[next_scene] }}"
121+
122+
# Handle off button: activate "off" scene
123+
- conditions:
124+
- condition: trigger
125+
id: off_button
126+
sequence:
127+
- service: scene.turn_on
128+
target:
129+
entity_id: !input off_scene
130+
131+
# Handle motion detection: activate motion scene (if defined)
132+
- conditions:
133+
- condition: template
134+
value_template: "{{ pir_sensor is not none and trigger.entity_id == pir_sensor }}"
135+
- condition: or
136+
conditions:
137+
- condition: template
138+
value_template: "{{ illuminance_sensor is none }}"
139+
- condition: template
140+
value_template: >
141+
{{ states(illuminance_sensor) | int <= illuminance_threshold }}
142+
sequence:
143+
- service: scene.turn_on
144+
target:
145+
entity_id: !input motion_scene
146+
- wait_for_trigger:
147+
- platform: state
148+
entity_id: !input pir_sensor
149+
to: "off"
150+
timeout: "{{ auto_off_delay }}"
151+
- choose:
152+
- conditions:
153+
- condition: state
154+
entity_id: !input cycle_button
155+
state: "off"
156+
sequence:
157+
- service: scene.turn_on
158+
target:
159+
entity_id: !input off_scene
160+
161+
# Reset scene cycling if off scene was activated (by any means)
162+
- conditions:
163+
- condition: template
164+
value_template: >
165+
{{ states(off_scene) is not none and
166+
(as_timestamp(now()) - as_timestamp(states(off_scene).last_updated)) < 60 }}
167+
sequence:
168+
- variables:
169+
next_scene: 0
170+
- service: scene.turn_on
171+
target:
172+
entity_id: "{{ cycle_scenes[next_scene] }}"

0 commit comments

Comments
 (0)