Last active
October 31, 2025 20:35
-
-
Save Belphemur/7b2db329f986214743f776507cc801fa to your computer and use it in GitHub Desktop.
Circadian Light Home Assistant
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: "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