Skip to content

Instantly share code, notes, and snippets.

@jroehl
Last active August 23, 2025 18:54
Show Gist options
  • Select an option

  • Save jroehl/e86c6be26fa5d7c81f7db228fb93e960 to your computer and use it in GitHub Desktop.

Select an option

Save jroehl/e86c6be26fa5d7c81f7db228fb93e960 to your computer and use it in GitHub Desktop.
blueprint:
name: Motion-activated Light (dual time profile + dual wait + lux + sensitivity)
description: >
Turn on lights on motion with two brightness profiles and two wait times
based on a time window (supports overnight). Optional ambient-lux guard,
sensor sensitivity control, transition, and cooldown.
domain: automation
input:
motion_entity:
name: Motion Sensor
selector:
entity:
filter:
domain: binary_sensor
light_target:
name: Light(s)
selector:
target:
entity:
domain: light
# --- Time profiles (single window; choose overnight if crossing midnight) ---
time_window_start:
name: Time window start
selector: { time: {} }
time_window_end:
name: Time window end
selector: { time: {} }
overnight_window:
name: Window crosses midnight
description: If enabled, inside = after start OR before end (e.g., 22:00–06:00).
default: false
selector: { boolean: {} }
# Brightness profiles
brightness_inside_pct:
name: Brightness inside window (%)
default: 60
selector:
number: { min: 1, max: 100, unit_of_measurement: "%", mode: slider }
brightness_outside_pct:
name: Brightness outside window (%)
default: 30
selector:
number: { min: 1, max: 100, unit_of_measurement: "%", mode: slider }
# Optional color temperature per profile (0 = skip)
color_temp_inside_kelvin:
name: (Optional) Color temperature inside window (K)
description: Set 0 to skip sending color temperature.
default: 0
selector:
number: { min: 0, max: 6500, unit_of_measurement: K, mode: slider }
color_temp_outside_kelvin:
name: (Optional) Color temperature outside window (K)
description: Set 0 to skip sending color temperature.
default: 0
selector:
number: { min: 0, max: 6500, unit_of_measurement: K, mode: slider }
transition_sec:
name: Transition (seconds)
default: 0.5
selector:
number: { min: 0, max: 10, step: 0.1, unit_of_measurement: s, mode: slider }
# --- Dual wait times ---
no_motion_wait_inside:
name: Wait time inside window (seconds)
description: Time to keep lights on after motion goes off during the inside window.
default: 120
selector:
number: { min: 0, max: 3600, unit_of_measurement: seconds }
no_motion_wait_outside:
name: Wait time outside window (seconds)
description: Time to keep lights on after motion goes off outside the window.
default: 60
selector:
number: { min: 0, max: 3600, unit_of_measurement: seconds }
# --- Optional: ambient light guard ---
illuminance_entity:
name: (Optional) Illuminance sensor
default: ''
selector:
entity:
filter:
domain: sensor
illuminance_threshold_lx:
name: Lux threshold (don’t turn on if above)
default: 40
selector:
number: { min: 1, max: 2000, unit_of_measurement: lx, mode: slider }
# --- Optional: sensor sensitivity control (use whichever your device exposes) ---
set_sensitivity_on_start:
name: Set sensitivity on Home Assistant start
default: false
selector: { boolean: {} }
sensitivity_number:
name: (Optional) Sensitivity as number entity
description: Use if your sensor exposes sensitivity as number.* (e.g., 1–3).
default: ''
selector:
entity:
filter:
domain: number
sensitivity_number_value:
name: Target number value
default: 0
selector:
number: { min: 0, max: 100, step: 1 }
sensitivity_select:
name: (Optional) Sensitivity as select entity
description: Use if your sensor exposes sensitivity as select.* (e.g., low/med/high).
default: ''
selector:
entity:
filter:
domain: select
sensitivity_select_option:
name: Target select option (exact label)
default: ""
# --- Optional: cooldown after turning off to avoid immediate retrigger ---
cooldown_sec:
name: Cooldown after lights off (ignore motion)
default: 0
selector:
number: { min: 0, max: 600, unit_of_measurement: s, mode: slider }
mode: restart
max_exceeded: silent
variables:
overnight: !input overnight_window
start_time: !input time_window_start
end_time: !input time_window_end
inside_pct: !input brightness_inside_pct
outside_pct: !input brightness_outside_pct
ct_inside: !input color_temp_inside_kelvin
ct_outside: !input color_temp_outside_kelvin
wait_inside: !input no_motion_wait_inside
wait_outside: !input no_motion_wait_outside
transition: !input transition_sec
lux_entity: !input illuminance_entity
lux_threshold: !input illuminance_threshold_lx
cooldown: !input cooldown_sec
sens_num: !input sensitivity_number
sens_num_value: !input sensitivity_number_value
sens_sel: !input sensitivity_select
sens_sel_option: !input sensitivity_select_option
trigger:
- platform: state
entity_id: !input motion_entity
from: "off"
to: "on"
id: motion_on
- platform: homeassistant
event: start
id: ha_start
condition: []
action:
- choose:
# --- HA start: optionally set sensitivity once ---
- conditions:
- condition: trigger
id: ha_start
- condition: template
value_template: >
{{ (sens_num != '') or (sens_sel != '' and sens_sel_option != '') }}
- condition: template
value_template: "{{ set_sensitivity_on_start }}"
sequence:
- choose:
- conditions:
- condition: template
value_template: "{{ sens_num != '' }}"
sequence:
- service: number.set_value
target: { entity_id: "{{ sens_num }}" }
data: { value: "{{ sens_num_value }}" }
- conditions:
- condition: template
value_template: "{{ sens_sel != '' and sens_sel_option != '' }}"
sequence:
- service: select.select_option
target: { entity_id: "{{ sens_sel }}" }
data: { option: "{{ sens_sel_option }}" }
# --- Motion ON: evaluate sensitivity, lux, time profile; turn on; then handle off/waits ---
- conditions:
- condition: trigger
id: motion_on
sequence:
# Optionally set sensitivity before acting
- choose:
- conditions:
- condition: template
value_template: "{{ sens_num != '' }}"
sequence:
- service: number.set_value
target: { entity_id: "{{ sens_num }}" }
data: { value: "{{ sens_num_value }}" }
- conditions:
- condition: template
value_template: "{{ sens_sel != '' and sens_sel_option != '' }}"
sequence:
- service: select.select_option
target: { entity_id: "{{ sens_sel }}" }
data: { option: "{{ sens_sel_option }}" }
# Ambient light guard (skip turning on if already bright)
- if:
- condition: template
value_template: >
{% if lux_entity == '' %}
false
{% else %}
{{ (states(lux_entity) | float(0)) > (lux_threshold | float(0)) }}
{% endif %}
then:
- stop: "Ambient light above threshold — skip turning on."
# Compute time window using today_at() (tz-aware, safe)
- variables:
start_dt: "{{ today_at(start_time) }}"
end_dt: "{{ today_at(end_time) }}"
now_dt: "{{ now() }}"
inside_window: >
{% if overnight %}
{{ now_dt >= start_dt or now_dt <= end_dt }}
{% else %}
{{ start_dt <= now_dt <= end_dt }}
{% endif %}
target_brightness: "{{ inside_pct if inside_window else outside_pct }}"
target_wait_sec: "{{ (wait_inside if inside_window else wait_outside) | int(0) }}"
target_ct_int: >
{% set ct = (ct_inside if inside_window else ct_outside) | int(0) %}
{{ ct if ct > 0 else 0 }}
# Turn on with chosen profile
- choose:
# with color temperature (only if > 0)
- conditions:
- condition: template
value_template: "{{ target_ct_int > 0 }}"
sequence:
- service: light.turn_on
target: !input light_target
data:
brightness_pct: "{{ target_brightness }}"
transition: "{{ transition }}"
color_temp_kelvin: "{{ target_ct_int }}"
default:
# without color temperature
- service: light.turn_on
target: !input light_target
data:
brightness_pct: "{{ target_brightness }}"
transition: "{{ transition }}"
# Wait until motion goes OFF, then wait per profile, then turn off
- wait_for_trigger:
- platform: state
entity_id: !input motion_entity
from: "on"
to: "off"
- delay: "{{ target_wait_sec | int }}"
- service: light.turn_off
target: !input light_target
data:
transition: "{{ transition }}"
# Optional cooldown
- if:
- condition: template
value_template: "{{ (cooldown | int(0)) > 0 }}"
then:
- delay:
seconds: "{{ cooldown | int(0) }}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment