Periodic lights
Github Gist: Periodic lights · GitHub
Github Gist for RGB lights Periodic Lights XY · GitHub
Introduction
Have you ever wished there was an easy way to have your lights adjust themselves based on the time of day? Well, this blueprint does just that! This blueprint progressively changes the brightness and color temperature of lights throughout the day (this runs 24 hours). This method indexes the light properties to midnight and fits them to a sin function (hence periodic). Midnight is the minimum brightness and color temperature and noon is the maximum.
You can offset midnight by up to 2 hours in either direction if you prefer a brighter or dimmer morning or evening. There is also a disable entity so you can turn the blueprint off for whatever reason (i.e. party mode). And probably the most sought after feature, there is a change threshold, so if you manually adjust a light the automation will skip it!
When a light is initially turned on the threshold is ignored and the light is immediately adjusted, the same is true for the disable entity. When the disable entity turns off, the lights that are currently on are immediately adjusted.
Requirements
You need a light, light group, or a list of lights separated by commas. You also need a ‘disable entity’. The disable entity can be anything the turns ‘on’ and ‘off’. When this entity is ‘on’ the blueprint is disabled and halts updating.
Limitations and solicitations for improvement
As far as I can gather, the blueprint entity chooser is limited somewhat. I cannot easily have a list of lights chosen without also presenting areas and devices. Because this code loops through the light entities, and as far as I know you cannot get a list of entities from an area, you need to provide each light manually in a comma separated list. If anyone knows a method to either allow for the choosing of multiple lights with the entity picker without presenting areas and devices, or knows how to get a list of entities in an area, please help me further improve this.
Also, as this is currently written, this will only adjust the color temperature for lights that can be changed with the Kelvin property. RGB lights in particular (in my experience) won’t adjust this way. Maybe in the future I can calculate color a different way.
If you want something more fully featured, you can try my AppDaemon app in HACS or: GitHub - haberda/update_lights: This AppDaemon app progressively changes the brightness and color temperature of lights over the course of the day. This app also uses change thresholds to ignore lights that have been manually adjusted.
Blueprint code
blueprint:
name: Periodic lights
description: "Dim and adjust color temperature of lights progressively throughout the evening (RGB bulbs probably won't change temperature). This is indexed to the midpoint between sunset and sunrise and fit to a sin function, so the midpoint will be minimum brightness and midpoint +12hr will be maximum brightness. The midpoint can be offset by a fixed amount if lights are too dim or bright at the desired time."
domain: automation
source_url: https://gist.github.com/haberda/f17694969a6de15d75267667b7c955ac
input:
light:
name: Light(s)
description: The light(s) to control
selector:
entity:
domain: light
min_brightness:
name: Minimum Brightness
description: Minimum brightness of the light(s)
default: 1
selector:
number:
min: 0.0
max: 100.0
mode: slider
step: 1.0
unit_of_measurement: '%'
max_brightness:
name: Maximum Brightness
description: Maximum brightness of the light(s)
default: 100
selector:
number:
min: 0.0
max: 100.0
mode: slider
step: 1.0
unit_of_measurement: '%'
min_temperature:
name: Minimum Temperature
description: Minimum temperature of the light(s) (Kelvin)
default: 2200
selector:
number:
min: 1800
max: 6000
mode: slider
step: 100.0
unit_of_measurement: 'K'
max_temperature:
name: Maximum Temperature
description: Maximum temperature of the light(s) (Kelvin)
default: 5000
selector:
number:
min: 1800
max: 6000
mode: slider
step: 100.0
unit_of_measurement: 'K'
threshold_brightness:
name: Brightness change threshold
description: Threshold value, above which the lights will not be adjusted (+ or -). This is the residual value between the current brightness level and the level it would adjust to.
default: 10
selector:
number:
min: 0.0
max: 100.0
mode: slider
step: 1.0
unit_of_measurement: '%'
transition:
name: Transition
description: Transition time (s)
default: 0
selector:
number:
min: 0.0
max: 30.0
mode: slider
step: 1.0
unit_of_measurement: 's'
midnight_offset:
name: Midnight offset
description: Offset from midnight. Positive for brighter evening and dimmer morning. Negative for dimmer evening and brighter morning.
default: 0
selector:
number:
min: -120.0
max: 120.0
step: 1.0
unit_of_measurement: min
mode: slider
light_on_adjust:
name: Adjust lights when they are turned on
description: 'If true adjusts a light immediately when it is turned on.'
default: true
selector:
boolean:
entity_off_adjust:
name: Adjust lights when disable entity is turned off
description: 'If true adjusts a light immediately when the disable entity is turned off.'
default: true
selector:
boolean:
disable_entity:
name: Disable entity
description: Binary sensor or input boolean that when on disables the updating of lights.
selector:
entity:
mode: parallel
max_exceeded: silent
variables:
light_list: !input 'light'
threshold_brightness: !input 'threshold_brightness'
min_brightness: !input 'min_brightness'
max_brightness: !input 'max_brightness'
min_temperature: !input 'min_temperature'
max_temperature: !input 'max_temperature'
midnight_offset: !input 'midnight_offset'
light_on_adjust: !input light_on_adjust
entity_off_adjust: !input entity_off_adjust
pct: >
{% if (states('sun.sun') == 'below_horizon') %}
{% set sunset = as_timestamp(states.sun.sun.attributes.next_setting)|float - 86400 %}
{% set sunrise = as_timestamp(states.sun.sun.attributes.next_rising)|float %}
{% else %}
{% set sunset = as_timestamp(states.sun.sun.attributes.next_setting)|float %}
{% set sunrise = as_timestamp(states.sun.sun.attributes.next_rising)|float %}
{% endif %}
{% set midpoint = (sunset |float + sunrise |float) / 2 + (midnight_offset|float * 60) | float %}
{{ sin(((as_timestamp(now())|float - midpoint)/86400)*pi) |abs }}
brightness_percent: '{{ (min_brightness|int+(max_brightness|int-min_brightness|int) * pct) | int }}'
kelvin_temperature: '{{ (min_temperature|int+(max_temperature|int-min_temperature|int) * pct) | int }}'
compliant_lights: "{% for state in states.light if state.state=='on' and state.entity_id in light_list.split(',') and (state_attr(state.entity_id, 'brightness') | int - (brightness_percent|int*2.55)) | abs < (threshold_brightness|int*2.55) %}{% if loop.last %}{{ state.entity_id }}{% else %}{{ state.entity_id }},{% endif %}{% endfor %}"
on_lights: "{% for state in states.light if state.state=='on' and state.entity_id in light_list.split(',') %}{% if loop.last %}{{ state.entity_id }}{% else %}{{ state.entity_id }},{% endif %}{% endfor %}"
trigger:
- platform: time_pattern
minutes: '/3'
id: 'time_change'
- platform: state
entity_id: !input 'light'
to: 'on'
id: 'light_on'
- platform: state
entity_id: !input 'disable_entity'
to: 'off'
id: 'disable_off'
condition:
- condition: state
entity_id: !input disable_entity
state: 'off'
- condition: or
conditions:
- condition: template
value_template: "{{compliant_lights.split(',')[0] in light_list.split(',')}}"
- condition: trigger
id: 'disable_off'
- condition: trigger
id: 'light_on'
action:
- choose:
- conditions:
- condition: trigger
id: 'disable_off'
- condition: template
value_template: '{{ entity_off_adjust }}'
- condition: template
value_template: "{{ on_lights.split(',')[0] in light_list.split(',') }}"
sequence:
- service: light.turn_on
data_template:
entity_id: '{{ on_lights }}'
brightness_pct: '{{ brightness_percent|int }}'
- delay:
hours: 0
minutes: 0
seconds: 0
milliseconds: 500
- service: light.turn_on
data_template:
entity_id: '{{ on_lights }}'
kelvin: '{{ kelvin_temperature|int }}'
- conditions:
- condition: trigger
id: 'light_on'
- condition: template
value_template: '{{ light_on_adjust }}'
sequence:
- service: light.turn_on
data_template:
entity_id: '{{trigger.entity_id}}'
brightness_pct: '{{ brightness_percent|int }}'
- delay:
hours: 0
minutes: 0
seconds: 0
milliseconds: 500
- service: light.turn_on
data_template:
entity_id: '{{trigger.entity_id}}'
kelvin: '{{ kelvin_temperature|int }}'
default:
- condition: template
value_template: "{{compliant_lights.split(',')[0] in light_list.split(',')}}"
- service: light.turn_on
data_template:
entity_id: '{{ compliant_lights }}'
brightness_pct: '{{ brightness_percent|int }}'
kelvin: '{{ kelvin_temperature|int }}'
transition: !input transition