Compare commits
66 Commits
de2c1e778f
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| edc4cabde5 | |||
| bf5409d36e | |||
| 3491ac64db | |||
| c6301b9f76 | |||
| b8839bac3a | |||
| 2eba16f2e7 | |||
| 2c838a85a1 | |||
| 7dd83511a3 | |||
| 1bac8c5e4c | |||
| 106d6215b1 | |||
| e99c3aa967 | |||
| 90f895dbe5 | |||
| 2e6fcefca4 | |||
| 69c65c844f | |||
| a2343237c3 | |||
| 5dd43bbd89 | |||
| a797acf3ab | |||
| e72365df0a | |||
| 0bb4ced299 | |||
| 3ff5db1cbf | |||
| 5895c7c9dc | |||
| aee08c12cc | |||
| 2fdf78ac75 | |||
| d58ea02aeb | |||
| 1d0b0ff241 | |||
| 413eea13e0 | |||
| a170d7d0e2 | |||
| 336f8e2e74 | |||
| 59edb3265c | |||
| 1759929d9f | |||
| 6ccbe1839b | |||
| f719294bcf | |||
| 9e9dbf8e5f | |||
| 1f0cc41a58 | |||
| 146e4e6ab5 | |||
| f6fe2f9ab9 | |||
| 55dff75ce5 | |||
| 5fdc338194 | |||
| 4de21e35ec | |||
| ddc8408a73 | |||
| 7042453358 | |||
| d3beca60b6 | |||
| d68a173de6 | |||
| ab94183c65 | |||
| 576b6fa98a | |||
| e200814de6 | |||
| 9cb8b30fca | |||
| 640681ce43 | |||
| e40e2b3e90 | |||
| 34c7cc90b9 | |||
| 49263eb1ca | |||
| 0ca8f4a97d | |||
| 1b6d967d80 | |||
| acb4c180ad | |||
| cd2053c999 | |||
| 16b721814b | |||
| b3126d5cc7 | |||
| 714bde1ee1 | |||
| f830176260 | |||
| 094beba3d6 | |||
| 770e5a1884 | |||
| 9e1909e690 | |||
| 3dd3671591 | |||
| 3ce1d58b7c | |||
| 01416a3751 | |||
| aadf1c2860 |
@@ -1,10 +1,16 @@
|
||||
mode: single
|
||||
mode: queued
|
||||
max: 10
|
||||
blueprint:
|
||||
name: Bosch BTH-RA Radiator Control
|
||||
homeassistant:
|
||||
min_version: "2024.6.0"
|
||||
description: >
|
||||
Eine Automation zur automatischen Steuerung eines Bosch TRV Heizkörperthermostats.
|
||||
|
||||
**Temperatur-Prioritätslogik:**
|
||||
1. Alarm armed_away → Abwesenheitstemperatur
|
||||
2. Aktiver Zeitplan → Temperatur aus Schedule
|
||||
3. Fallback → Abwesenheitstemperatur
|
||||
domain: automation
|
||||
author: Me
|
||||
input:
|
||||
@@ -16,10 +22,70 @@ blueprint:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: climate
|
||||
temperature_sensor:
|
||||
name: Temperatursensor
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: sensor
|
||||
device_class: temperature
|
||||
sensor_sync_threshold:
|
||||
name: Sensor-Synchronisations-Schwellenwert
|
||||
description: >
|
||||
Minimale Temperaturdifferenz in °C, um eine Sensor-Synchronisation auszulösen (Default = 0.5°C).
|
||||
|
||||
**Synchronisation erfolgt bei:**
|
||||
1. Differenz zwischen Sensor und TRV ≥ Schwellenwert
|
||||
2. Sensor kreuzt Solltemperatur von unten (verhindert zu spätes Aufheizen)
|
||||
3. Sensor kreuzt Solltemperatur von oben (verhindert Überhitzung)
|
||||
4. Spätestens nach 25 Minuten ohne Änderung
|
||||
default: 0.5
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
min: 0.1
|
||||
max: 1.0
|
||||
unit_of_measurement: "°C"
|
||||
step: 0.1
|
||||
heating_period_switch:
|
||||
name: Heizperiode Switch
|
||||
description: Optional - Input Boolean der angibt ob Heizperiode aktiv ist. Wenn nicht gesetzt, ist die Heizperiode immer aktiv.
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: input_boolean
|
||||
min_temperature:
|
||||
name: Minimale Temperatur
|
||||
description: >
|
||||
Minimale erlaubte Solltemperatur als Sicherheitsgrenze (Default = 15°C).
|
||||
Alle berechneten Temperaturen werden auf diesen Minimalwert begrenzt (Clamping).
|
||||
default: 15
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
min: 10.0
|
||||
max: 20.0
|
||||
unit_of_measurement: "°C"
|
||||
step: 0.5
|
||||
max_temperature:
|
||||
name: Maximale Temperatur
|
||||
description: >
|
||||
Maximale erlaubte Solltemperatur als Sicherheitsgrenze (Default = 23°C).
|
||||
Alle berechneten Temperaturen werden auf diesen Maximalwert begrenzt (Clamping).
|
||||
default: 23
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
min: 20.0
|
||||
max: 25.0
|
||||
unit_of_measurement: "°C"
|
||||
step: 0.5
|
||||
window_section:
|
||||
name: Fenster-/Türsensor Konfiguration
|
||||
description: Konfiguration für den Fenster-/Türsensor.
|
||||
collapsed: false
|
||||
collapsed: true
|
||||
input:
|
||||
window_sensor:
|
||||
name: Fenster-/Türsensor (oder Gruppe)
|
||||
@@ -50,138 +116,481 @@ blueprint:
|
||||
max: 3600.0
|
||||
unit_of_measurement: seconds
|
||||
step: 1.0
|
||||
remaining_section:
|
||||
name: Weitere Konfiguration
|
||||
description: Sonstige Konfigurationen für die Automation
|
||||
collapsed: false
|
||||
schedule_section:
|
||||
name: Heizplan Konfiguration
|
||||
description: Konfiguration der Heizpläne die für den Radiator berücksichtigt werden sollen
|
||||
collapsed: true
|
||||
input:
|
||||
temperature_sensor:
|
||||
name: Temperatursensor
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: sensor
|
||||
device_class: temperature
|
||||
radiator_schedules:
|
||||
name: Heizpläne
|
||||
description: Alle Heizpläne die für den Radiator berücksichtigt werden sollen. Sind mehrere Schedules aktiv, wird der erste mit einem gültigen Slot verwendet.
|
||||
description: Alle Heizpläne die für den Radiator berücksichtigt werden sollen. Sind mehrere Schedules aktiv, wird der erste mit einer gültigen Temperatur verwendet.
|
||||
default: []
|
||||
selector:
|
||||
entity:
|
||||
multiple: true
|
||||
filter:
|
||||
- domain: switch
|
||||
- domain: schedule
|
||||
|
||||
active_scheduler_selector:
|
||||
name: Aktiver Scheduler Selector
|
||||
description: >
|
||||
Input Select der den aktuell aktiven Scheduler enthält (per Friendly Name).
|
||||
Wird verwendet um zu bestimmen welcher Schedule für die Temperatur verwendet werden soll.
|
||||
|
||||
**WICHTIG**: Die Options müssen die Friendly Names der Scheduler aus der Scheduler-Liste enthalten.
|
||||
|
||||
**HINWEIS**: Wenn der angezeigte Scheduler inaktiv ist (off), wird automatisch
|
||||
auf die Abwesenheitstemperatur zurückgegriffen.
|
||||
|
||||
Beispiel: Wird typischerweise vom "Heizplan Selector" Blueprint gesteuert.
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_select
|
||||
away_section:
|
||||
name: Konfiguration für Abwesenheitsmodus
|
||||
description: Konfiguration für das Absenken der Heizung im Abwesenheitsmodus eines Alarmsystems
|
||||
collapsed: true
|
||||
input:
|
||||
alarm_control_panel:
|
||||
name: Alarm Control Panel
|
||||
description: Optional - Alarm Control Panel um Heizung abzusenken, wenn Alarm im Abwesendmodus ist
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: alarm_control_panel
|
||||
away_temperature:
|
||||
name: Abwesenheitstemperatur
|
||||
description: >
|
||||
Temperatur die verwendet wird, wenn der Alarm im Abwesendmodus ist oder kein Zeitplan aktiv ist (Default = 18°C).
|
||||
|
||||
**Verwendung:**
|
||||
- Primär: Alarm Control Panel im Modus 'armed_away' (höchste Priorität)
|
||||
- Fallback: Wenn kein aktiver Zeitplan eine Temperatur liefert
|
||||
default: 18
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
min: 15.0
|
||||
max: 25.0
|
||||
unit_of_measurement: "°C"
|
||||
step: 0.5
|
||||
override_section:
|
||||
name: Override Reset Konfiguration
|
||||
description: Automatisches Zurücksetzen der Solltemperatur nach manueller Änderung am Thermostat
|
||||
collapsed: true
|
||||
input:
|
||||
override_reset_duration:
|
||||
name: Override Reset Zeitraum
|
||||
description: >
|
||||
Zeit nach der eine manuelle Temperaturänderung automatisch auf den Heizplan zurückgesetzt wird.
|
||||
|
||||
**Feature deaktiviert wenn auf 00:00:00 gesetzt** (Default = 00:00:00)
|
||||
|
||||
**Verhalten:**
|
||||
- Nur manuelle Änderungen am Thermostat werden zurückgesetzt (nicht über Home Assistant)
|
||||
- Timer startet neu bei jeder weiteren manuellen Änderung
|
||||
- Reset erfolgt nur wenn Solltemperatur vom Heizplan abweicht
|
||||
- Wenn kein Schedule aktiv ist, wird auf Abwesenheitstemperatur zurückgesetzt
|
||||
- Alarm-Modus hat Priorität: Bei aktivem Alarm erfolgt kein Reset (Abwesenheitstemperatur gilt)
|
||||
|
||||
Beispiel: Nach 2 Stunden wird die Temperatur wieder auf den aktiven Heizplan-Wert gesetzt.
|
||||
default:
|
||||
hours: 0
|
||||
minutes: 0
|
||||
seconds: 0
|
||||
selector:
|
||||
duration:
|
||||
enable_day: false
|
||||
|
||||
variables:
|
||||
# Input-Variablen
|
||||
trv: !input trv
|
||||
radiator_schedules: !input radiator_schedules
|
||||
temperature_sensor: !input temperature_sensor
|
||||
sensor_sync_threshold: !input sensor_sync_threshold
|
||||
heating_period_switch: !input heating_period_switch
|
||||
radiator_schedules: !input radiator_schedules
|
||||
active_scheduler_selector: !input active_scheduler_selector
|
||||
away_temperature: !input away_temperature
|
||||
min_temperature: !input min_temperature
|
||||
max_temperature: !input max_temperature
|
||||
alarm_control_panel: !input alarm_control_panel
|
||||
override_reset_duration: !input override_reset_duration
|
||||
|
||||
# Konstanten
|
||||
temperature_change_tolerance: 0.4 # °C - Minimale Differenz für Temperaturänderung
|
||||
sensor_sync_max_age: 1499 # Sekunden (25 Minuten - 1 Sekunde) - Max Alter für Sensor-Sync
|
||||
random_delay_max_seconds: 30
|
||||
|
||||
# Zufalls-Delay für climate.set_temperature
|
||||
random_delay_seconds: "{{ range(0, random_delay_max_seconds + 1) | random }}"
|
||||
|
||||
# Entity-Discovery
|
||||
remote_temperature_entity: >
|
||||
{% set entities = device_entities(device_id(trv)) %}
|
||||
{% set remote_temperature_entity_id = namespace(id='') %}
|
||||
{% for entity in entities %}
|
||||
{% if 'remote_temperature' in entity %}
|
||||
{% set remote_temperature_entity_id.id = entity %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ remote_temperature_entity_id.id }}
|
||||
{{ device_entities(device_id(trv)) | select('search', 'remote_temperature') | list | first | default('') }}
|
||||
window_detection_entity: >
|
||||
{% set entities = device_entities(device_id(trv)) %}
|
||||
{% set window_detection_entity_id = namespace(id='') %}
|
||||
{% for entity in entities %}
|
||||
{% if 'window_detection' in entity %}
|
||||
{% set window_detection_entity_id.id = entity %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ window_detection_entity_id.id }}
|
||||
{{ device_entities(device_id(trv)) | select('search', 'window_detection') | list | first | default('') }}
|
||||
setpoint_change_source_entity: >
|
||||
{{ device_entities(device_id(trv)) | select('search', 'setpoint_change_source') | list | first | default('') }}
|
||||
|
||||
# Entity-Validierung
|
||||
remote_temperature_entity_valid: >
|
||||
{{ remote_temperature_entity and states(remote_temperature_entity) not in ['unknown', 'unavailable', none] }}
|
||||
window_detection_entity_valid: >
|
||||
{{ window_detection_entity and window_detection_entity | length > 0 }}
|
||||
setpoint_change_source_entity_valid: >
|
||||
{{ setpoint_change_source_entity and states(setpoint_change_source_entity) not in ['unknown', 'unavailable', none] }}
|
||||
|
||||
# Basis-Berechnungen
|
||||
is_heating_period: >
|
||||
{{ heating_period_switch in [none, ''] or is_state(heating_period_switch, 'on') }}
|
||||
current_remote_temperature: >
|
||||
{{ states(remote_temperature_entity) | float(0) if remote_temperature_entity_valid else 0 }}
|
||||
remote_temperature_last_change: >
|
||||
{{ states[remote_temperature_entity].last_changed if remote_temperature_entity_valid else none }}
|
||||
scheduled_temperature: >
|
||||
{% set ns = namespace(current_temperature = none) %}
|
||||
{% for schedule in radiator_schedules %}
|
||||
{% if states(schedule) == 'on' and state_attr(schedule, 'current_slot') is not none %}
|
||||
{% set current_slot = state_attr(schedule, 'current_slot') %}
|
||||
{% set actions = state_attr(schedule, 'actions') %}
|
||||
{% if actions is not none and actions | length > current_slot %}
|
||||
{% set action = actions[current_slot] %}
|
||||
{% if action.data.temperature is defined %}
|
||||
{% set ns.current_temperature = action.data.temperature %}
|
||||
{% break %}
|
||||
{% endif %}
|
||||
{% set selected = states(active_scheduler_selector) %}
|
||||
{% if selected not in [none, 'unknown', ''] %}
|
||||
{% for schedule in radiator_schedules if state_attr(schedule, 'friendly_name') == selected and is_state(schedule, 'on') %}
|
||||
{% set temp = state_attr(schedule, 'temp') %}
|
||||
{% if temp is not none and temp | is_number %}
|
||||
{{ temp }}
|
||||
{% break %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ ns.current_temperature }}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
# Temperatur-Berechnungen
|
||||
# Priorität: 1. Alarm armed_away → away_temperature, 2. Aktiver Zeitplan → scheduled_temperature, 3. Fallback → away_temperature
|
||||
target_temperature: >
|
||||
{% if alarm_control_panel and is_state(alarm_control_panel, 'armed_away') %}
|
||||
{{ away_temperature }}
|
||||
{% elif scheduled_temperature != none %}
|
||||
{{ scheduled_temperature }}
|
||||
{% else %}
|
||||
{{ away_temperature }}
|
||||
{% endif %}
|
||||
# Begrenzt target_temperature auf den Bereich [min_temperature, max_temperature] (Clamping)
|
||||
safe_temperature: >
|
||||
{{ [min_temperature, [max_temperature, target_temperature | float(18)] | min] | max }}
|
||||
|
||||
# Status-Prüfungen
|
||||
is_valid_temperature: >
|
||||
{{ safe_temperature is not none and safe_temperature | is_number }}
|
||||
is_temperature_change_needed: >
|
||||
{{ (safe_temperature | float(0) - state_attr(trv, 'temperature') | float(0)) | abs >= temperature_change_tolerance }}
|
||||
# Synchronisation nötig wenn: 1) Differenz > Schwelle, 2) Sensor kreuzt Soll-Temp von unten, 3) Sensor kreuzt Soll-Temp von oben
|
||||
is_sensor_sync_needed: >
|
||||
{% set new_sensor_temp = states(temperature_sensor) | float(0) %}
|
||||
{% set target_temp = state_attr(trv, 'temperature') | float(0) %}
|
||||
{% set diff = (new_sensor_temp - current_remote_temperature) | abs %}
|
||||
{{ diff >= sensor_sync_threshold or
|
||||
(new_sensor_temp < target_temp and current_remote_temperature >= target_temp) or
|
||||
(new_sensor_temp > target_temp and current_remote_temperature <= target_temp) }}
|
||||
scheduler_mismatch: >
|
||||
{% set selected = states(active_scheduler_selector) %}
|
||||
{% if selected not in ['unknown', '', none] %}
|
||||
{% set schedule_found = namespace(value=false) %}
|
||||
{% for schedule in radiator_schedules %}
|
||||
{% if state_attr(schedule, 'friendly_name') == selected %}
|
||||
{% set schedule_found.value = true %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ not schedule_found.value }}
|
||||
{% else %}
|
||||
false
|
||||
{% endif %}
|
||||
is_manual_override: >
|
||||
{{ (state_attr(trv, 'temperature') | float(0) - safe_temperature | float(0)) | abs >= temperature_change_tolerance }}
|
||||
|
||||
# Override Reset Berechnungen
|
||||
# Konvertiert duration-Dictionary {hours, minutes, seconds} in Gesamtsekunden
|
||||
override_reset_duration_seconds: >
|
||||
{{ (override_reset_duration.hours | default(0) | int) * 3600 +
|
||||
(override_reset_duration.minutes | default(0) | int) * 60 +
|
||||
(override_reset_duration.seconds | default(0) | int) if override_reset_duration is mapping else 0 }}
|
||||
override_last_change: >
|
||||
{{ states[setpoint_change_source_entity].last_updated if setpoint_change_source_entity_valid else none }}
|
||||
is_setpoint_manual: >
|
||||
{{ setpoint_change_source_entity_valid and states(setpoint_change_source_entity) == 'manual' }}
|
||||
# Early exits: 1) Keine Änderung/Timeout=0 → false, 2) Nicht manuell → false, 3) Berechne Zeitdifferenz
|
||||
override_duration_exceeded: >
|
||||
{% if override_last_change == none or override_reset_duration_seconds == 0 %}
|
||||
false
|
||||
{% elif not is_setpoint_manual %}
|
||||
false
|
||||
{% else %}
|
||||
{% set last_change = as_datetime(override_last_change) %}
|
||||
{{ last_change != none and (now() - last_change).total_seconds() > override_reset_duration_seconds }}
|
||||
{% endif %}
|
||||
|
||||
triggers:
|
||||
- trigger: state
|
||||
- platform: state
|
||||
entity_id:
|
||||
- !input window_sensor
|
||||
from: "off"
|
||||
to: "on"
|
||||
for: !input window_delay_open
|
||||
id: FENSTER_OPEN
|
||||
- trigger: state
|
||||
id: WINDOW_OPENED
|
||||
- platform: state
|
||||
entity_id:
|
||||
- !input window_sensor
|
||||
from: "on"
|
||||
to: "off"
|
||||
for: !input window_delay_close
|
||||
id: FENSTER_CLOSED
|
||||
id: WINDOW_CLOSED
|
||||
- platform: time_pattern
|
||||
# Synce Temperatur alle 20 Minuten (Teiler von 60)
|
||||
minutes: "/20"
|
||||
id: SYNC_TEMPERATURE
|
||||
# Periodische Überprüfung alle 5 Minuten (Temperatursynchronisation, Override-Check)
|
||||
minutes: "/5"
|
||||
id: PERIODIC_CHECK
|
||||
- platform: state
|
||||
entity_id: !input temperature_sensor
|
||||
id: TEMP_CHANGED
|
||||
id: SENSOR_TEMPERATURE_CHANGED
|
||||
- platform: state
|
||||
entity_id: !input alarm_control_panel
|
||||
to: "armed_away"
|
||||
id: ALARM_ARMED_AWAY
|
||||
- platform: state
|
||||
entity_id: !input alarm_control_panel
|
||||
from: "armed_away"
|
||||
id: ALARM_DISARMED
|
||||
- platform: state
|
||||
entity_id: !input heating_period_switch
|
||||
to: "on"
|
||||
id: HEATING_PERIOD_STARTED
|
||||
- platform: state
|
||||
entity_id: !input heating_period_switch
|
||||
to: "off"
|
||||
id: HEATING_PERIOD_ENDED
|
||||
- platform: state
|
||||
entity_id: !input radiator_schedules
|
||||
attribute: temp
|
||||
id: SCHEDULE_TEMPERATURE_CHANGED
|
||||
- platform: state
|
||||
entity_id: !input active_scheduler_selector
|
||||
id: SCHEDULE_SELECTOR_CHANGED
|
||||
|
||||
# Hinweis zur Wartbarkeit: climate.set_temperature wird an 4 Stellen verwendet:
|
||||
# 1. Heizperiode aktiviert - Setzt Temperatur beim Einschalten der Heizung
|
||||
# 2. Fenster geschlossen - Setzt Temperatur nach Fensterschließung
|
||||
# 3. Override Reset - Setzt Temperatur zurück nach manuellem Override
|
||||
# 4. Schedule/Alarm-Änderungen - Setzt Temperatur bei Zeitplan- oder Alarmänderungen
|
||||
# Standardformat: service: climate.set_temperature | target: !input trv | data: safe_temperature
|
||||
actions:
|
||||
- choose:
|
||||
# Heizperiode Switch Aktionen
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- FENSTER_OPEN
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_state(window_detection_entity, 'off') }}
|
||||
- HEATING_PERIOD_STARTED
|
||||
- HEATING_PERIOD_ENDED
|
||||
sequence:
|
||||
- service: switch.turn_on
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
alias: Setze Fenster auf offen
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- HEATING_PERIOD_STARTED
|
||||
sequence:
|
||||
- service: climate.set_hvac_mode
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
hvac_mode: "heat"
|
||||
- if:
|
||||
- condition: state
|
||||
entity_id: !input window_sensor
|
||||
state: "on"
|
||||
then:
|
||||
- service: switch.turn_on
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_valid_temperature and is_temperature_change_needed and is_state(window_detection_entity, 'off') }}
|
||||
then:
|
||||
- delay:
|
||||
seconds: "{{ random_delay_seconds }}"
|
||||
- service: climate.set_temperature
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
temperature: "{{ safe_temperature | float }}"
|
||||
alias: Heizperiode aktiviert - Setze Modus auf heat, synchronisiere Fensterstatus und Solltemperatur
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- HEATING_PERIOD_ENDED
|
||||
sequence:
|
||||
- service: switch.turn_off
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
- service: climate.set_hvac_mode
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
hvac_mode: "off"
|
||||
alias: Heizperiode deaktiviert - Setze Fenster geschlossen und Modus auf off
|
||||
alias: Heizperiode Switch Änderung
|
||||
alias: Heizperiode Switch Aktionen
|
||||
# Alle bestehenden Aktionen nur ausführen wenn Heizperiode aktiv ist
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- FENSTER_CLOSED
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_state(window_detection_entity, 'on') }}
|
||||
value_template: "{{ is_heating_period }}"
|
||||
sequence:
|
||||
- service: switch.turn_off
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
- if:
|
||||
# setze Fenster auf offen/geschlossen
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- WINDOW_OPENED
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ scheduled_temperature is not none }}
|
||||
then:
|
||||
- action: climate.set_temperature
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
temperature: "{{ scheduled_temperature | float }}"
|
||||
alias: Setze Fenster auf geschlossen und setze Solltemperatur auf Wert aus Zeitplan (wenn vorhanden)
|
||||
# temperature sensor sync
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- SYNC_TEMPERATURE
|
||||
- TEMP_CHANGED
|
||||
sequence:
|
||||
- service: number.set_value
|
||||
data:
|
||||
value: "{{ states(temperature_sensor) | float }}"
|
||||
target:
|
||||
entity_id: "{{ remote_temperature_entity }}"
|
||||
alias: Synchronisiere Temperatur am TRV
|
||||
{{ is_state(window_detection_entity, 'off') }}
|
||||
sequence:
|
||||
- service: switch.turn_on
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
alias: Setze Fenster auf offen
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- WINDOW_CLOSED
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_state(window_detection_entity, 'on') }}
|
||||
sequence:
|
||||
- service: switch.turn_off
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
- delay:
|
||||
minutes: 1
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_valid_temperature and is_temperature_change_needed }}
|
||||
then:
|
||||
- delay:
|
||||
seconds: "{{ random_delay_seconds }}"
|
||||
- service: climate.set_temperature
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
temperature: "{{ safe_temperature | float }}"
|
||||
alias: Setze Fenster auf geschlossen und setze Solltemperatur auf Wert aus Zeitplan (wenn vorhanden)
|
||||
alias: Fensterstatus Änderung
|
||||
# temperature sensor sync
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- SENSOR_TEMPERATURE_CHANGED
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ temperature_sensor is defined and states(temperature_sensor) | is_number }}
|
||||
- condition: template
|
||||
value_template: "{{ is_sensor_sync_needed }}"
|
||||
sequence:
|
||||
- service: number.set_value
|
||||
data:
|
||||
value: "{{ states(temperature_sensor) | float }}"
|
||||
target:
|
||||
entity_id: "{{ remote_temperature_entity }}"
|
||||
alias: Synchronisiere Temperatur am TRV (bei Änderung)
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- PERIODIC_CHECK
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ temperature_sensor is defined and states(temperature_sensor) | is_number }}
|
||||
- condition: template
|
||||
value_template: >
|
||||
{% if remote_temperature_last_change != none %}
|
||||
{% set last_change = as_datetime(remote_temperature_last_change) %}
|
||||
{{ last_change != none and (now() - last_change).total_seconds() > sensor_sync_max_age }}
|
||||
{% else %}
|
||||
false
|
||||
{% endif %}
|
||||
sequence:
|
||||
- service: number.set_value
|
||||
data:
|
||||
value: "{{ states(temperature_sensor) | float }}"
|
||||
target:
|
||||
entity_id: "{{ remote_temperature_entity }}"
|
||||
alias: Synchronisiere Temperatur am TRV (zeitbasiert, wenn länger als 25min unverändert)
|
||||
alias: Temperatursynchronisation
|
||||
# override reset
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- PERIODIC_CHECK
|
||||
- condition: template
|
||||
value_template: "{{ override_reset_duration_seconds > 0 }}"
|
||||
- condition: template
|
||||
value_template: "{{ is_manual_override }}"
|
||||
- condition: template
|
||||
value_template: "{{ override_duration_exceeded }}"
|
||||
sequence:
|
||||
- delay:
|
||||
seconds: "{{ random_delay_seconds }}"
|
||||
- service: climate.set_temperature
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
temperature: "{{ safe_temperature | float }}"
|
||||
alias: Setze Solltemperatur zurück nach manuellem Override
|
||||
alias: Override Reset
|
||||
# setze Solltemperatur bei Schedule und Alarm-Status-Änderungen
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- ALARM_ARMED_AWAY
|
||||
- ALARM_DISARMED
|
||||
- SCHEDULE_TEMPERATURE_CHANGED
|
||||
- SCHEDULE_SELECTOR_CHANGED
|
||||
- condition: template
|
||||
value_template: >
|
||||
{% if trigger.id == 'SCHEDULE_TEMPERATURE_CHANGED' %}
|
||||
{% set selected_friendly_name = states(active_scheduler_selector) %}
|
||||
{{ state_attr(trigger.entity_id, 'friendly_name') == selected_friendly_name }}
|
||||
{% else %}
|
||||
true
|
||||
{% endif %}
|
||||
sequence:
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_valid_temperature and is_temperature_change_needed and is_state(window_detection_entity, 'off') }}
|
||||
then:
|
||||
- delay:
|
||||
seconds: "{{ random_delay_seconds }}"
|
||||
- service: climate.set_temperature
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
temperature: "{{ safe_temperature | float }}"
|
||||
# Notification bei Scheduler-Mismatch
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: "{{ scheduler_mismatch and trigger.id == 'SCHEDULER_CHANGED' }}"
|
||||
then:
|
||||
- service: persistent_notification.create
|
||||
data:
|
||||
title: "⚠️ Radiator Control - Scheduler nicht gefunden"
|
||||
message: >
|
||||
Der ausgewählte Scheduler '{{ states(active_scheduler_selector) }}' wurde nicht in der
|
||||
Scheduler-Liste gefunden.
|
||||
|
||||
TRV '{{ state_attr(trv, 'friendly_name') }}' nutzt Fallback-Temperatur: {{ safe_temperature }}°C
|
||||
(Original: {{ target_temperature }}°C, Limits: {{ min_temperature }}-{{ max_temperature }}°C)
|
||||
|
||||
Bitte Konfiguration überprüfen.
|
||||
notification_id: "radiator_control_scheduler_mismatch_{{ trv }}"
|
||||
alias: Setze Solltemperatur
|
||||
alias: Solltemperatur bei Änderungen
|
||||
alias: Aktionen während Heizperiode
|
||||
alias: Hauptsteuerung
|
||||
@@ -1,187 +0,0 @@
|
||||
mode: single
|
||||
blueprint:
|
||||
name: Bosch BTH-RA Radiator Control - DEV
|
||||
homeassistant:
|
||||
min_version: "2024.6.0"
|
||||
description: >
|
||||
Eine Automation zur automatischen Steuerung eines Bosch TRV Heizkörperthermostats.
|
||||
domain: automation
|
||||
author: Me
|
||||
input:
|
||||
trv:
|
||||
name: Thermostat
|
||||
description: Thermostat muss ein Bosch BTH-RA sein
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: climate
|
||||
window_section:
|
||||
name: Fenster-/Türsensor Konfiguration
|
||||
description: Konfiguration für den Fenster-/Türsensor.
|
||||
collapsed: false
|
||||
input:
|
||||
window_sensor:
|
||||
name: Fenster-/Türsensor (oder Gruppe)
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: binary_sensor
|
||||
window_delay_open:
|
||||
name: Fenster-/Türsensor Verzögerung
|
||||
description: Zeit die das Fenster offen bleiben muss, um die den Radiator in den "Fenster offen"-Modus zu versetzen (Default = 30s)
|
||||
default: 30
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
min: 0.0
|
||||
max: 3600.0
|
||||
unit_of_measurement: seconds
|
||||
step: 1.0
|
||||
window_delay_close:
|
||||
name: Fenster-/Türsensor Verzögerung
|
||||
description: Zeit die das Fenster geschlossen bleiben muss, um die den Radiator in den "Fenster geschlossen"-Modus zu versetzen (Default = 5s)
|
||||
default: 5
|
||||
selector:
|
||||
number:
|
||||
mode: box
|
||||
min: 0.0
|
||||
max: 3600.0
|
||||
unit_of_measurement: seconds
|
||||
step: 1.0
|
||||
remaining_section:
|
||||
name: Weitere Konfiguration
|
||||
description: Sonstige Konfigurationen für die Automation
|
||||
collapsed: false
|
||||
input:
|
||||
temperature_sensor:
|
||||
name: Temperatursensor
|
||||
selector:
|
||||
entity:
|
||||
multiple: false
|
||||
filter:
|
||||
- domain: sensor
|
||||
device_class: temperature
|
||||
radiator_schedules:
|
||||
name: Heizpläne
|
||||
description: Alle Heizpläne die für den Radiator berücksichtigt werden sollen. Sind mehrere Schedules aktiv, wird der erste mit einem gültigen Slot verwendet.
|
||||
default: []
|
||||
selector:
|
||||
entity:
|
||||
multiple: true
|
||||
filter:
|
||||
- domain: switch
|
||||
|
||||
variables:
|
||||
trv: !input trv
|
||||
radiator_schedules: !input radiator_schedules
|
||||
temperature_sensor: !input temperature_sensor
|
||||
remote_temperature_entity: >
|
||||
{% set entities = device_entities(device_id(trv)) %}
|
||||
{% set remote_temperature_entity_id = namespace(id='') %}
|
||||
{% for entity in entities %}
|
||||
{% if 'remote_temperature' in entity %}
|
||||
{% set remote_temperature_entity_id.id = entity %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ remote_temperature_entity_id.id }}
|
||||
window_detection_entity: >
|
||||
{% set entities = device_entities(device_id(trv)) %}
|
||||
{% set window_detection_entity_id = namespace(id='') %}
|
||||
{% for entity in entities %}
|
||||
{% if 'window_detection' in entity %}
|
||||
{% set window_detection_entity_id.id = entity %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ window_detection_entity_id.id }}
|
||||
scheduled_temperature: >
|
||||
{% set ns = namespace(current_temperature = none) %}
|
||||
{% for schedule in radiator_schedules %}
|
||||
{% if states(schedule) == 'on' and state_attr(schedule, 'current_slot') is not none %}
|
||||
{% set current_slot = state_attr(schedule, 'current_slot') %}
|
||||
{% set actions = state_attr(schedule, 'actions') %}
|
||||
{% if actions is not none and actions | length > current_slot %}
|
||||
{% set action = actions[current_slot] %}
|
||||
{% if action.data.temperature is defined %}
|
||||
{% set ns.current_temperature = action.data.temperature %}
|
||||
{% break %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ ns.current_temperature }}
|
||||
|
||||
triggers:
|
||||
- trigger: state
|
||||
entity_id:
|
||||
- !input window_sensor
|
||||
from: "off"
|
||||
to: "on"
|
||||
for: !input window_delay_open
|
||||
id: FENSTER_OPEN
|
||||
- trigger: state
|
||||
entity_id:
|
||||
- !input window_sensor
|
||||
from: "on"
|
||||
to: "off"
|
||||
for: !input window_delay_close
|
||||
id: FENSTER_CLOSED
|
||||
- platform: time_pattern
|
||||
# Synce Temperatur alle 20 Minuten (Teiler von 60)
|
||||
minutes: "/20"
|
||||
id: SYNC_TEMPERATURE
|
||||
- platform: state
|
||||
entity_id: !input temperature_sensor
|
||||
id: TEMP_CHANGED
|
||||
|
||||
actions:
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- FENSTER_OPEN
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_state(window_detection_entity, 'off') }}
|
||||
sequence:
|
||||
- service: switch.turn_on
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
alias: Setze Fenster auf offen
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- FENSTER_CLOSED
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ is_state(window_detection_entity, 'on') }}
|
||||
sequence:
|
||||
- service: switch.turn_off
|
||||
target:
|
||||
entity_id: "{{ window_detection_entity }}"
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ scheduled_temperature is not none }}
|
||||
then:
|
||||
- action: climate.set_temperature
|
||||
target:
|
||||
entity_id: !input trv
|
||||
data:
|
||||
temperature: "{{ scheduled_temperature | float }}"
|
||||
alias: Setze Fenster auf geschlossen und setze Solltemperatur auf Wert aus Zeitplan (wenn vorhanden)
|
||||
# temperature sensor sync
|
||||
- choose:
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id:
|
||||
- SYNC_TEMPERATURE
|
||||
- TEMP_CHANGED
|
||||
sequence:
|
||||
- service: number.set_value
|
||||
data:
|
||||
value: "{{ states(temperature_sensor) | float }}"
|
||||
target:
|
||||
entity_id: "{{ remote_temperature_entity }}"
|
||||
alias: Synchronisiere Temperatur am TRV
|
||||
268
Climate/schedule_selector.yaml
Normal file
268
Climate/schedule_selector.yaml
Normal file
@@ -0,0 +1,268 @@
|
||||
blueprint:
|
||||
name: Heizplan Selector basierend auf Kalenderereignissen
|
||||
description: >
|
||||
Wählt automatisch einen Heizplan basierend auf Kalenderereignissen aus.
|
||||
|
||||
Der Blueprint überwacht einen Kalender und wechselt zwischen verschiedenen
|
||||
Schedule-Helfern basierend auf Keywords im Event-Titel oder der Beschreibung.
|
||||
|
||||
**WICHTIG**: Die Anzahl der Scheduler und Keywordlisten muss übereinstimmen!
|
||||
Jede Zeile in den Keywordlisten entspricht einem Scheduler an der gleichen Position.
|
||||
|
||||
Bei Event-Ende wird zum Standard-Scheduler zurückgekehrt, außer ein anderes
|
||||
Event ist bereits aktiv.
|
||||
|
||||
Required = *
|
||||
domain: automation
|
||||
homeassistant:
|
||||
min_version: "2024.6.0"
|
||||
author: Me
|
||||
input:
|
||||
calendar_section:
|
||||
name: Kalender-Einstellungen
|
||||
description: Kalender und zeitlicher Offset für Events
|
||||
collapsed: false
|
||||
input:
|
||||
calendar_entity:
|
||||
name: Kalender *
|
||||
description: Der Kalender, der für Event-Erkennung überwacht wird
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: calendar
|
||||
|
||||
event_offset:
|
||||
name: Zeitlicher Offset
|
||||
description: >
|
||||
Optional: Zeitlicher Versatz für Event-Start und -Ende.
|
||||
Beispiel: "-00:15:00" startet 15 Minuten vor dem Event.
|
||||
default: "00:00:00"
|
||||
selector:
|
||||
duration:
|
||||
enable_day: false
|
||||
|
||||
scheduler_section:
|
||||
name: Scheduler-Konfiguration
|
||||
description: Schedule-Helfer und zugeordnete Keywords
|
||||
collapsed: false
|
||||
input:
|
||||
scheduler_list:
|
||||
name: Scheduler-Liste *
|
||||
description: >
|
||||
Liste der Schedule-Helfer (schedule entities).
|
||||
Die Reihenfolge muss mit den Keywordlisten übereinstimmen!
|
||||
selector:
|
||||
entity:
|
||||
multiple: true
|
||||
filter:
|
||||
- domain: schedule
|
||||
|
||||
keyword_lists:
|
||||
name: Keywordlisten *
|
||||
description: >
|
||||
Eine Keywordliste pro Zeile (komma-separiert).
|
||||
Beispiel:
|
||||
urlaub,vacation,holiday
|
||||
homeoffice,wfh,remote
|
||||
normal,standard
|
||||
|
||||
**Position in der Liste = Position im Scheduler!**
|
||||
Zeile 1 → Scheduler 1, Zeile 2 → Scheduler 2, etc.
|
||||
selector:
|
||||
text:
|
||||
multiline: true
|
||||
type: text
|
||||
|
||||
default_scheduler:
|
||||
name: Standard-Scheduler *
|
||||
description: >
|
||||
Dieser Scheduler wird aktiviert, wenn kein Keyword matched
|
||||
oder ein Event endet (und kein anderes aktiv ist).
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: schedule
|
||||
|
||||
helper_section:
|
||||
name: Helper-Entity
|
||||
description: Entity zum Speichern des aktiven Schedulers
|
||||
collapsed: false
|
||||
input:
|
||||
helper_entity:
|
||||
name: Input Select Helper *
|
||||
description: >
|
||||
Die input_select Helper-Entity, in die der aktive Scheduler geschrieben wird.
|
||||
|
||||
**WICHTIG**: Die Options der input_select müssen vorbereitet werden!
|
||||
Sie müssen die Friendly Names folgender Entities enthalten:
|
||||
- Alle Scheduler aus der Scheduler-Liste
|
||||
- Den Standard-Scheduler
|
||||
|
||||
Beispiel Options:
|
||||
["Urlaub Heizplan", "Home Office Heizplan", "Normal Heizplan", "Standard Heizplan"]
|
||||
|
||||
Die Blueprint schreibt den Friendly Name (nicht die Entity-ID) in die Helper-Entity.
|
||||
selector:
|
||||
entity:
|
||||
filter:
|
||||
- domain: input_select
|
||||
|
||||
mode: single
|
||||
max_exceeded: silent
|
||||
|
||||
triggers:
|
||||
- platform: calendar
|
||||
event: start
|
||||
entity_id: !input calendar_entity
|
||||
offset: !input event_offset
|
||||
id: CALENDAR_START
|
||||
|
||||
- platform: calendar
|
||||
event: end
|
||||
entity_id: !input calendar_entity
|
||||
offset: !input event_offset
|
||||
id: CALENDAR_END
|
||||
|
||||
variables:
|
||||
schedulers: !input scheduler_list
|
||||
keywords_raw: !input keyword_lists
|
||||
default_scheduler: !input default_scheduler
|
||||
helper: !input helper_entity
|
||||
calendar: !input calendar_entity
|
||||
|
||||
# Keywords in Liste umwandeln (eine pro Zeile)
|
||||
keyword_lists: >
|
||||
{{ keywords_raw.split('\n') | select() | list }}
|
||||
|
||||
# Bei Event-Start: Keywords matchen
|
||||
matched_scheduler: >
|
||||
{% set ns = namespace(scheduler = none) %}
|
||||
{% if trigger.id == 'CALENDAR_START' %}
|
||||
{% set event_text = (trigger.calendar_event.summary | lower) ~ ' ' ~ (trigger.calendar_event.description | default('') | lower) %}
|
||||
{% for i in range(keyword_lists | length) %}
|
||||
{% set keywords = keyword_lists[i].split(',') | map('trim') | map('lower') | list %}
|
||||
{% set matched = namespace(found = false) %}
|
||||
{% for keyword in keywords %}
|
||||
{% if keyword in event_text %}
|
||||
{% set matched.found = true %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% if matched.found and i < (schedulers | length) %}
|
||||
{% set ns.scheduler = schedulers[i] %}
|
||||
{% break %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{{ ns.scheduler }}
|
||||
|
||||
# Bei Event-Ende: Prüfen ob ein anderes Event aktiv ist
|
||||
other_event_active: >
|
||||
{% if trigger.id == 'CALENDAR_END' %}
|
||||
{% set start = state_attr(calendar, 'start_time') %}
|
||||
{% set end = state_attr(calendar, 'end_time') %}
|
||||
{% if start and end %}
|
||||
{% set now_ts = now().timestamp() %}
|
||||
{% set start_ts = as_timestamp(start) %}
|
||||
{% set end_ts = as_timestamp(end) %}
|
||||
{{ start_ts <= now_ts and now_ts <= end_ts }}
|
||||
{% else %}
|
||||
false
|
||||
{% endif %}
|
||||
{% else %}
|
||||
false
|
||||
{% endif %}
|
||||
|
||||
conditions: []
|
||||
|
||||
actions:
|
||||
- choose:
|
||||
# Event-Start: Scheduler aktivieren wenn Keyword matched
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id: CALENDAR_START
|
||||
- condition: template
|
||||
value_template: "{{ matched_scheduler is not none and matched_scheduler != '' }}"
|
||||
sequence:
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ state_attr(matched_scheduler, 'friendly_name') in state_attr(helper, 'options') }}
|
||||
then:
|
||||
# Matched Scheduler ist in Options vorhanden
|
||||
- service: input_select.select_option
|
||||
target:
|
||||
entity_id: !input helper_entity
|
||||
data:
|
||||
option: "{{ state_attr(matched_scheduler, 'friendly_name') }}"
|
||||
else:
|
||||
# Matched Scheduler nicht vorhanden - Fallback auf Default
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ state_attr(default_scheduler, 'friendly_name') in state_attr(helper, 'options') }}
|
||||
then:
|
||||
- service: input_select.select_option
|
||||
target:
|
||||
entity_id: !input helper_entity
|
||||
data:
|
||||
option: "{{ state_attr(default_scheduler, 'friendly_name') }}"
|
||||
- service: persistent_notification.create
|
||||
data:
|
||||
title: "⚠️ Heizplan Selector - Konfigurationsfehler"
|
||||
message: >
|
||||
Der gematchte Scheduler '{{ state_attr(matched_scheduler, 'friendly_name') }}' ({{ matched_scheduler }}) ist nicht in den Options der input_select '{{ helper }}' vorhanden.
|
||||
|
||||
Fallback auf Standard-Scheduler '{{ state_attr(default_scheduler, 'friendly_name') }}' ({{ default_scheduler }}).
|
||||
|
||||
Event: {{ trigger.calendar_event.summary }}
|
||||
notification_id: "schedule_selector_config_error"
|
||||
else:
|
||||
# Auch Default-Scheduler nicht vorhanden
|
||||
- service: persistent_notification.create
|
||||
data:
|
||||
title: "❌ Heizplan Selector - Kritischer Konfigurationsfehler"
|
||||
message: >
|
||||
Weder der gematchte Scheduler '{{ state_attr(matched_scheduler, 'friendly_name') }}' ({{ matched_scheduler }}) noch der Standard-Scheduler '{{ state_attr(default_scheduler, 'friendly_name') }}' ({{ default_scheduler }}) sind in den Options der input_select '{{ helper }}' vorhanden.
|
||||
|
||||
Kein Scheduler wurde aktiviert!
|
||||
|
||||
Bitte input_select Options korrigieren.
|
||||
|
||||
Event: {{ trigger.calendar_event.summary }}
|
||||
notification_id: "schedule_selector_critical_error"
|
||||
alias: Event-Start - Scheduler aktivieren
|
||||
|
||||
# Event-Ende: Zu Standard zurückkehren (nur wenn kein anderes Event aktiv)
|
||||
- conditions:
|
||||
- condition: trigger
|
||||
id: CALENDAR_END
|
||||
- condition: template
|
||||
value_template: "{{ not other_event_active }}"
|
||||
sequence:
|
||||
- if:
|
||||
- condition: template
|
||||
value_template: >
|
||||
{{ state_attr(default_scheduler, 'friendly_name') in state_attr(helper, 'options') }}
|
||||
then:
|
||||
- service: input_select.select_option
|
||||
target:
|
||||
entity_id: !input helper_entity
|
||||
data:
|
||||
option: "{{ state_attr(default_scheduler, 'friendly_name') }}"
|
||||
else:
|
||||
- service: persistent_notification.create
|
||||
data:
|
||||
title: "❌ Heizplan Selector - Konfigurationsfehler"
|
||||
message: >
|
||||
Der Standard-Scheduler '{{ state_attr(default_scheduler, 'friendly_name') }}' ({{ default_scheduler }}) ist nicht in den Options der input_select '{{ helper }}' vorhanden.
|
||||
|
||||
Kein Scheduler wurde aktiviert!
|
||||
|
||||
Bitte input_select Options korrigieren.
|
||||
|
||||
Event: {{ trigger.calendar_event.summary }}
|
||||
notification_id: "schedule_selector_default_error"
|
||||
alias: Event-Ende - Standard-Scheduler aktivieren
|
||||
|
||||
default: []
|
||||
|
||||
Reference in New Issue
Block a user