349 lines
11 KiB
YAML
349 lines
11 KiB
YAML
blueprint:
|
|
name: Wake-up Sunrise (Kelvin, smooth & smart) - Fixed
|
|
description: >
|
|
Moderner Wecker mit Sonnenaufgangseffekt. Korrigierte Version mit sequenzieller Variablen-Berechnung.
|
|
domain: automation
|
|
|
|
input:
|
|
light_entity:
|
|
name: Ziel-Licht
|
|
selector:
|
|
entity:
|
|
domain: light
|
|
timestamp_sensor:
|
|
name: Zeitstempel-Entität (optional)
|
|
default: none
|
|
selector:
|
|
entity:
|
|
device_class: timestamp
|
|
manual_time:
|
|
name: Manuelle Weckzeit
|
|
default: "07:00:00"
|
|
selector:
|
|
time: {}
|
|
sunrise_duration_min:
|
|
name: Dauer des Sonnenaufgangs (Minuten)
|
|
default: 25
|
|
selector:
|
|
number:
|
|
min: 5
|
|
max: 120
|
|
step: 5
|
|
unit_of_measurement: min
|
|
mode: slider
|
|
start_brightness_pct:
|
|
name: Starthelligkeit (%)
|
|
default: 3
|
|
selector:
|
|
number:
|
|
min: 1
|
|
max: 100
|
|
step: 1
|
|
mode: slider
|
|
end_brightness_pct:
|
|
name: Endhelligkeit (%)
|
|
default: 100
|
|
selector:
|
|
number:
|
|
min: 5
|
|
max: 100
|
|
step: 1
|
|
mode: slider
|
|
start_kelvin:
|
|
name: Start-Kelvin (warm)
|
|
default: 2200
|
|
selector:
|
|
number:
|
|
min: 1500
|
|
max: 9000
|
|
step: 50
|
|
unit_of_measurement: K
|
|
mode: slider
|
|
end_kelvin:
|
|
name: End-Kelvin (kühler / tageslicht)
|
|
default: 6500
|
|
selector:
|
|
number:
|
|
min: 1500
|
|
max: 9000
|
|
step: 50
|
|
unit_of_measurement: K
|
|
mode: slider
|
|
enable_color_ramp:
|
|
name: Farbverlauf (RGB) statt Kelvin
|
|
default: false
|
|
selector:
|
|
boolean: {}
|
|
start_color_rgb:
|
|
name: Startfarbe (RGB)
|
|
default: { r: 255, g: 120, b: 20 }
|
|
selector:
|
|
color_rgb: {}
|
|
end_color_rgb:
|
|
name: Endfarbe (RGB)
|
|
default: { r: 255, g: 255, b: 255 }
|
|
selector:
|
|
color_rgb: {}
|
|
ramp_steps:
|
|
name: Schrittanzahl (Glätte)
|
|
default: 60
|
|
selector:
|
|
number:
|
|
min: 10
|
|
max: 240
|
|
step: 10
|
|
check_entity:
|
|
name: Check-Entität
|
|
default: none
|
|
selector:
|
|
entity: {}
|
|
require_workday:
|
|
name: Nur an Arbeitstagen
|
|
default: false
|
|
selector:
|
|
boolean: {}
|
|
workday_sensor:
|
|
name: Workday-Sensor
|
|
default: binary_sensor.workday
|
|
selector:
|
|
entity:
|
|
domain: binary_sensor
|
|
respect_quiet_hours:
|
|
name: Ruhezeiten beachten
|
|
default: false
|
|
selector:
|
|
boolean: {}
|
|
quiet_start:
|
|
name: Ruhezeit Beginn
|
|
default: "22:00:00"
|
|
selector:
|
|
time: {}
|
|
quiet_end:
|
|
name: Ruhezeit Ende
|
|
default: "06:00:00"
|
|
selector:
|
|
time: {}
|
|
off_cancels:
|
|
name: Ausschalten bricht ab
|
|
default: true
|
|
selector:
|
|
boolean: {}
|
|
pre_actions:
|
|
name: Vor-Aktionen
|
|
default: []
|
|
selector:
|
|
action: {}
|
|
post_actions:
|
|
name: Nach-Aktionen
|
|
default: []
|
|
selector:
|
|
action: {}
|
|
|
|
# Globale Variablen (nur statische Zuweisungen aus Inputs)
|
|
variables:
|
|
le: !input light_entity
|
|
sensor_ts: !input timestamp_sensor
|
|
manual_time: !input manual_time
|
|
duration_min: !input sunrise_duration_min
|
|
start_pct: !input start_brightness_pct
|
|
end_pct: !input end_brightness_pct
|
|
steps: !input ramp_steps
|
|
enable_rgb: !input enable_color_ramp
|
|
off_cancels: !input off_cancels
|
|
check_entity: !input check_entity
|
|
require_workday: !input require_workday
|
|
workday_sensor: !input workday_sensor
|
|
respect_quiet: !input respect_quiet_hours
|
|
quiet_start: !input quiet_start
|
|
quiet_end: !input quiet_end
|
|
startK_in: !input start_kelvin
|
|
endK_in: !input end_kelvin
|
|
rgb_start: !input start_color_rgb
|
|
rgb_end: !input end_color_rgb
|
|
|
|
trigger:
|
|
- platform: time_pattern
|
|
minutes: "*"
|
|
|
|
action:
|
|
# Ebene 1: Basis-Berechnungen und Geräte-Attribute holen
|
|
- variables:
|
|
seconds: "{{ (duration_min | float(25)) * 60 }}"
|
|
range_pct: "{{ (end_pct | float) - (start_pct | float) }}"
|
|
minK_native: "{{ state_attr(le, 'min_color_temp_kelvin') }}"
|
|
maxK_native: "{{ state_attr(le, 'max_color_temp_kelvin') }}"
|
|
minM: "{{ state_attr(le, 'min_mireds') }}"
|
|
maxM: "{{ state_attr(le, 'max_mireds') }}"
|
|
sr: "{{ rgb_start.r | int }}"
|
|
sg: "{{ rgb_start.g | int }}"
|
|
sb: "{{ rgb_start.b | int }}"
|
|
er: "{{ rgb_end.r | int }}"
|
|
eg: "{{ rgb_end.g | int }}"
|
|
eb: "{{ rgb_end.b | int }}"
|
|
supported_modes: "{{ state_attr(le, 'supported_color_modes') | default([]) }}"
|
|
|
|
# Ebene 2: Berechnungen, die auf Ebene 1 basieren (z.B. device_k_min)
|
|
- variables:
|
|
device_k_min: >-
|
|
{% if minK_native is number %}{{ minK_native | int }}
|
|
{% elif maxM is number %}{{ (1000000 / (maxM | float)) | int }}
|
|
{% else %}2000{% endif %}
|
|
device_k_max: >-
|
|
{% if maxK_native is number %}{{ maxK_native | int }}
|
|
{% elif minM is number %}{{ (1000000 / (minM | float)) | int }}
|
|
{% else %}6500{% endif %}
|
|
tick: >-
|
|
{% set t = (seconds | float) / (steps | float) %}
|
|
{{ [ t, 1 ] | max | int }}
|
|
can_rgb: >-
|
|
{{ 'hs' in supported_modes or 'rgb' in supported_modes or 'rgbw' in supported_modes or 'rgbww' in supported_modes or 'xy' in supported_modes }}
|
|
can_ct: >-
|
|
{{ 'color_temp' in supported_modes or minM is number or minK_native is number or maxM is number or maxK_native is number }}
|
|
|
|
# Ebene 3: Finale Kelvin-Werte und Bedingungen
|
|
- variables:
|
|
startK_clamped: >-
|
|
{% set s1 = [startK_in | int, device_k_min] | max %}
|
|
{{ [s1, device_k_max] | min }}
|
|
endK_clamped: >-
|
|
{% set e1 = [endK_in | int, device_k_min] | max %}
|
|
{{ [e1, device_k_max] | min }}
|
|
cond_check_entity_ok: >-
|
|
{{ check_entity == 'none' or states(check_entity) in ['on','home','unknown'] }}
|
|
cond_workday_ok: >-
|
|
{{ (not require_workday) or (is_state(workday_sensor, 'on')) }}
|
|
cond_quiet_ok: >-
|
|
{% if not respect_quiet %}true
|
|
{% else %}
|
|
{% set nowt = now().time() %}
|
|
{% set qs = strptime(quiet_start, '%H:%M:%S').time() %}
|
|
{% set qe = strptime(quiet_end, '%H:%M:%S').time() %}
|
|
{% if qs <= qe %}{{ not (nowt >= qs and nowt < qe) }}
|
|
{% else %}{{ not (nowt >= qs or nowt < qe) }}{% endif %}
|
|
{% endif %}
|
|
|
|
# Ebene 4: Finalisierung der Kelvin-Werte
|
|
- variables:
|
|
start_kelvin_final: "{{ [startK_clamped, endK_clamped] | min }}"
|
|
end_kelvin_final: "{{ [startK_clamped, endK_clamped] | max }}"
|
|
|
|
# --- Ablauf ---
|
|
- wait_template: >-
|
|
{{ sensor_ts == 'none' or as_timestamp(states(sensor_ts), None) != None }}
|
|
|
|
- wait_template: >-
|
|
{% set alarm_ts = as_timestamp(sensor_ts != 'none' and states(sensor_ts) or (states('sensor.date') ~ ' ' ~ manual_time)) %}
|
|
{% set now_ts = as_timestamp(now()) %}
|
|
{{ 0 < (alarm_ts - now_ts) <= (seconds | float) and cond_check_entity_ok and cond_workday_ok and cond_quiet_ok }}
|
|
|
|
- choose: []
|
|
default: !input pre_actions
|
|
|
|
- condition: template
|
|
value_template: "{{ cond_check_entity_ok and cond_workday_ok and cond_quiet_ok }}"
|
|
|
|
- choose:
|
|
- conditions: "{{ enable_rgb and can_rgb }}"
|
|
sequence:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ start_pct | int }}"
|
|
rgb_color: ["{{ sr }}","{{ sg }}","{{ sb }}"]
|
|
transition: 1
|
|
- conditions: "{{ can_ct }}"
|
|
sequence:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ start_pct | int }}"
|
|
color_temp_kelvin: "{{ start_kelvin_final | int }}"
|
|
transition: 1
|
|
default:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ start_pct | int }}"
|
|
transition: 1
|
|
|
|
- repeat:
|
|
while:
|
|
- >-
|
|
{% set alarm_ts = as_timestamp(sensor_ts != 'none' and states(sensor_ts) or (states('sensor.date') ~ ' ' ~ manual_time)) %}
|
|
{{ 0 < (alarm_ts - as_timestamp(now())) <= (seconds | float) }}
|
|
- "{{ not (off_cancels and is_state(le, 'off')) }}"
|
|
sequence:
|
|
- delay:
|
|
seconds: "{{ tick | int }}"
|
|
- variables:
|
|
alarm_ts: >-
|
|
{{ as_timestamp(sensor_ts != 'none' and states(sensor_ts) or (states('sensor.date') ~ ' ' ~ manual_time)) }}
|
|
remain: "{{ (alarm_ts - as_timestamp(now())) | float }}"
|
|
frac: "{{ (remain / (seconds | float)) | float }}"
|
|
bri_now: "{{ ((end_pct | float) - ((range_pct | float) * frac)) | round(0) | int }}"
|
|
r_now: "{{ (sr + (er - sr) * (1 - frac)) | round(0) | int }}"
|
|
g_now: "{{ (sg + (eg - sg) * (1 - frac)) | round(0) | int }}"
|
|
b_now: "{{ (sb + (eb - sb) * (1 - frac)) | round(0) | int }}"
|
|
kelv_now: "{{ ((end_kelvin_final | float) - ((end_kelvin_final | float - start_kelvin_final | float) * frac)) | round(0) | int }}"
|
|
- choose:
|
|
- conditions: "{{ enable_rgb and can_rgb }}"
|
|
sequence:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ [bri_now, 1] | max }}"
|
|
rgb_color: ["{{ r_now }}","{{ g_now }}","{{ b_now }}"]
|
|
transition: "{{ [ (tick | int) - 1, 0 ] | max }}"
|
|
- conditions: "{{ can_ct }}"
|
|
sequence:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ [bri_now, 1] | max }}"
|
|
color_temp_kelvin: "{{ kelv_now }}"
|
|
transition: "{{ [ (tick | int) - 1, 0 ] | max }}"
|
|
default:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ [bri_now, 1] | max }}"
|
|
transition: "{{ [ (tick | int) - 1, 0 ] | max }}"
|
|
|
|
- choose:
|
|
- conditions: "{{ enable_rgb and can_rgb }}"
|
|
sequence:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ end_pct | int }}"
|
|
rgb_color: ["{{ er }}","{{ eg }}","{{ eb }}"]
|
|
transition: 1
|
|
- conditions: "{{ can_ct }}"
|
|
sequence:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ end_pct | int }}"
|
|
color_temp_kelvin: "{{ end_kelvin_final | int }}"
|
|
transition: 1
|
|
default:
|
|
- service: light.turn_on
|
|
target:
|
|
entity_id: !input light_entity
|
|
data:
|
|
brightness_pct: "{{ end_pct | int }}"
|
|
transition: 1
|
|
|
|
- choose: []
|
|
default: !input post_actions
|
|
|
|
mode: single
|
|
max_exceeded: silent |