Compare commits
8 Commits
1bac8c5e4c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| edc4cabde5 | |||
| bf5409d36e | |||
| 3491ac64db | |||
| c6301b9f76 | |||
| b8839bac3a | |||
| 2eba16f2e7 | |||
| 2c838a85a1 | |||
| 7dd83511a3 |
@@ -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: >
|
||||||
@@ -225,22 +250,19 @@ variables:
|
|||||||
remote_temperature_last_change: >
|
remote_temperature_last_change: >
|
||||||
{{ states[remote_temperature_entity].last_changed if remote_temperature_entity_valid else none }}
|
{{ states[remote_temperature_entity].last_changed if remote_temperature_entity_valid else none }}
|
||||||
scheduled_temperature: >
|
scheduled_temperature: >
|
||||||
{% set schedule_finder = namespace(current_temperature = none) %}
|
{% set selected = states(active_scheduler_selector) %}
|
||||||
{% set selected_friendly_name = states(active_scheduler_selector) %}
|
{% if selected not in [none, 'unknown', ''] %}
|
||||||
{% if selected_friendly_name is not none and selected_friendly_name != 'unknown' %}
|
{% for schedule in radiator_schedules if state_attr(schedule, 'friendly_name') == selected and is_state(schedule, 'on') %}
|
||||||
{% for schedule in radiator_schedules %}
|
{% set temp = state_attr(schedule, 'temp') %}
|
||||||
{% if state_attr(schedule, 'friendly_name') == selected_friendly_name and states(schedule) == 'on' %}
|
{% if temp is not none and temp | is_number %}
|
||||||
{% set temp = state_attr(schedule, 'temp') %}
|
{{ temp }}
|
||||||
{% if temp is not none and temp | is_number %}
|
{% break %}
|
||||||
{% set schedule_finder.current_temperature = temp %}
|
|
||||||
{% break %}
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ schedule_finder.current_temperature }}
|
|
||||||
|
|
||||||
# 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 }}
|
||||||
@@ -249,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 }}
|
||||||
|
|
||||||
@@ -257,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) %}
|
||||||
@@ -281,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 +
|
||||||
@@ -289,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
|
||||||
@@ -328,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
|
||||||
@@ -383,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
|
||||||
@@ -437,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
|
||||||
@@ -503,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
|
||||||
@@ -531,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
|
||||||
|
|||||||
Reference in New Issue
Block a user