Compare commits

...

7 Commits

View File

@@ -6,6 +6,11 @@ blueprint:
min_version: "2024.6.0" min_version: "2024.6.0"
description: > description: >
Eine Automation zur automatischen Steuerung eines Bosch TRV Heizkörperthermostats. 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 domain: automation
author: Me author: Me
input: input:
@@ -27,7 +32,14 @@ blueprint:
device_class: temperature device_class: temperature
sensor_sync_threshold: sensor_sync_threshold:
name: Sensor-Synchronisations-Schwellenwert name: Sensor-Synchronisations-Schwellenwert
description: Minimale Temperaturdifferenz in °C, um eine Sensor-Synchronisation auszulösen (Default = 0.5°C). Temperatur wird weiterhin spätestens nach 25 Minuten synchronisiert. 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 default: 0.5
selector: selector:
number: number:
@@ -46,7 +58,9 @@ blueprint:
- domain: input_boolean - domain: input_boolean
min_temperature: min_temperature:
name: Minimale Temperatur name: Minimale Temperatur
description: Minimale erlaubte Solltemperatur als Sicherheitsgrenze (Default = 15°C) description: >
Minimale erlaubte Solltemperatur als Sicherheitsgrenze (Default = 15°C).
Alle berechneten Temperaturen werden auf diesen Minimalwert begrenzt (Clamping).
default: 15 default: 15
selector: selector:
number: number:
@@ -57,7 +71,9 @@ blueprint:
step: 0.5 step: 0.5
max_temperature: max_temperature:
name: Maximale Temperatur name: Maximale Temperatur
description: Maximale erlaubte Solltemperatur als Sicherheitsgrenze (Default = 28°C) description: >
Maximale erlaubte Solltemperatur als Sicherheitsgrenze (Default = 23°C).
Alle berechneten Temperaturen werden auf diesen Maximalwert begrenzt (Clamping).
default: 23 default: 23
selector: selector:
number: number:
@@ -146,7 +162,12 @@ blueprint:
- domain: alarm_control_panel - domain: alarm_control_panel
away_temperature: away_temperature:
name: Abwesenheitstemperatur name: Abwesenheitstemperatur
description: Temperatur die eingestellt wird, wenn der Alarm im Abwesendmodus ist (Default = 18°C) 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 default: 18
selector: selector:
number: number:
@@ -200,6 +221,10 @@ variables:
# Konstanten # Konstanten
temperature_change_tolerance: 0.4 # °C - Minimale Differenz für Temperaturänderung 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 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 # Entity-Discovery
remote_temperature_entity: > remote_temperature_entity: >
@@ -237,6 +262,7 @@ variables:
{% endif %} {% endif %}
# Temperatur-Berechnungen # Temperatur-Berechnungen
# Priorität: 1. Alarm armed_away → away_temperature, 2. Aktiver Zeitplan → scheduled_temperature, 3. Fallback → away_temperature
target_temperature: > target_temperature: >
{% if alarm_control_panel and is_state(alarm_control_panel, 'armed_away') %} {% if alarm_control_panel and is_state(alarm_control_panel, 'armed_away') %}
{{ away_temperature }} {{ away_temperature }}
@@ -245,6 +271,7 @@ variables:
{% else %} {% else %}
{{ away_temperature }} {{ away_temperature }}
{% endif %} {% endif %}
# Begrenzt target_temperature auf den Bereich [min_temperature, max_temperature] (Clamping)
safe_temperature: > safe_temperature: >
{{ [min_temperature, [max_temperature, target_temperature | float(18)] | min] | max }} {{ [min_temperature, [max_temperature, target_temperature | float(18)] | min] | max }}
@@ -253,6 +280,7 @@ variables:
{{ safe_temperature is not none and safe_temperature | is_number }} {{ safe_temperature is not none and safe_temperature | is_number }}
is_temperature_change_needed: > is_temperature_change_needed: >
{{ (safe_temperature | float(0) - state_attr(trv, 'temperature') | float(0)) | abs >= temperature_change_tolerance }} {{ (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: > is_sensor_sync_needed: >
{% set new_sensor_temp = states(temperature_sensor) | float(0) %} {% set new_sensor_temp = states(temperature_sensor) | float(0) %}
{% set target_temp = state_attr(trv, 'temperature') | float(0) %} {% set target_temp = state_attr(trv, 'temperature') | float(0) %}
@@ -277,6 +305,7 @@ variables:
{{ (state_attr(trv, 'temperature') | float(0) - safe_temperature | float(0)) | abs >= temperature_change_tolerance }} {{ (state_attr(trv, 'temperature') | float(0) - safe_temperature | float(0)) | abs >= temperature_change_tolerance }}
# Override Reset Berechnungen # Override Reset Berechnungen
# Konvertiert duration-Dictionary {hours, minutes, seconds} in Gesamtsekunden
override_reset_duration_seconds: > override_reset_duration_seconds: >
{{ (override_reset_duration.hours | default(0) | int) * 3600 + {{ (override_reset_duration.hours | default(0) | int) * 3600 +
(override_reset_duration.minutes | default(0) | int) * 60 + (override_reset_duration.minutes | default(0) | int) * 60 +
@@ -285,6 +314,7 @@ variables:
{{ states[setpoint_change_source_entity].last_updated if setpoint_change_source_entity_valid else none }} {{ states[setpoint_change_source_entity].last_updated if setpoint_change_source_entity_valid else none }}
is_setpoint_manual: > is_setpoint_manual: >
{{ setpoint_change_source_entity_valid and states(setpoint_change_source_entity) == '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: > override_duration_exceeded: >
{% if override_last_change == none or override_reset_duration_seconds == 0 %} {% if override_last_change == none or override_reset_duration_seconds == 0 %}
false false
@@ -324,7 +354,6 @@ triggers:
- platform: state - platform: state
entity_id: !input alarm_control_panel entity_id: !input alarm_control_panel
from: "armed_away" from: "armed_away"
to: "disarmed"
id: ALARM_DISARMED id: ALARM_DISARMED
- platform: state - platform: state
entity_id: !input heating_period_switch entity_id: !input heating_period_switch
@@ -379,8 +408,10 @@ actions:
- if: - if:
- condition: template - condition: template
value_template: > value_template: >
{{ is_valid_temperature and is_temperature_change_needed }} {{ is_valid_temperature and is_temperature_change_needed and is_state(window_detection_entity, 'off') }}
then: then:
- delay:
seconds: "{{ random_delay_seconds }}"
- service: climate.set_temperature - service: climate.set_temperature
target: target:
entity_id: !input trv entity_id: !input trv
@@ -433,11 +464,15 @@ actions:
- service: switch.turn_off - service: switch.turn_off
target: target:
entity_id: "{{ window_detection_entity }}" entity_id: "{{ window_detection_entity }}"
- delay:
minutes: 1
- if: - if:
- condition: template - condition: template
value_template: > value_template: >
{{ is_valid_temperature and is_temperature_change_needed }} {{ is_valid_temperature and is_temperature_change_needed }}
then: then:
- delay:
seconds: "{{ random_delay_seconds }}"
- service: climate.set_temperature - service: climate.set_temperature
target: target:
entity_id: !input trv entity_id: !input trv
@@ -499,6 +534,8 @@ actions:
- condition: template - condition: template
value_template: "{{ override_duration_exceeded }}" value_template: "{{ override_duration_exceeded }}"
sequence: sequence:
- delay:
seconds: "{{ random_delay_seconds }}"
- service: climate.set_temperature - service: climate.set_temperature
target: target:
entity_id: !input trv entity_id: !input trv
@@ -527,8 +564,10 @@ actions:
- if: - if:
- condition: template - condition: template
value_template: > value_template: >
{{ is_valid_temperature and is_temperature_change_needed }} {{ is_valid_temperature and is_temperature_change_needed and is_state(window_detection_entity, 'off') }}
then: then:
- delay:
seconds: "{{ random_delay_seconds }}"
- service: climate.set_temperature - service: climate.set_temperature
target: target:
entity_id: !input trv entity_id: !input trv