Skip to content

Instantly share code, notes, and snippets.

@Belphemur
Last active October 31, 2025 20:35
Show Gist options
  • Select an option

  • Save Belphemur/7b2db329f986214743f776507cc801fa to your computer and use it in GitHub Desktop.

Select an option

Save Belphemur/7b2db329f986214743f776507cc801fa to your computer and use it in GitHub Desktop.
Circadian Light Home Assistant
blueprint:
name: "Circadian Motion Lighting - Smart Motion Logic"
description: >
**Version: 2.5.6 - Smart Motion Logic**
Motion/Occupancy/Presence-activated lighting with **smart conditional logic** and complete light therapy.
**NEW in 2.5.6: Smart Motion Detection**
- **Lights already on + motion detected = do nothing** (prevents flickering)
- **Lights off + motion detected = turn on with circadian settings**
- **Optimized performance** - no unnecessary light commands
- **Default transition multiplier: 0.75** (smoother, more natural transitions)
- **Fine-tunable range: 0.1 to 0.95** (step: 0.01) for precise control
- **Text input for time pattern** (e.g., "/2" for every 2 minutes)
- **No template limitations** - direct time_pattern support
**Color Temperature Scaling:**
- **0.5 = Slower** (stays cooler longer for extended alertness)
- **1.0 = Normal** (original therapeutic curve)
- **2.0 = Faster** (warms up sooner for earlier wind-down)
- **Real-time adjustable** via helper slider
**Protected Schedule Logic:**
- **Motion ON**: Always turns lights on (regardless of schedule) - **ONLY if lights are off**
- **Motion OFF + Schedule ON**: Lights stay on (protected by schedule)
- **Motion OFF + Schedule OFF**: Lights turn off
- **Schedule OFF + Lights ON**: Turn off lights immediately
**Complete Light Therapy Features:**
- **Morning peak for BOTH brightness and color temperature** (like professional 10,000 lux @ 6500K therapy)
- **Cool morning light (6500K)** for maximum circadian rhythm support and alertness
- **Customizable color temperature transition speed**
- **Gradual transition** from cool/bright morning to warm/dim evening
- **Queued mode** - runs execute in order without interruption
- Lux sensor ONLY affects brightness calculation (darker = brighter)
- Feedback loop prevention using input_number helper for persistence
- **WORKING: Text selector for configurable time patterns**
**⚠️ IMPORTANT: Before using this blueprint, you MUST create:**
1. **Input number helper** with VERY HIGH maximum value (999999) for lux smoothing
2. **Schedule helper** to define protected time periods
3. **Color temperature scaling helper** (0.1-3.0 range) for transition speed control
Required = *
domain: automation
author: "Home Assistant User"
homeassistant:
min_version: "2025.10.0"
input:
# Schedule Settings
schedule_settings:
name: "Protected Schedule Settings *"
icon: mdi:calendar-clock
collapsed: true
input:
schedule_entity:
name: "Protected Schedule Helper *"
description: "Schedule helper defining PROTECTED time periods when lights won't turn off due to no motion"
selector:
entity:
filter:
domain: schedule
# 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 considering turn-off (only applies when schedule is OFF)
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
# Update Timing Settings (Optional)
timing_settings:
name: "Update Timing Settings (Optional)"
icon: mdi:clock-outline
collapsed: true
input:
time_pattern_minutes:
name: "Light Update Pattern"
description: "Time pattern for light updates (e.g., '/2' = every 2 minutes, '/5' = every 5 minutes, '/10' = every 10 minutes)"
default: "/2"
selector:
text:
prefix: "minutes: "
transition_multiplier:
name: "Transition Time Multiplier"
description: "Multiplier for transition time (transition = update_frequency × this value × 60 seconds). 0.75 = smoother, natural transitions."
default: 0.75
selector:
number:
min: 0.1
max: 0.95
step: 0.01
# Lux Sensor Settings
lux_settings:
name: "Lux Brightness Settings *"
icon: mdi:brightness-6
collapsed: true
input:
lux_sensor:
name: "Illuminance Sensor *"
description: Lux sensor for brightness adjustment (can be in same room as lights)
selector:
entity:
filter:
domain: sensor
device_class: illuminance
lux_smoothing_helper:
name: "Lux Smoothing Helper *"
description: "⚠️ CRITICAL: Input number helper with MAXIMUM VALUE = 999999 (see setup instructions)"
selector:
entity:
filter:
domain: input_number
lux_min:
name: "Minimum Lux (Maximum Brightness)"
description: Lux level where lights are at maximum brightness
default: 100
selector:
number:
min: 0
max: 1000
unit_of_measurement: lux
lux_max:
name: "Maximum Lux (Minimum Brightness)"
description: Lux level where lights are at minimum brightness
default: 2000
selector:
number:
min: 500
max: 5000
unit_of_measurement: lux
lux_smoothing:
name: "Lux Smoothing Factor"
description: Smoothing to prevent feedback loops (0.1=heavy smoothing, 0.9=minimal smoothing)
default: 0.3
selector:
number:
min: 0.1
max: 0.9
step: 0.1
lux_hysteresis:
name: "Lux Hysteresis"
description: Lux buffer to prevent rapid brightness changes (added/subtracted from thresholds)
default: 50
selector:
number:
min: 10
max: 200
unit_of_measurement: lux
# Complete Light Therapy Circadian Settings
circadian_settings:
name: "Complete Light Therapy Settings"
icon: mdi:weather-sunny
collapsed: true
input:
morning_peak_time:
name: "Morning Light Therapy Peak Time"
description: Time when BOTH brightness and color temperature should be at maximum (optimal therapy time)
default: "08:00:00"
selector:
time:
start_brightness:
name: "Maximum Brightness (Morning Peak)"
description: Maximum brightness percentage during morning light therapy period
default: 100
selector:
number:
min: 1
max: 100
unit_of_measurement: "%"
end_brightness:
name: "Minimum Brightness (Evening)"
description: Minimum brightness percentage in evening
default: 20
selector:
number:
min: 1
max: 100
unit_of_measurement: "%"
start_color_temp:
name: "Maximum Color Temperature (Morning Peak)"
description: Coolest color temperature for morning light therapy (6500K recommended for maximum alertness)
default: 6500
selector:
number:
min: 4000
max: 6500
unit_of_measurement: K
end_color_temp:
name: "Minimum Color Temperature (Evening)"
description: Warmest color temperature for evening relaxation
default: 2700
selector:
number:
min: 2000
max: 4000
unit_of_measurement: K
color_temp_scaling:
name: "Color Temperature Transition Speed"
description: "Controls how fast color temperature changes (0.5=slower/cooler longer, 1.0=normal, 2.0=faster/warmer sooner)"
default: 1.0
selector:
number:
min: 0.1
max: 3.0
step: 0.1
# 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 - QUEUED MODE
mode: queued
max: 10
max_exceeded: silent
variables:
# Assign all !input values to variables
schedule_entity: !input schedule_entity
motion_sensor: !input motion_sensor
light_entities: !input light_entities
lux_sensor: !input lux_sensor
lux_smoothing_helper: !input lux_smoothing_helper
lux_min: !input lux_min
lux_max: !input lux_max
lux_smoothing: !input lux_smoothing
lux_hysteresis: !input lux_hysteresis
no_motion_delay: !input no_motion_delay
morning_peak_time: !input morning_peak_time
start_brightness: !input start_brightness
end_brightness: !input end_brightness
start_color_temp: !input start_color_temp
end_color_temp: !input end_color_temp
color_temp_scaling: !input color_temp_scaling
time_pattern_minutes: !input time_pattern_minutes
transition_multiplier: !input transition_multiplier
debug_mode: !input debug_mode
# Extract numeric value from time pattern for transition calculation
update_frequency_numeric: "{{ time_pattern_minutes.replace('/', '') | int }}"
transition_seconds: "{{ (update_frequency_numeric * transition_multiplier * 60) | int }}"
# Schedule and motion states
schedule_active: "{{ states(schedule_entity) == 'on' }}"
motion_state: "{{ states(motion_sensor) }}"
# Complete Light Therapy Calculation (BOTH brightness AND color temperature)
current_time_minutes: "{{ now().hour * 60 + now().minute }}"
morning_peak_minutes: "{{ (morning_peak_time.split(':')[0] | int) * 60 + (morning_peak_time.split(':')[1] | int) }}"
# Create a curve that peaks at morning_peak_time and decreases throughout the day
time_diff_from_peak: "{{ current_time_minutes - morning_peak_minutes }}"
time_normalized: "{{ (time_diff_from_peak / 720.0) | float }}" # 720 = 12 hours
# Light therapy curve for brightness: peaks at morning_peak_time, gradually decreases
light_therapy_multiplier: "{{ [0.2, 1.0 - (0.8 * ([0, time_normalized] | max))] | max }}"
# Scaled color temperature curve with independent scaling factor
scaled_time_multiplier: "{{ [0, (time_normalized * color_temp_scaling)] | max }}"
color_temp_multiplier: "{{ [0.2, 1.0 - (0.8 * ([0, scaled_time_multiplier] | max))] | max }}"
# Apply light therapy curve to brightness (unchanged)
brightness_range: "{{ (start_brightness | int) - (end_brightness | int) }}"
circadian_brightness: "{{ (end_brightness | int) + (brightness_range * light_therapy_multiplier) | int }}"
# Apply SCALED light therapy curve to color temperature
color_temp_range: "{{ (start_color_temp | int) - (end_color_temp | int) }}"
current_color_temp: "{{ (end_color_temp | int) + (color_temp_range * color_temp_multiplier) | int }}"
# Lux sensor smoothing using input_number helper
raw_lux: "{{ states(lux_sensor) | float(0) }}"
prev_smoothed_lux: "{{ states(lux_smoothing_helper) | float(raw_lux) }}"
smoothed_lux: "{{ ((1 - lux_smoothing) * prev_smoothed_lux + lux_smoothing * raw_lux) | round(1) }}"
# Apply hysteresis to smoothed lux values
lux_min_with_hysteresis: "{{ (lux_min | int) - (lux_hysteresis | int) }}"
lux_max_with_hysteresis: "{{ (lux_max | int) + (lux_hysteresis | int) }}"
# Clamp smoothed lux between min and max values (with hysteresis)
lux_clamped: "{{ [lux_min_with_hysteresis, [smoothed_lux, lux_max_with_hysteresis] | min] | max }}"
# Calculate lux multiplier (1.0 at lux_min, 0.3 at lux_max)
lux_range: "{{ lux_max_with_hysteresis - lux_min_with_hysteresis }}"
lux_normalized: "{{ (lux_clamped - lux_min_with_hysteresis) / lux_range if lux_range > 0 else 0 }}"
lux_multiplier: "{{ 1.0 - (lux_normalized * 0.7) }}"
# FINAL: Combined brightness (light therapy circadian * lux adjustment)
# NOTE: Color temperature is NOT affected by lux - only by time-based light therapy curve with scaling
current_brightness: "{{ (circadian_brightness * lux_multiplier) | int }}"
# 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 - ALWAYS triggers (regardless of schedule)
- platform: state
entity_id: !input motion_sensor
from: "off"
to: "on"
id: "motion_on"
# Motion/Occupancy/Presence stopped - Only matters if schedule is OFF
- platform: state
entity_id: !input motion_sensor
from: "on"
to: "off"
for: !input no_motion_delay
id: "motion_off"
# WORKING: Text-based time_pattern trigger - no templates needed!
- platform: time_pattern
minutes: !input time_pattern_minutes
id: "minute_update"
# Schedule becomes inactive - Turn off lights if they're on
- platform: state
entity_id: !input schedule_entity
from: "on"
to: "off"
id: "schedule_off"
condition:
- condition: template
value_template: "{{ true }}"
action:
# Store smoothed lux value in input_number helper
- service: input_number.set_value
target:
entity_id: !input lux_smoothing_helper
data:
value: "{{ smoothed_lux }}"
# Debug notification - show all variables if debug mode is enabled
- if:
- condition: template
value_template: "{{ debug_mode }}"
then:
- service: persistent_notification.create
data:
title: "🛡️ Protected Schedule Debug v2.5.6"
message: |
**Trigger:** {{ trigger.id }}
**Time:** {{ current_date }} {{ current_time }}
**🛡️ Protected Schedule Logic:**
• Schedule Active: {{ schedule_active }}
• Motion State: {{ motion_state }}
• Lights On: {{ lights_on }}
• **Turn Off Allowed**: {{ not schedule_active and motion_state == 'off' }}
**🧠 Smart Motion Logic:**
• **Motion ON + Lights Already ON**: Do nothing (prevents flickering)
• **Motion ON + Lights OFF**: Turn on with circadian settings
**⏱️ WORKING Timing Configuration:**
• **Time Pattern: {{ time_pattern_minutes }}**
• **Update Frequency: {{ update_frequency_numeric }} minutes**
• **Transition Multiplier: {{ transition_multiplier }}**
• **Transition Time: {{ transition_seconds }} seconds**
• **Calculation: {{ update_frequency_numeric }} × {{ transition_multiplier }} × 60**
**🌅 Light Therapy:**
• Light Therapy Multiplier: {{ light_therapy_multiplier | round(3) }}
• **Color Temp Scaling**: {{ color_temp_scaling }}
• **Scaled Color Temp Multiplier**: {{ color_temp_multiplier | round(3) }}
• **Circadian Brightness: {{ circadian_brightness }}%**
• **Current Color Temp: {{ current_color_temp }}K**
**🌟 Final Values:**
• Raw Lux: {{ raw_lux }} lux
• Smoothed Lux: {{ smoothed_lux }} lux
• Lux Multiplier: {{ lux_multiplier | round(3) }}
• **FINAL Brightness: {{ current_brightness }}%**
• **FINAL Color Temp: {{ current_color_temp }}K**
**⚙️ Configuration:**
• Peak: {{ start_brightness }}% @ {{ start_color_temp }}K at {{ morning_peak_time }}
• Evening: {{ end_brightness }}% @ {{ end_color_temp }}K
• **Color Scaling: {{ color_temp_scaling }}x**
notification_id: "protected_schedule_debug"
- choose:
# NEW: Smart motion sensor logic - ONLY turn on if lights are OFF
- conditions:
- condition: trigger
id: "motion_on"
- condition: template
value_template: "{{ not lights_on }}"
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 - ONLY turn off if schedule is OFF
- conditions:
- condition: trigger
id: "motion_off"
- condition: template
value_template: "{{ not schedule_active }}"
sequence:
- service: light.turn_off
target: !input light_entities
data:
transition: 5
# Schedule becomes inactive - Turn off lights if they're on (regardless of motion)
- conditions:
- condition: trigger
id: "schedule_off"
- condition: template
value_template: "{{ lights_on }}"
sequence:
- service: light.turn_off
target: !input light_entities
data:
transition: 5
# WORKING: Time pattern triggered 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: "{{ transition_seconds }}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment