Skip to content

Instantly share code, notes, and snippets.

@snowyu
Last active April 28, 2022 12:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save snowyu/1bc65cb8d635d880473bc31b5e102c37 to your computer and use it in GitHub Desktop.
Save snowyu/1bc65cb8d635d880473bc31b5e102c37 to your computer and use it in GitHub Desktop.
HA Blueprints
blueprint:
# INTRODUCTION
name: Advanced Circadian Lighting Brightness
description: >-
This automation adjusts light brightness, temperature, and color hue,
based on current time and sun position.
Available features:
- Works with lights supporting different types of color modes.
- Adjusts brightness, temperature and hue based on the circadian cycle.
- The circadian cycle can be defined based on sunrise and sunset times.
- Sunrise and sunset times can also be defined manually.
- Light attributes can be adjusted following various types of functions.
- The minimum and maximum brightness and temperature can be configured.
- This option can be deactivated.
- Gets automatically activated when a light is turned on.
- Runs when the turn on service does not define light brightness or color.
- Does not run when the turn on service also defines light attributes, e.g. in scenes.
- Stops running when light attributes are manually changed.
- The light will still turn off automatically.
domain: automation
# INPUT
input:
# Input - Lights
lights_target:
name: Lights
description: >-
List of lights to adjust.
brightness, temperature and color modes are supported.
selector:
target:
entity:
domain: light
# Input - Circadian
circadian_type:
name: Circadian cycle
description: >-
Determines how the circadian cycle will be defined.
Select sun to use actual sunrise and sunset times.
Select time to override with manual sunrise and sunset times.
selector:
select:
options:
- Sun
- Time
default: Time
circadian_sunrise:
name: Circadian manual sunrise time
description: >-
Defines the start of daytime when the circadian rhythm is time-based.
This value is ignored when using actual sunrise and sunset times.
selector:
time:
default: "07:30:00"
circadian_sunset:
name: Circadian manual sunset time
description: >-
Defines the end of daytime when the circadian rhythm is time-based.
This value is ignored when using sunrise and sunset times.
selector:
time:
default: "21:30:00"
circadian_function:
name: Circadian function
description: >-
Determines the function used for circadian cycle adjustments.
Use day-only or night-only to adjust lights in daytime or nightime.
Day & night half-sine functions are similar to the full cycle cosine.
Select day & night cosine functions for smoother transitions.
Select none to skip circadian cycle adjustments.
default: Day-only (half-sine)
selector:
select:
options:
- Day-only (half-sine)
- Day-only (cosine)
- Night-only (half-sine)
- Night-only (cosine)
- Day & night (cosine)
- None
circadian_brightness_midday:
name: Circadian brightness at midday
description: >-
Sets the maximum (or minimum) value that light brightness
will reach at midday.
This value is also used when circadian lighting is disabled.
default: 100
selector:
number:
min: 0
max: 100
unit_of_measurement: "%"
mode: slider
step: 5
circadian_brightness_midnight:
name: Circadian brightness at midnight
description: >-
Sets the minimum (or maximum) value that light brightness
will reach at midnight.
This value is ignored when circadian lighting is disabled.
default: 10
selector:
number:
min: 0
max: 100
unit_of_measurement: "%"
mode: slider
step: 5
circadian_temperature_midday:
name: Circadian temperature at midday
description: >-
Sets the maximum (or minimum) value that color temperature
will reach at midday.
This value is also used when circadian lighting is disabled.
default: 4100
selector:
number:
min: 2700
max: 6500
unit_of_measurement: "Kelvin"
mode: slider
step: 100
circadian_temperature_midnight:
name: Circadian temperature at midnight
description: >-
Sets the minimum (or maximum) value that color temperature
will reach at midnight.
This value is ignored when circadian lighting is disabled.
default: 2700
selector:
number:
min: 2700
max: 6500
unit_of_measurement: "Kelvin"
mode: slider
step: 100
circadian_hue_default:
name: Circadian default hue
description: >-
Sets the hue value to be used for when circadian lighting is disabled.
default: 180
selector:
number:
min: 0
max: 360
unit_of_measurement: "°"
mode: slider
step: 5
circadian_saturation_default:
name: Circadian default saturation
description: >-
Sets the color saturation value to be used for circadian adjustments.
default: 100
selector:
number:
min: 0
max: 100
unit_of_measurement: "%"
mode: slider
step: 5
# Input Elevation
elevation_switch_on:
name: Dim lights on based on sun elevation
description: >-
Normally, the lights will dim on at sunset,
and they will be turned on during nightime.
default: true
selector:
boolean:
elevation_switch_off:
name: Dim lights off based on sun elevation
description: >-
Normally, the lights will dim off at sunrise,
and they will be turned off during daytime.
default: true
selector:
boolean:
elevation_inverse:
name: Inverse light dimming behaviour
description: >-
Dim the lights on at sunrise and off at sunset.
The lights will be turned on during daytime
and off during nightime.
default: false
selector:
boolean:
elevation_sunrise_start:
name: Sunrise start elevation
description: >-
Defines the beginning of sunrise in terms of sun elevation.
Normally, this is when lights start to dim off.
When dimming is inversed, this is when lights turn on.
default: -8
selector:
number:
min: -20
max: 10
unit_of_measurement: "°"
mode: slider
step: 1
elevation_sunrise_end:
name: Sunrise end elevation
description: >-
Defines the end of sunrise in terms of sun elevation.
Normally, this is when lights turn off.
When dimming is inversed, this is when lights have fully dimmed on.
default: 6
selector:
number:
min: -10
max: 20
unit_of_measurement: "°"
mode: slider
step: 1
elevation_sunset_start:
name: Sunset start elevation
description: >-
Defines the beginning of sunset in terms of sun elevation.
Normally, this is when lights turn on.
When dimming is inversed, this is when lights start to dim off.
default: 6
selector:
number:
min: -10
max: 20
unit_of_measurement: "°"
mode: slider
step: 1
elevation_sunset_end:
name: Sunset end elevation
description: >-
Defines the end of sunset in terms of sun elevation.
Normally, this is when light have fully dimmed on.
When dimming is inversed, this is when lights turn off.
default: -8
selector:
number:
min: -20
max: 10
unit_of_measurement: "°"
mode: slider
step: 1
# VARIABLES
variables:
# Variables Circadian
circadian_type: !input circadian_type
circadian_sunrise: !input circadian_sunrise
circadian_sunset: !input circadian_sunset
circadian_function: !input circadian_function
circadian_position: >-
{# Define next sunrise and sunset times based on sun or manual input #}
{%- set time_current = now()|as_timestamp -%}
{%- if circadian_type == 'Sun' and states('sun.sun') != 'unknown' -%}
{%- set time_sunrise = state_attr('sun.sun','next_rising')|as_timestamp -%}
{%- set time_sunset = state_attr('sun.sun','next_setting')|as_timestamp -%}
{%- else -%}
{%- set time_sunrise = today_at(circadian_sunrise)|as_timestamp -%}
{%- set time_sunset = today_at(circadian_sunset)|as_timestamp -%}
{# Fix input times so that they reflect the next sunrise and sunset #}
{%- if time_sunrise < time_current -%}
{% set time_sunrise = time_sunrise + 86400 -%}
{%- endif -%}
{%- if time_sunset < time_current -%}
{% set time_sunset = time_sunset + 86400 -%}
{%- endif -%}
{%- endif -%}
{# Calculate sun position, from -1 to 0 in nightime and 0 to 1 in daytime. #}
{%- if time_sunrise > time_sunset -%}
{%- set time_sunrise = [time_sunrise-86400,time_current]|min -%}
{%- set position = (time_current-time_sunrise) / (time_sunset-time_sunrise) -%}
{%- else -%}
{%- set time_sunset = [time_sunset-86400,time_current]|min -%}
{%- set position = (time_current-time_sunrise) / (time_sunrise-time_sunset) -%}
{%- endif -%}
{# Return calculated result #}
{{ position }}
circadian_coefficient: >-
{# Calculate coefficient based on selected circadian function #}
{%- set coefficient = 1.0 -%}
{%- if circadian_function == 'Day-only (half-sine)' -%}
{%- set coefficient = sin( pi*([circadian_position,0]|max) ) -%}
{%- elif circadian_function == 'Day-only (cosine)' -%}
{%- set coefficient = 0.5 - 0.5 * cos( 2*pi*([circadian_position,0]|max) ) -%}
{%- elif circadian_function == 'Night-only (half-sine)' -%}
{%- set coefficient = 1 - sin( pi*([circadian_position,0]|min) ) -%}
{%- elif circadian_function == 'Night-only (cosine)' -%}
{%- set coefficient = 0.5 + 0.5 * cos( 2*pi*([circadian_position,0]|min) ) -%}
{%- elif circadian_function == 'Day & night (cosine)' -%}
{%- set coefficient = 0.5 + 0.5 * sin( pi*circadian_position ) -%}
{%- else -%}
{%- set coefficient = -1.0 -%}
{%- endif -%}
{# Return calculated result #}
{{ coefficient }}
circadian_angle: >-
{# Calculate angle based on selected circadian function #}
{%- set angle = 0.5 -%}
{%- if circadian_function == 'Day-only (half-sine)'
or circadian_function == 'Day-only (cosine)' -%}
{%- set angle = [circadian_position,0]|max -%}
{%- elif circadian_function == 'Night-only (half-sine)'
or circadian_function == 'Night-only (cosine)' -%}
{%- if circadian_position < -0.5 -%}
{%- set angle = 1.5 + circadian_position -%}
{%- else -%}
{%- set angle = 0.5 + [circadian_position,0]|min -%}
{%- endif -%}
{%- elif circadian_function == 'Day & night (cosine)' -%}
{%- if circadian_position < -0.5 -%}
{%- set angle = 1.25 + 0.5 * circadian_position -%}
{%- else -%}
{%- set angle = 0.25 + 0.5 * circadian_position -%}
{%- endif -%}
{%- else -%}
{%- set angle = -1.0 -%}
{%- endif -%}
{# Return calculated result #}
{{ angle }}
circadian_brightness_midday: !input circadian_brightness_midday
circadian_brightness_midnight: !input circadian_brightness_midnight
circadian_brightness_value: >-
{# Light brightness value to adjust to #}
{%- if circadian_coefficient < 0 -%}
{{ [ ( 2.54 * circadian_brightness_midday|float + 0.5)|int , 1]|max }}
{%- else -%}
{{ [ ( 2.54 * ( circadian_brightness_midnight|float + circadian_coefficient * ( circadian_brightness_midday|float - circadian_brightness_midnight|float ) ) + 0.5)|int , 1]|max }}
{%- endif -%}
circadian_temperature_midday: !input circadian_temperature_midday
circadian_temperature_midnight: !input circadian_temperature_midnight
circadian_temperature_value: >-
{# Color temperature value to adjust to #}
{%- if circadian_coefficient < 0 -%}
{{ ( 1000000/circadian_temperature_midday + 0.5)|int }}
{%- else -%}
{{ ( 1000000/circadian_temperature_midnight|float + circadian_coefficient * ( 1000000/circadian_temperature_midday|float - 1000000/circadian_temperature_midnight|float ) + 0.5)|int }}
{%- endif -%}
circadian_hue_default_input: !input circadian_hue_default
circadian_hue_default: '{{ circadian_hue_default_input|float }}'
circadian_hue_value: >-
{# Color hue value to adjust to #}
{%- if circadian_angle < 0 -%}
{{ circadian_hue_default }}
{%- else -%}
{{ (360 * circadian_angle + 0.5)|int }}
{%- endif -%}
circadian_saturation_default_input: !input circadian_saturation_default
circadian_saturation_default: '{{ circadian_saturation_default_input|float }}'
# Variables Sunrise/Sunset
elevation_switch_on: !input elevation_switch_on
elevation_switch_off: !input elevation_switch_off
elevation_inverse: !input elevation_inverse
elevation_sunrise_start_input: !input elevation_sunrise_start
elevation_sunrise_start: "{{ elevation_sunrise_start_input | float }}"
elevation_sunrise_end_input: !input elevation_sunrise_end
elevation_sunrise_end: "{{ elevation_sunrise_end_input | float }}"
elevation_sunset_start_input: !input elevation_sunset_start
elevation_sunset_start: "{{ elevation_sunset_start_input | float }}"
elevation_sunset_end_input: !input elevation_sunset_end
elevation_sunset_end: "{{ elevation_sunset_end_input | float }}"
elevation_dim_on: >-
{# Boolean for dimming on #}
{{ elevation_switch_on
and ( ( not elevation_inverse
and not state_attr('sun.sun','rising')
and ( ( state_attr('sun.sun','elevation') < elevation_sunset_start
and state_attr('sun.sun','elevation') > elevation_sunset_end )
or ( trigger is defined
and trigger.platform == 'numeric_state'
and trigger.from_state.entity_id == 'sun.sun'
and trigger.from_state.attributes.elevation < elevation_sunset_start
and trigger.from_state.attributes.elevation > elevation_sunset_end ) ) )
or ( elevation_inverse
and state_attr('sun.sun','rising')
and ( ( state_attr('sun.sun','elevation') > elevation_sunrise_start
and state_attr('sun.sun','elevation') < elevation_sunrise_end )
or ( trigger is defined
and trigger.platform == 'numeric_state'
and trigger.from_state.entity_id == 'sun.sun'
and trigger.from_state.attributes.elevation > elevation_sunrise_start
and trigger.from_state.attributes.elevation < elevation_sunrise_end ) ) ) ) }}
elevation_dim_off: >-
{# Boolean for dimming off #}
{{ elevation_switch_off
and ( ( not elevation_inverse
and state_attr('sun.sun','rising')
and state_attr('sun.sun','elevation') > elevation_sunrise_start
and state_attr('sun.sun','elevation') < elevation_sunrise_end )
or ( elevation_inverse
and not state_attr('sun.sun','rising')
and state_attr('sun.sun','elevation') < elevation_sunset_start
and state_attr('sun.sun','elevation') > elevation_sunset_end ) ) }}
elevation_brightness: >-
{# Calculate coefficient to be multiplied with brightness #}
{%- if elevation_dim_on or elevation_dim_off -%}
{%- set elevation_current = state_attr('sun.sun','elevation') -%}
{%- if state_attr('sun.sun','rising') -%}
{%- set coefficient = 1.0 - (elevation_current-elevation_sunrise_start) / (elevation_sunrise_end-elevation_sunrise_start) -%}
{%- else -%}
{%- set coefficient = (elevation_current-elevation_sunset_start) / (elevation_sunset_end-elevation_sunset_start) -%}
{%- endif -%}
{%- if elevation_inverse -%}
{%- set coefficient = 1.0 - coefficient -%}
{%- endif -%}
{%- else -%}
{%- set coefficient = 1.0 -%}
{%- endif -%}
{# Return calculated result #}
{# Alternative: 0.5 - 0.5*cos(pi*coefficient) #}
{{ [ ( coefficient * circadian_brightness_value + 0.5 )|int , 1]|max }}
# Variables Trigger
turnon_trigger: >-
{# Boolean for light.turn_on event trigger #}
{{ trigger is defined
and trigger.platform == 'event'
and trigger.event.data.service_data is defined
and trigger.event.data.service_data.entity_id is defined }}
# Variables Lights
lights_target_input: !input lights_target
lights_target: >-
{# This is the full list of targetted lights #}
{# Ensure that the variable is a list #}
{%- if lights_target_input.entity_id is string -%}
{%- set lights_list = [lights_target_input] -%}
{%- else -%}
{%- set lights_list = lights_target_input -%}
{%- endif -%}
{{ expand(lights_list)
|selectattr('state', 'eq', 'on')
|map(attribute='entity_id')
|list
}}
lights_dim_all: >-
{# This is the list of lights that are being dimmed #}
{%- set lights_select = namespace(entities=[]) -%}
{%- if elevation_dim_on or elevation_dim_off -%}
{%- for i_entity in lights_target -%}
{# Check that the light is being dimmed in one direction #}
{# Also check that other circadian values are being followed #}
{%- if ( state_attr(i_entity,'brightness') != none
and ( elevation_dim_on
and state_attr(i_entity,'brightness') < elevation_brightness+15 )
or ( elevation_dim_off
and state_attr(i_entity,'brightness') > elevation_brightness-15 ) )
and ( ( state_attr(i_entity,'color_temp') == none
and state_attr(i_entity,'hs_color') == none )
or ( state_attr(i_entity,'hs_color') != none
and state_attr(i_entity,'hs_color')|first > circadian_hue_value-30
and state_attr(i_entity,'hs_color')|first < circadian_hue_value+30 )
or ( state_attr(i_entity,'color_temp') != none
and state_attr(i_entity,'color_temp') > circadian_temperature_value-20
and state_attr(i_entity,'color_temp') < circadian_temperature_value+20 ) ) -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{{ lights_select.entities }}
lights_on_all: >-
{# This is the list of lights that follow the circadian cycle #}
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_target -%}
{# Check that the light is following all circadian values #}
{# Also check that the light is not being dimmed #}
{%- if (state_attr(i_entity,'brightness') == none
or ( state_attr(i_entity,'brightness') != none
and state_attr(i_entity,'brightness') > circadian_brightness_value-15
and state_attr(i_entity,'brightness') < circadian_brightness_value+15 ) )
and (
( state_attr(i_entity,'color_temp') == none and state_attr(i_entity,'hs_color') == none )
or ( state_attr(i_entity,'hs_color') != none
and state_attr(i_entity,'hs_color')|first > circadian_hue_value-30
and state_attr(i_entity,'hs_color')|first < circadian_hue_value+30 )
or ( state_attr(i_entity,'color_temp') != none
and state_attr(i_entity,'color_temp') > circadian_temperature_value-20
and state_attr(i_entity,'color_temp') < circadian_temperature_value+20 ) )
and i_entity not in lights_dim_all -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_off_all: >-
{# This is the list of lights that are currently off #}
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_target -%}
{# Check that the light is off #}
{%- if is_state(i_entity,'off') -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_trigger_all: >-
{# This is the list of lights that have been triggered #}
{%- set lights_select = namespace(entities=[]) -%}
{%- if turnon_trigger -%}
{# Ensure that the triggered lights are a list #}
{%- if trigger.event.data.service_data.entity_id is string -%}
{%- set lights_list = [trigger.event.data.service_data.entity_id] -%}
{%- else -%}
{%- set lights_list = trigger.event.data.service_data.entity_id -%}
{%- endif -%}
{# Check for individual entities within a group light #}
{%- set group_list = namespace(entities=[]) -%}
{%- for i_entity in lights_list -%}
{%- if state_attr(i_entity,'entity_id') is not none -%}
{%- if state_attr(i_entity,'entity_id') is string -%}
{%- set group_list.entities = group_list.entities + [state_attr(i_entity,'entity_id')] -%}
{%- else -%}
{%- set group_list.entities = group_list.entities + state_attr(i_entity,'entity_id') -%}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- set lights_list = lights_list + group_list.entities -%}
{%- for i_entity in lights_list -%}
{# Check that the light is in the target list #}
{# Also check that its properties are not being set #}
{%- if i_entity in lights_target
and ( trigger.event.data.service_data|length == 1
or ( is_state(i_entity,'on')
and trigger.event.data.service_data|length <=2
and trigger.event.data.service_data.brightness is not defined
and trigger.event.data.service_data.brightness_pct is not defined ) ) -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{{ lights_select.entities }}
lights_dim_brightness: >-
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_dim_all -%}
{%- if state_attr(i_entity,'color_mode') == 'brightness' -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_dim_color: >-
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_dim_all -%}
{%- if state_attr(i_entity,'color_mode') in ['rgb','rgbw','rgbww','xy','hs'] -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_dim_temperature: >-
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_dim_all -%}
{%- if state_attr(i_entity,'color_mode') == 'color_temp' -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_on_brightness: >-
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_on_all -%}
{%- if state_attr(i_entity,'color_mode') == 'brightness' -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_on_color: >-
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_on_all -%}
{%- if state_attr(i_entity,'color_mode') in ['rgb','rgbw','rgbww','xy','hs'] -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
lights_on_temperature: >-
{%- set lights_select = namespace(entities=[]) -%}
{%- for i_entity in lights_on_all -%}
{%- if state_attr(i_entity,'color_mode') == 'color_temp' -%}
{%- set lights_select.entities = lights_select.entities + [i_entity] -%}
{%- endif -%}
{%- endfor -%}
{{ lights_select.entities }}
# AUTOMATION
mode: 'queued'
# TRIGGER
trigger:
- platform: time_pattern
minutes: "/1"
- platform: numeric_state
entity_id: sun.sun
attribute: elevation
above: !input elevation_sunrise_start
- platform: numeric_state
entity_id: sun.sun
attribute: elevation
above: !input elevation_sunrise_end
- platform: numeric_state
entity_id: sun.sun
attribute: elevation
below: !input elevation_sunset_start
- platform: numeric_state
entity_id: sun.sun
attribute: elevation
below: !input elevation_sunset_end
- platform: event
event_type: call_service
event_data:
domain: light
service: turn_on
# ACTION
action:
# Default (on lights to circadian, dim lights to elevation brightness)
- choose:
- conditions: "{{ lights_on_brightness | length > 0 }}"
sequence:
- service: light.turn_on
data:
entity_id: "{{ lights_on_brightness }}"
brightness: "{{ circadian_brightness_value }}"
- choose:
- conditions: "{{ lights_on_color | length > 0 }}"
sequence:
- service: light.turn_on
data:
entity_id: "{{ lights_on_color }}"
brightness: "{{ circadian_brightness_value }}"
hs_color:
- "{{ circadian_hue_value }}"
- "{{ circadian_saturation_default }}"
- choose:
- conditions: "{{ lights_on_temperature | length > 0 }}"
sequence:
- service: light.turn_on
data:
entity_id: "{{ lights_on_temperature }}"
brightness: "{{ circadian_brightness_value }}"
color_temp: "{{ circadian_temperature_value }}"
- choose:
- conditions: "{{ lights_dim_brightness | length > 0 }}"
sequence:
- service: light.turn_on
data:
entity_id: "{{ lights_dim_brightness }}"
brightness: "{{ elevation_brightness }}"
- choose:
- conditions: "{{ lights_dim_color | length > 0 }}"
sequence:
- service: light.turn_on
data:
entity_id: "{{ lights_dim_color }}"
brightness: "{{ elevation_brightness }}"
hs_color:
- "{{ circadian_hue_value }}"
- "{{ circadian_saturation_default }}"
- choose:
- conditions: "{{ lights_dim_temperature | length > 0 }}"
sequence:
- service: light.turn_on
data:
entity_id: "{{ lights_dim_temperature }}"
brightness: "{{ elevation_brightness }}"
color_temp: "{{ circadian_temperature_value }}"
blueprint:
name: Presence-activated Light Off with Illuminance and sun's Elevation
description: Turn off a light when presence is not detected, or illuminance is above a set Lux level or sun's elevation or in time range.
domain: automation
source_url: https://gist.github.com/snowyu/1bc65cb8d635d880473bc31b5e102c37/#file-motion-light-off-yaml
input:
motion_entity:
name: Presence Sensor
description: >-
This can be a device_tracker, an input_boolean, a binary_sensor,
or any entity that can switch to "on" or "home".
It can also be a media_player that can swith to "playing" or "paused".
selector:
entity:
# domain: binary_sensor
# device_class: motion
default: "device_tracker.me"
motion_duration:
name: Presence Sensor Duration Time (Optional)
description: The state lasts at least.
default: 0
selector:
number:
min: 0
max: 3600
unit_of_measurement: seconds
sunrise_elevation:
name: Sunrise elevation (Optional)
description: turn off after Sunrise elevation. Elevation is the angle between the sun and the horizon. Negative values mean the sun is BELOW the horizon.
default: false
selector:
number:
min: -90
max: 90
unit_of_measurement: degrees
sunset_elevation:
name: Sunset elevation (Optional)
description: turn off before Sunset elevation. Elevation is the angle between the sun and the horizon. Negative values mean the sun is BELOW the horizon.
default: false
selector:
number:
min: -90
max: 90
unit_of_measurement: degrees
lux_entity:
name: Illuminance Sensor (Optional)
default: false
selector:
entity:
domain: sensor
device_class: illuminance
lux_level:
name: Illuminance level (Optional)
description: If lux is above this value, the light will turn off.
default: false
selector:
number:
min: 0
max: 1000
light_target:
name: Light
selector:
target:
entity:
domain: light
start_time:
name: Light off start time (Optional)
description: only light off after start time
default: ''
selector:
time:
end_time:
name: Light off end time (Optional)
description: only light off before end time
default: ''
selector:
time:
no_motion_wait:
name: Wait time before turn off (Optional)
description: Time to leave the light on after last motion is detected.
default: 0
selector:
number:
min: 0
max: 3600
unit_of_measurement: seconds
mode: restart
max_exceeded: silent
trigger_variables:
sunset_elevation: !input sunset_elevation
sunrise_elevation: !input sunrise_elevation
lux_entity: !input lux_entity
lux_level: !input lux_level
variables:
motion_entity: !input motion_entity
sunset_elevation: !input sunset_elevation
sunrise_elevation: !input sunrise_elevation
lux_entity: !input lux_entity
lux_level: !input lux_level
no_motion_wait: !input no_motion_wait
start_time: !input start_time
end_time: !input end_time
ts_start: "{{ start_time and today_at(start_time)|as_timestamp }}"
ts_end: "{{ end_time and today_at(end_time)|as_timestamp }}"
ts_now: "{{ now().timestamp() }}"
elevation: "{{ sunset_elevation if ts_now > today_at('12:00:00')|as_timestamp else sunrise_elevation }}"
trigger:
- platform: state
entity_id: !input motion_entity
for:
seconds: !input motion_duration
- platform: template
value_template: "{{ (lux_entity != false) and (states(lux_entity)|float(0) > lux_level|float(0)) }}"
- platform: template
value_template: >-
{%- set ts_now = now().timestamp() -%}
{%- set elevation = sunset_elevation if ts_now > today_at('12:00:00')|as_timestamp else sunrise_elevation -%}
{{ (elevation != false) and (state_attr('sun.sun','elevation') > elevation|float(90)) }}
condition:
# - condition: state
# entity_id: !input light_target
# state: "on"
- condition: or
conditions:
- condition: template
value_template: >-
{{( states(motion_entity) == 'unknown') or not (states(motion_entity) in ['on','home','playing','paused']) }}
- condition: template
value_template: "{{ (lux_entity != false) and (states(lux_entity)|float(0) > lux_level|float(0)) }}"
- condition: template
value_template: "{{ (elevation != false) and (state_attr('sun.sun','elevation') > elevation|float(90)) }}"
- condition: template
value_template: >-
{%- if ts_end and ts_start and (ts_end < ts_start) -%}
{{ (ts_now >= ts_start and ts_now <= today_at('23:59:59')|as_timestamp) or (ts_now >= today_at('00:00:00')|as_timestamp and ts_now <= ts_end) }}
{%- else -%}
{{ (not ts_start or ts_now >= ts_start) and (not ts_end or ts_now <= ts_end) }}
{%- endif -%}
action:
- delay: !input no_motion_wait
- choose:
- alias: "check conditions again"
conditions:
- condition: or
conditions:
- condition: template
value_template: >-
{{( states(motion_entity) == 'unknown') or not (states(motion_entity) in ['on','home','playing','paused']) }}
- condition: template
value_template: "{{ (lux_entity != false) and (states(lux_entity)|float(0) > lux_level|float(0)) }}"
- condition: template
value_template: "{{ (elevation != false) and (state_attr('sun.sun','elevation') > elevation|float(90)) }}"
- condition: template
value_template: >-
{%- if ts_end and ts_start and (ts_end < ts_start) -%}
{{ (ts_now >= ts_start and ts_now <= today_at('23:59:59')|as_timestamp) or (ts_now >= today_at('00:00:00')|as_timestamp and ts_now <= ts_end) }}
{%- else -%}
{{ (not ts_start or ts_now >= ts_start) and (not ts_end or ts_now <= ts_end) }}
{%- endif -%}
sequence:
- service: light.turn_off
target: !input light_target
blueprint:
name: Motion-activated Light On with Illuminance and sun's Elevation
description: Turn on a light when presence is detected, illuminance is below a set Lux level and sun's elevation.
domain: automation
source_url: https://gist.github.com/snowyu/1bc65cb8d635d880473bc31b5e102c37/#file-motion-light-on-yaml
input:
motion_entity:
name: Presence Sensor
description: >-
This can be a device_tracker, an input_boolean, a binary_sensor,
or any entity that can switch to "on" or "home".
It can also be a media_player that can swith to "playing" or "paused".
selector:
entity:
# domain: binary_sensor
# device_class: motion
default: "device_tracker.me"
motion_duration:
name: Presence Sensor Duration Time (Optional)
description: The state lasts at least.
default: 0
selector:
number:
min: 0
max: 3600
unit_of_measurement: seconds
sunset_elevation:
name: Sunset elevation (Optional)
description: turn on after sunset elevation. Elevation is the angle between the sun and the horizon. Negative values mean the sun is BELOW the horizon.
default: false
selector:
number:
min: -90
max: 90
unit_of_measurement: degrees
sunrise_elevation:
name: Sunrise elevation (Optional)
description: turn on before sunrise elevation. Elevation is the angle between the sun and the horizon. Negative values mean the sun is BELOW the horizon.
default: false
selector:
number:
min: -90
max: 90
unit_of_measurement: degrees
lux_entity:
name: Illuminance Sensor (Optional)
default: false
selector:
entity:
domain: sensor
device_class: illuminance
lux_level:
name: Illuminance level (Optional)
description: If lux is below this value and motion is detected, the light will turn on.
default: false
selector:
number:
min: 0
max: 1000
light_target:
name: Light
selector:
target:
entity:
domain: light
start_time:
name: Light on start time (Optional)
description: only light on after start time
default: ''
selector:
time:
end_time:
name: Light on end time (Optional)
description: only light on before end time
default: ''
selector:
time:
mode: restart
max_exceeded: silent
trigger_variables:
sunset_elevation: !input sunset_elevation
sunrise_elevation: !input sunrise_elevation
lux_entity: !input lux_entity
lux_level: !input lux_level
variables:
motion_entity: !input motion_entity
sunset_elevation: !input sunset_elevation
sunrise_elevation: !input sunrise_elevation
lux_entity: !input lux_entity
lux_level: !input lux_level
start_time: !input start_time
end_time: !input end_time
ts_start: "{{ start_time and today_at(start_time)|as_timestamp }}"
ts_end: "{{ end_time and today_at(end_time)|as_timestamp }}"
ts_now: "{{ now().timestamp() }}"
elevation: "{{ sunset_elevation if ts_now > today_at('12:00:00')|as_timestamp else sunrise_elevation }}"
trigger:
- platform: state
entity_id: !input motion_entity
for:
seconds: !input motion_duration
- platform: template
value_template: "{{ (lux_entity != false) and (states(lux_entity)|float(0) <= lux_level|float(0)) }}"
- platform: template
value_template: >-
{%- set ts_now = now().timestamp() -%}
{%- set elevation = sunset_elevation if ts_now > today_at('12:00:00')|as_timestamp else sunrise_elevation -%}
{{ (elevation != false) and (state_attr('sun.sun','elevation') <= elevation|float(90)) }}
condition:
- condition: template
value_template: >-
{{( states(motion_entity) == 'unknown') or states(motion_entity) in ['on','home','playing','paused'] }}
- condition: template
value_template: "{{ (states(lux_entity) == 'unknown') or (states(lux_entity)|float(0) <= lux_level|float(0)) }}"
- condition: template
value_template: "{{ (elevation == false) or (state_attr('sun.sun','elevation') <= elevation|float(90)) }}"
- condition: template
value_template: >-
{%- if ts_end and ts_start and (ts_end < ts_start) -%}
{{ (ts_now >= ts_start and ts_now <= today_at('23:59:59')|as_timestamp) or (ts_now >= today_at('00:00:00')|as_timestamp and ts_now <= ts_end) }}
{%- else -%}
{{ (not ts_start or ts_now >= ts_start) and (not ts_end or ts_now <= ts_end) }}
{%- endif -%}
action:
- service: light.turn_on
target: !input light_target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment