Skip to content

Instantly share code, notes, and snippets.

@cbenard
Last active June 25, 2025 02:30
Motion-Activated Light with Light Sensor and Mode Support
blueprint:
name: Motion-Activated Light with Optional Modes and Light Sensor
description: >
Turns on lights with optional mode-based day/night logic.
Defensive template usage avoids undefined input errors.
Wait times are in minutes. Modes are CSV strings. Supports multiple lights and optional max-on-time.
domain: automation
author: Chris Benard (assisted by ChatGPT)
input:
motion_sensor:
name: Motion or Occupancy Sensor (Required)
selector:
entity:
domain: binary_sensor
device_class:
- motion
- occupancy
light_target:
name: Lights to Control (Required)
selector:
target:
entity:
domain: light
daytime_wait_minutes:
name: Day Timeout (minutes) (Required)
default: 5
selector:
number:
min: 0.5
max: 180
step: 0.1
unit_of_measurement: min
enable_max_on_time:
name: Enforce Max On Time if No Motion? (Optional)
default: false
selector:
boolean: {}
max_on_minutes:
name: Max On Time (minutes) (Optional, used if above enabled)
default: 30
selector:
number:
min: 0.5
max: 180
step: 0.1
unit_of_measurement: min
mode_select:
name: Mode Selector (input_select) (Optional)
default: null
selector:
entity:
domain: input_select
day_modes:
name: Day Modes (CSV) (Optional)
default: ""
selector:
text:
night_modes:
name: Night Modes (CSV) (Optional)
default: ""
selector:
text:
use_light_sensor:
name: Use Light Sensor? (Optional)
default: false
selector:
boolean: {}
light_sensor:
name: Light Sensor (Optional)
default: null
selector:
entity:
domain: sensor
device_class: illuminance
light_threshold:
name: Light Level Threshold (Optional, lx)
default: 50
selector:
number:
min: 0
max: 1000
unit_of_measurement: lx
nighttime_wait_minutes:
name: Night Timeout (minutes) (Optional)
default: null
selector:
number:
min: 0.5
max: 180
step: 0.1
unit_of_measurement: min
daytime_brightness:
name: Day Brightness (%) (Optional)
default: null
selector:
number:
min: 1
max: 100
unit_of_measurement: percent
nighttime_brightness:
name: Night Brightness (%) (Optional)
default: null
selector:
number:
min: 1
max: 100
unit_of_measurement: percent
mode: restart
trigger:
- platform: state
entity_id: !input motion_sensor
to: "on"
id: motion_detected
- platform: state
entity_id: !input motion_sensor
to: "off"
id: motion_cleared
variables:
motion_sensor: !input motion_sensor
light_target: !input light_target
daytime_wait_minutes: !input daytime_wait_minutes
nighttime_wait_minutes: !input nighttime_wait_minutes
enable_max_on_time: !input enable_max_on_time
max_on_minutes: !input max_on_minutes
mode_entity_id: !input mode_select
day_modes_str: !input day_modes
night_modes_str: !input night_modes
use_sensor: !input use_light_sensor
sensor_entity_id: !input light_sensor
threshold: !input light_threshold
daytime_brightness: !input daytime_brightness
nighttime_brightness: !input nighttime_brightness
light_entities: "{{ expand(light_target.entity_id) | map(attribute='entity_id') | list }}"
mode_enabled: >-
{{
mode_entity_id is not none and
day_modes_str is defined and day_modes_str|trim != '' and
night_modes_str is defined and night_modes_str|trim != ''
}}
day_modes: >-
{% if day_modes_str is defined and day_modes_str|trim != '' %}
{{ day_modes_str.split(',') | map('trim') | list }}
{% else %}
[]
{% endif %}
night_modes: >-
{% if night_modes_str is defined and night_modes_str|trim != '' %}
{{ night_modes_str.split(',') | map('trim') | list }}
{% else %}
[]
{% endif %}
current_mode: >-
{{
mode_enabled
and mode_entity_id is not none
and states[mode_entity_id] is not none
and states[mode_entity_id].state or ''
}}
is_day_mode: >-
{{
mode_enabled
and current_mode in day_modes
or not mode_enabled
}}
is_night_mode: >-
{{
mode_enabled
and current_mode in night_modes
or false
}}
day_wait: "{{ (daytime_wait_minutes | float) * 60 }}"
night_wait: >-
{{
((nighttime_wait_minutes if nighttime_wait_minutes is not none else daytime_wait_minutes) | float) * 60
}}
wait_time: >-
{{
is_night_mode and mode_enabled
and night_wait
or day_wait
}}
brightness: >-
{{ nighttime_brightness if is_night_mode and mode_enabled and nighttime_brightness is not none
else daytime_brightness if is_day_mode and daytime_brightness is not none
else 'none' }}
max_time: "{{ (max_on_minutes | float(30)) * 60 }}"
action:
- if:
- condition: template
value_template: "{{ trigger.id == 'motion_detected' }}"
then:
- if:
- condition: template
value_template: >
{{
not use_sensor
or
(
sensor_entity_id is not none
and
states[sensor_entity_id] is not none
and
states[sensor_entity_id] | float(0) <= threshold | float(0)
)
}}
then:
- if:
- condition: template
value_template: "{{ brightness != 'none' }}"
then:
- service: light.turn_on
data:
brightness_pct: "{{ brightness | float }}"
target: !input light_target
else:
- service: light.turn_on
target: !input light_target
- if:
- condition: template
value_template: "{{ trigger.id == 'motion_cleared' }}"
then:
- wait_for_trigger:
- platform: state
entity_id: !input motion_sensor
to: "on"
timeout: "{{ wait_time | float }}"
continue_on_timeout: true
- if:
- condition: template
value_template: >
{{
is_state(motion_sensor, 'off')
and
expand(light_target.entity_id) | selectattr('state', 'eq', 'on') | list | count > 0
}}
then:
- service: light.turn_off
target: !input light_target
- if:
- condition: template
value_template: "{{ enable_max_on_time }}"
then:
- wait_for_trigger:
- platform: state
entity_id: !input motion_sensor
to: "on"
timeout: "{{ max_time | float }}"
continue_on_timeout: true
- if:
- condition: template
value_template: >
{{
is_state(motion_sensor, 'off')
and
expand(light_target.entity_id) | selectattr('state', 'eq', 'on') | list | count > 0
}}
then:
- service: light.turn_off
target: !input light_target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment