Skip to content

Instantly share code, notes, and snippets.

@Belphemur
Last active October 28, 2025 14:24
Show Gist options
  • Save Belphemur/7b2db329f986214743f776507cc801fa to your computer and use it in GitHub Desktop.
Save Belphemur/7b2db329f986214743f776507cc801fa to your computer and use it in GitHub Desktop.
Circadian Light Home Assistant
blueprint:
name: "Circadian Motion Lighting"
description: >
**Version: 1.1**
Motion/Occupancy/Presence-activated lighting with minute-by-minute circadian adjustments.
Uses imperceptible gradual changes based on sun elevation for smooth transitions.
**Features:**
- Runs every minute for smooth, barely perceptible transitions
- Color temperature transitions from cool (morning) to warm (evening)
- Brightness dimming throughout the day
- Lux sensor condition with hysteresis to prevent feedback loops
- Motion/occupancy sensor integration with 'for' duration (no delays)
- Debug mode with persistent notifications showing all variables
Required = *
domain: automation
author: "Home Assistant User"
homeassistant:
min_version: "2025.10.0"
input:
# Motion Sensor Settings
motion_settings:
name: "Motion Sensor Settings *"
icon: mdi:motion-sensor
collapsed: true
input:
motion_sensor:
name: "Motion/Occupancy/Presence Sensor *"
description: The sensor that triggers the lights (motion, occupancy, or presence detection)
selector:
entity:
filter:
domain: binary_sensor
device_class:
- motion
- occupancy
- presence
no_motion_delay:
name: "No Motion Duration"
description: How long motion must be off before turning off lights
default: "00:05:00"
selector:
duration:
# Light Settings
light_settings:
name: "Light Settings *"
icon: mdi:lightbulb-outline
collapsed: true
input:
light_entities:
name: "Light Entities *"
description: The lights to control
selector:
target:
entity:
domain: light
# Lux Sensor Settings
lux_settings:
name: "Lux Sensor Settings *"
icon: mdi:brightness-6
collapsed: true
input:
lux_sensor:
name: "Illuminance Sensor *"
description: Lux sensor to determine if lights are needed (same room as lights)
selector:
entity:
filter:
domain: sensor
device_class: illuminance
lux_threshold:
name: "Lux Threshold"
description: Maximum lux level to turn on lights
default: 50
selector:
number:
min: 1
max: 500
unit_of_measurement: lux
lux_hysteresis:
name: "Lux Hysteresis"
description: Lux buffer to prevent rapid on/off cycling (added to threshold for turn-off)
default: 20
selector:
number:
min: 5
max: 100
unit_of_measurement: lux
# Circadian Settings
circadian_settings:
name: "Circadian Settings"
icon: mdi:weather-sunny
collapsed: true
input:
start_brightness:
name: "Starting Brightness"
description: Maximum brightness percentage (morning/midday)
default: 100
selector:
number:
min: 1
max: 100
unit_of_measurement: "%"
end_brightness:
name: "Ending Brightness"
description: Minimum brightness percentage (evening/night)
default: 30
selector:
number:
min: 1
max: 100
unit_of_measurement: "%"
start_color_temp:
name: "Starting Color Temperature"
description: Cool color temperature for morning (in Kelvin)
default: 5000
selector:
number:
min: 2000
max: 6500
unit_of_measurement: K
end_color_temp:
name: "Ending Color Temperature"
description: Warm color temperature for evening (in Kelvin)
default: 2700
selector:
number:
min: 2000
max: 6500
unit_of_measurement: K
# Debug Settings
debug_settings:
name: "Debug Settings"
icon: mdi:bug-outline
collapsed: true
input:
debug_mode:
name: "Debug Mode"
description: Enable debug notifications showing all calculated variables
default: false
selector:
boolean:
# Automation Configuration
mode: restart
max_exceeded: silent
variables:
# Assign all !input values to variables first
motion_sensor: !input motion_sensor
light_entities: !input light_entities
lux_sensor: !input lux_sensor
lux_threshold: !input lux_threshold
lux_hysteresis: !input lux_hysteresis
no_motion_delay: !input no_motion_delay
start_brightness: !input start_brightness
end_brightness: !input end_brightness
start_color_temp: !input start_color_temp
end_color_temp: !input end_color_temp
debug_mode: !input debug_mode
# Calculate sun elevation-based values
sun_elevation: "{{ state_attr('sun.sun', 'elevation') | float(0) }}"
elevation_normalized: "{{ ((sun_elevation + 10) / 100) | float(0) }}"
elevation_clamped: "{{ [0, [elevation_normalized, 1] | min] | max }}"
# Calculate dynamic values using assigned variables
color_temp_range: "{{ (start_color_temp | int) - (end_color_temp | int) }}"
current_color_temp: "{{ (end_color_temp | int) + (color_temp_range * elevation_clamped) | int }}"
brightness_range: "{{ (start_brightness | int) - (end_brightness | int) }}"
current_brightness: "{{ (end_brightness | int) + (brightness_range * elevation_clamped) | int }}"
# Lux thresholds
lux_on_threshold: "{{ lux_threshold | int }}"
lux_off_threshold: "{{ (lux_threshold | int) + (lux_hysteresis | int) }}"
current_lux: "{{ states(lux_sensor) | float(0) }}"
# Motion sensor state
motion_state: "{{ states(motion_sensor) }}"
# Check if any lights are currently on
lights_on: "{{ expand(light_entities.entity_id) | selectattr('state', 'eq', 'on') | list | count > 0 }}"
lights_on_count: "{{ expand(light_entities.entity_id) | selectattr('state', 'eq', 'on') | list | count }}"
# Current time for debugging
current_time: "{{ now().strftime('%H:%M:%S') }}"
current_date: "{{ now().strftime('%Y-%m-%d') }}"
trigger:
# Motion/Occupancy/Presence detected
- platform: state
entity_id: !input motion_sensor
from: "off"
to: "on"
id: "motion_on"
# Motion/Occupancy/Presence stopped - FIXED: Using 'for' instead of delay
- platform: state
entity_id: !input motion_sensor
from: "on"
to: "off"
for: !input no_motion_delay
id: "motion_off"
# Time-based trigger - runs every minute for gradual adjustments
- platform: time_pattern
minutes: "/1"
id: "minute_update"
condition:
- condition: template
value_template: "{{ true }}"
action:
# Debug notification - show all variables if debug mode is enabled
- if:
- condition: template
value_template: "{{ debug_mode }}"
then:
- service: persistent_notification.create
data:
title: "πŸ”§ Circadian Lighting Debug"
message: |
**Trigger:** {{ trigger.id }}
**Time:** {{ current_date }} {{ current_time }}
**β˜€οΈ Sun & Elevation:**
β€’ Sun Elevation: {{ sun_elevation }}Β°
β€’ Elevation Normalized: {{ elevation_normalized | round(3) }}
β€’ Elevation Clamped: {{ elevation_clamped | round(3) }}
**πŸ’‘ Light Calculations:**
β€’ Current Color Temp: {{ current_color_temp }}K
β€’ Current Brightness: {{ current_brightness }}%
β€’ Color Temp Range: {{ color_temp_range }}K
β€’ Brightness Range: {{ brightness_range }}%
**🌟 Lux & Sensors:**
β€’ Current Lux: {{ current_lux }} lux
β€’ Lux ON Threshold: {{ lux_on_threshold }} lux
β€’ Lux OFF Threshold: {{ lux_off_threshold }} lux
β€’ Motion Sensor: {{ motion_state }}
**🏠 Light Status:**
β€’ Lights On: {{ lights_on }}
β€’ Lights On Count: {{ lights_on_count }}
**βš™οΈ Configuration:**
β€’ Start Color: {{ start_color_temp }}K β†’ End Color: {{ end_color_temp }}K
β€’ Start Brightness: {{ start_brightness }}% β†’ End Brightness: {{ end_brightness }}%
β€’ Lux Threshold: {{ lux_threshold }} lux (Β±{{ lux_hysteresis }} hysteresis)
β€’ No Motion Duration: {{ no_motion_delay }}
notification_id: "circadian_debug"
- choose:
# Motion sensor activated - turn on lights if dark enough
- conditions:
- condition: trigger
id: "motion_on"
- condition: template
value_template: "{{ states(lux_sensor) | float(0) < lux_on_threshold }}"
sequence:
- service: light.turn_on
target: !input light_entities
data:
brightness_pct: "{{ current_brightness }}"
color_temp_kelvin: "{{ current_color_temp }}"
transition: 2
# Motion sensor deactivated - FIXED: No delay needed, trigger handles timing
- conditions:
- condition: trigger
id: "motion_off"
- condition: template
value_template: "{{ states(lux_sensor) | float(0) > lux_off_threshold }}"
sequence:
- service: light.turn_off
target: !input light_entities
data:
transition: 5
# Minute-by-minute gradual adjustment - only if lights are on
- conditions:
- condition: trigger
id: "minute_update"
- condition: template
value_template: "{{ lights_on }}"
sequence:
- service: light.turn_on
target: !input light_entities
data:
brightness_pct: "{{ current_brightness }}"
color_temp_kelvin: "{{ current_color_temp }}"
transition: 60
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment