Last active
June 13, 2026 21:01
-
-
Save iwarner/b6a640fe4c26edb764b98bf119c60730 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: Synapse - Motion Sensor Lights | |
| description: > | |
| V1.0.0 — Control lights with a Philips Hue Motion Sensor (SML001/SML002) via ZHA. | |
| Trigger: occupancy detected → turn on lights (optional lux gate). | |
| Timer: no new motion for configured timeout → turn off. | |
| Optional: night mode with lower brightness and warmer colour temperature. | |
| Optional: disable entity (sleep mode switch, TV media player). | |
| IMPORTANT — entity selection: use the "Occupancy" binary_sensor. | |
| Do NOT use the "Motion" or "On/Off" entities — these are dead/unreliable | |
| with the PhilipsMotion quirk (ZHA bug, always off). | |
| domain: automation | |
| source_url: https://gist.github.com/iwarner/b6a640fe4c26edb764b98bf119c60730 | |
| author: iwarner | |
| homeassistant: | |
| min_version: "2024.6.0" | |
| input: | |
| occupancy_sensor: | |
| name: Occupancy Sensor | |
| description: > | |
| Select the Occupancy binary_sensor from the Philips Hue motion sensor device. | |
| In ZHA device page → Sensors → look for "Occupancy" (device_class: occupancy). | |
| Do NOT select "Motion" or "On/Off" — those are unreliable. | |
| selector: | |
| entity: | |
| domain: binary_sensor | |
| device_class: occupancy | |
| light_target: | |
| name: Light(s) | |
| description: Light entity, ZHA group entity, or area to control. | |
| selector: | |
| target: | |
| entity: | |
| domain: light | |
| no_motion_timeout: | |
| name: No Motion Timeout | |
| description: > | |
| Seconds after last detected motion before lights turn off. | |
| HA controls this timer — independent of the sensor's internal Zigbee timeout. | |
| Each new motion detection resets the timer from zero. | |
| default: 120 | |
| selector: | |
| number: | |
| min: 10 | |
| max: 3600 | |
| step: 10 | |
| unit_of_measurement: seconds | |
| mode: box | |
| illuminance_sensor: | |
| name: Illuminance Sensor (optional) | |
| description: > | |
| If set, lights only turn on when lux is below the threshold. | |
| Use the illuminance sensor from the same motion sensor device. | |
| Leave empty to always turn on regardless of ambient light. | |
| default: | |
| selector: | |
| entity: | |
| domain: sensor | |
| device_class: illuminance | |
| lux_threshold: | |
| name: Lux Threshold | |
| description: > | |
| Only turn on lights if illuminance is below this value. | |
| Ignored if no illuminance sensor is set. | |
| Typical indoor dark threshold: 30-80 lx. Closets with no windows: not needed. | |
| default: 50 | |
| selector: | |
| number: | |
| min: 0 | |
| max: 3000 | |
| step: 5 | |
| unit_of_measurement: lx | |
| mode: box | |
| daytime_brightness: | |
| name: Daytime Brightness | |
| description: Brightness percentage when not in night mode. | |
| default: 80 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 100 | |
| step: 1 | |
| unit_of_measurement: "%" | |
| mode: slider | |
| daytime_colour_temp: | |
| name: Daytime Colour Temperature (K) | |
| description: > | |
| 6500K = cool white, 4000K = neutral white, 2700K = warm white. | |
| default: 4000 | |
| selector: | |
| number: | |
| min: 2200 | |
| max: 6535 | |
| step: 100 | |
| unit_of_measurement: K | |
| mode: box | |
| nighttime_brightness: | |
| name: Night Brightness | |
| description: > | |
| Brightness at night. Use a very low value (10-20%) to avoid blinding | |
| when waking in the dark. | |
| default: 15 | |
| selector: | |
| number: | |
| min: 1 | |
| max: 100 | |
| step: 1 | |
| unit_of_measurement: "%" | |
| mode: slider | |
| nighttime_colour_temp: | |
| name: Night Colour Temperature (K) | |
| description: > | |
| 2200K = very warm amber — preserves night vision and minimises sleep disruption. | |
| default: 2200 | |
| selector: | |
| number: | |
| min: 2200 | |
| max: 6535 | |
| step: 100 | |
| unit_of_measurement: K | |
| mode: box | |
| night_start: | |
| name: Night Mode Start | |
| description: Time at which night mode begins (local time). | |
| default: "22:00:00" | |
| selector: | |
| time: | |
| night_end: | |
| name: Night Mode End | |
| description: Time at which night mode ends (local time). | |
| default: "07:00:00" | |
| selector: | |
| time: | |
| disable_entity: | |
| name: Disable Entity (optional) | |
| description: > | |
| When active, motion is ignored. input_boolean: disabled when 'on'. | |
| media_player: disabled when 'playing' or 'paused'. Leave empty to never disable. | |
| default: | |
| selector: | |
| entity: | |
| domain: | |
| - input_boolean | |
| - binary_sensor | |
| - media_player | |
| trigger: | |
| - platform: state | |
| entity_id: !input occupancy_sensor | |
| to: "on" | |
| condition: [] | |
| variables: | |
| illuminance_sensor: !input illuminance_sensor | |
| lux_threshold: !input lux_threshold | |
| disable_entity: !input disable_entity | |
| night_start: !input night_start | |
| night_end: !input night_end | |
| daytime_brightness: !input daytime_brightness | |
| daytime_colour_temp: !input daytime_colour_temp | |
| nighttime_brightness: !input nighttime_brightness | |
| nighttime_colour_temp: !input nighttime_colour_temp | |
| no_motion_timeout: !input no_motion_timeout | |
| is_night: > | |
| {% set t = now().strftime('%H:%M:%S') %} | |
| {% if night_start > night_end %} | |
| {{ t >= night_start or t < night_end }} | |
| {% else %} | |
| {{ night_start <= t < night_end }} | |
| {% endif %} | |
| active_brightness: "{{ nighttime_brightness if is_night else daytime_brightness }}" | |
| active_colour_temp: "{{ nighttime_colour_temp if is_night else daytime_colour_temp }}" | |
| lux_ok: > | |
| {% if illuminance_sensor == none %} | |
| true | |
| {% else %} | |
| {{ states(illuminance_sensor) | float(0) < lux_threshold }} | |
| {% endif %} | |
| disable_active: > | |
| {% if disable_entity == none %} | |
| false | |
| {% else %} | |
| {{ states(disable_entity) in ['on', 'playing', 'paused'] }} | |
| {% endif %} | |
| action: | |
| - condition: template | |
| value_template: "{{ lux_ok and not disable_active }}" | |
| - service: light.turn_on | |
| target: !input light_target | |
| data: | |
| brightness_pct: "{{ active_brightness }}" | |
| color_temp_kelvin: "{{ active_colour_temp }}" | |
| transition: 1 | |
| - delay: | |
| seconds: "{{ no_motion_timeout }}" | |
| - service: light.turn_off | |
| target: !input light_target | |
| data: | |
| transition: 2 | |
| mode: restart | |
| max_exceeded: silent |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment