Einrückung
#load packages
homeassistant:
packages: !include_dir_merge_named packages
Einrückung
#load packages
homeassistant:
packages: !include_dir_merge_named packages
Danke dir. Kleine Korrektur für meine Umgebung:
#load packages
homeassistant:
packages: !include_dir_named packages
Update meines Energy-Manager Home-Assistant Packages (Bosch 5800i / PV-optimierte WP-Steuerung)
Ich habe mein bestehendes Energy-Manager-Package erweitert, nachdem es zu einem einmaligen, aber deutlichen Problem gekommen ist:
In einer Nacht lief der elektrische Zusatzheizer meiner Bosch Compress 5800i AW für mehrere Stunden durch und hat dabei ca. 16,6 kWh verbraucht sowie den Batteriespeicher vollständig entladen.
Die Analyse hat gezeigt:
switch.boiler_aux_heater_only war über die gesamte Zeit aktiv
dadurch lief die Anlage im reinen Heizstabbetrieb
die bestehende Logik hatte keine ausreichende Sicherheitsabschaltung
Der Fehler war kein Hardwareproblem, sondern ein fehlender Fail-Safe in der Automationslogik:
Aktivierung des Heizstabs war möglich (über PV-/Temperaturlogik)
aber es gab keine harte Begrenzung der Laufzeit
und keine zuverlässige Abschaltung bei fehlendem PV-Überschuss
Dadurch konnte ein einmaliger falscher Zustand über Stunden bestehen bleiben.
Ich habe das Package um zwei zentrale Schutzmechanismen erweitert:
Der Heizstab wird jetzt automatisch abgeschaltet, wenn er zu lange aktiv ist:
- alias: "EM: Aux-Heater max Laufzeit"
description: "Schaltet den Aux-Heater automatisch nach definierter Zeit wieder aus (Failsafe)"
mode: restart
trigger:
- platform: state
entity_id: switch.boiler_aux_heater_only
to: "on"
for: "00:20:00"
action:
- service: switch.turn_off
target:
entity_id: switch.boiler_aux_heater_only
Ziel:
verhindert Dauerbetrieb durch Fehltrigger oder vergessene Zustände
begrenzt mögliche Schäden auf wenige Minuten
Der Heizstab wird nun konsequent deaktiviert, wenn keine ausreichende PV-Leistung vorhanden ist:
- alias: "EM: Aux-Heater aus bei keinem PV-Überschuss"
description: "Schaltet den Aux-Heater aus, wenn kein ausreichender PV-Überschuss vorhanden ist"
mode: restart
trigger:
- platform: numeric_state
entity_id: sensor.em_available_for_heatpump
below: 0.3
for: "00:02:00"
action:
- condition: state
entity_id: switch.boiler_aux_heater_only
state: "on"
- service: switch.turn_off
target:
entity_id: switch.boiler_aux_heater_only
Ziel:
verhindert nächtlichen Netzbezug durch Heizstab
schützt Batteriespeicher zuverlässig vor Entladung
sorgt für PV-priorisierte Betriebsweise
Mit diesen beiden Ergänzungen ist das System jetzt deutlich robuster:
kein unbegrenzter Heizstabbetrieb mehr möglich
kein unkontrolliertes Entladen des Stromspeichers
automatische Rückfallebene bei Fehlern oder falschen States
PV-optimierter Betrieb wird konsequent eingehalten
Der Vorfall hat gezeigt, dass nicht die Optimierungslogik selbst das Problem war, sondern das Fehlen einer harten Sicherheitsbegrenzung für den Heizstabbetrieb.
Mit den neuen Failsafe-Automationen ist das System jetzt deutlich stabiler und fehlertoleranter aufgebaut.
Weil ich gerade dabei war, habe noch eine Sommer-/Winterumschaltung eingebaut**.**
Der Sommer-/Wintermodus wird jetzt:
über den input_select.energy_manager_mode gesteuert
zentral über das Script script.em_set_mode
automatisch bei Änderung des Selects ausgelöst
Dadurch ist sichergestellt:
keine „halb aktiven“ Zustände
vollständiges Ein-/Ausschalten aller relevanten Automationen
Wintermodus
Energy Manager aktiv
Temperaturprüfung aktiv
alle Automationen eingeschaltet:
Vorlaufregelung
DHW Steuerung
Aux-Heater Steuerung
Sommermodus
Energy Manager deaktiviert
DHW & Aux-Heater AUS
Automationen deaktiviert
System wird in definierten Grundzustand zurückgesetzt
Beim Wechsel in den Sommermodus erfolgt jetzt ein kompletter Reset:
alle Input-Booleans zurückgesetzt
alle relevanten Input-Numbers auf Default
Wärmepumpe geht in definierten Ausgangszustand
sichere Abschaltung aller Verbraucher
Zusätzlich gibt es jetzt eine dedizierte Automation:
reagiert direkt auf input_select.energy_manager_mode
ruft automatisch script.em_set_mode auf
keine manuelle Script-Auslösung mehr notwendig
Der neue Button zeigt jetzt klar den aktuellen Status und erlaubt direkten Wechsel:
Winter = blau
Sommer = rot
visuelle Rückmeldung + klare Zustandsanzeige
Screenshots:
# config/packages/energy_manager.yaml
# --- Helpers / Controls ---
input_boolean:
energy_manager_enabled:
name: "Energy Manager aktiv"
initial: on
energy_manager_temp_ok:
name: "Energy Manager: Temp OK"
initial: on
energy_manager_force_zero:
name: "Energy Manager: Force smoothed zero"
initial: off
icon: mdi:power-off
em_allow_aux:
name: "EM: Aux-Heater erlauben"
initial: off
em_dhw_charging:
name: "EM DHW Ladung aktiv"
initial: off
em_safe_mode:
name: "EM Safe Mode"
initial: off
icon: mdi:shield-alert
input_select:
energy_manager_mode:
name: "Energy Manager Modus"
options:
- "Sommer"
- "Winter"
input_number:
pw_max_charge:
name: "Powerwall max Ladeleistung (kW)"
initial: 4.6
min: 0
max: 11.0
step: 0.1
unit_of_measurement: kW
energy_manager_temp_start:
name: "EM Temp Start (°C)"
initial: 14
min: -40
max: 40
step: 0.5
energy_manager_temp_stop:
name: "EM Temp Stop (°C)"
initial: 17
min: -40
max: 40
step: 0.5
em_flow_temp_min:
name: "EM Vorlauf Minimum (°C)"
initial: 38
min: 20
max: 45
step: 0.5
em_flow_temp_max:
name: "EM Vorlauf Maximum (°C)"
initial: 50
min: 40
max: 60
step: 0.5
em_flow_temp_step_k:
name: "EM Vorlauf Änderung pro Intervall (°C)"
initial: 0.5
min: 0.1
max: 2
step: 0.1
em_min_runtime:
name: "EM Kompressor Mindestlaufzeit (Minuten)"
initial: 15
min: 5
max: 60
step: 1
em_pv_threshold_start:
name: "EM PV Überschuss Startschwelle (kW)"
initial: 3
min: 0
max: 5
step: 0.1
em_pv_threshold_stop:
name: "EM PV Überschuss Stoppschwelle (kW)"
initial: 1
min: 0
max: 5
step: 0.1
em_dhw_max_temp:
name: "EM DHW Max Temperatur (°C)"
initial: 55
min: 45
max: 70
step: 0.5
em_dhw_min_temp:
name: "EM DHW Min Temperatur (°C)"
initial: 45
min: 35
max: 55
step: 0.5
em_dhw_charge_min_duration:
name: "EM DHW Mindestladezeit (Minuten)"
initial: 20
min: 5
max: 60
step: 1
em_avail_start:
name: "EM Avail Start (kW)"
initial: 0.6
min: 0
max: 10
step: 0.1
em_avail_stop:
name: "EM Avail Stop (kW)"
initial: 0.4
min: 0
max: 10
step: 0.1
# --- Scripts ---
script:
em_set_mode:
alias: "EM: Modus anwenden"
mode: single
sequence:
- variables:
mode: "{{ states('input_select.energy_manager_mode') }}"
- choose:
- conditions:
- condition: template
value_template: "{{ mode == 'Winter' }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.energy_manager_enabled
- service: input_boolean.turn_on
target:
entity_id: input_boolean.energy_manager_temp_ok
- service: input_boolean.turn_off
target:
entity_id: input_boolean.em_safe_mode
- service: number.set_value
target:
entity_id: number.boiler_selected_flow_temperature
data:
value: "{{ states('input_number.em_flow_temp_min') | float(38) }}"
- delay: "00:00:02"
- service: automation.turn_on
target:
entity_id:
- automation.em_vorlauftemperatur_regeln
- automation.em_dhw_ladung_steuern
- automation.em_aux_heater_steuerung
- service: system_log.write
data:
message: "EM: Wintermodus aktiviert"
level: info
- conditions:
- condition: template
value_template: "{{ mode == 'Sommer' }}"
sequence:
- service: input_boolean.turn_off
target:
entity_id:
- input_boolean.energy_manager_enabled
- input_boolean.em_dhw_charging
- input_boolean.em_allow_aux
- service: automation.turn_off
target:
entity_id:
- automation.em_vorlauftemperatur_regeln
- automation.em_dhw_ladung_steuern
- automation.em_aux_heater_steuerung
- service: script.em_reset_to_defaults
- service: system_log.write
data:
message: "EM: Sommermodus aktiviert"
level: warning
em_toggle_mode:
alias: "EM: Modus umschalten"
mode: single
sequence:
- variables:
current: "{{ states('input_select.energy_manager_mode') }}"
- service: input_select.select_option
target:
entity_id: input_select.energy_manager_mode
data:
option: >
{% if current == 'Winter' %}
Sommer
{% else %}
Winter
{% endif %}
em_reset_to_defaults:
alias: "EM: Reset auf Standardwerte"
mode: single
sequence:
# 🛡 Safe Mode aktivieren (verhindert Zwischenzustände)
- service: input_boolean.turn_on
target:
entity_id: input_boolean.em_safe_mode
- delay: "00:00:01"
# 🧹 Grundsystem deaktivieren
- service: input_boolean.turn_off
target:
entity_id:
- input_boolean.energy_manager_enabled
- input_boolean.energy_manager_force_zero
- input_boolean.em_allow_aux
- input_boolean.em_dhw_charging
# ✔ Temp Status initialisieren
- service: input_boolean.turn_on
target:
entity_id: input_boolean.energy_manager_temp_ok
# 🔧 Input Numbers Reset
- service: input_number.set_value
data:
entity_id: input_number.pw_max_charge
value: 4.6
- service: input_number.set_value
data:
entity_id: input_number.energy_manager_temp_start
value: 14
- service: input_number.set_value
data:
entity_id: input_number.energy_manager_temp_stop
value: 17
- service: input_number.set_value
data:
entity_id: input_number.em_flow_temp_min
value: 38
- service: input_number.set_value
data:
entity_id: input_number.em_flow_temp_max
value: 50
- service: input_number.set_value
data:
entity_id: input_number.em_flow_temp_step_k
value: 0.5
- service: input_number.set_value
data:
entity_id: input_number.em_min_runtime
value: 15
- service: input_number.set_value
data:
entity_id: input_number.em_pv_threshold_start
value: 3
- service: input_number.set_value
data:
entity_id: input_number.em_pv_threshold_stop
value: 1
- service: input_number.set_value
data:
entity_id: input_number.em_dhw_max_temp
value: 55
- service: input_number.set_value
data:
entity_id: input_number.em_dhw_min_temp
value: 45
- service: input_number.set_value
data:
entity_id: input_number.em_dhw_charge_min_duration
value: 20
- service: input_number.set_value
data:
entity_id: input_number.em_avail_start
value: 0.6
- service: input_number.set_value
data:
entity_id: input_number.em_avail_stop
value: 0.4
# 🌡 Boiler Startwert setzen
- service: number.set_value
data:
entity_id: number.boiler_selected_flow_temperature
value: "{{ states('input_number.em_flow_temp_min') | float(38) }}"
# 🔌 Aktoren sicher aus
- service: switch.turn_off
target:
entity_id:
- switch.boiler_dhw_one_time_charging
- switch.boiler_aux_heater_only
# 📣 Feedback
- service: notify.persistent_notification
data:
title: "EM Reset"
message: "System wurde vollständig zurückgesetzt und in Wintermodus initialisiert"
# --- Filter Sensoren (Glättung) ---
sensor:
- platform: filter
name: "em_pv_power_smoothed"
entity_id: sensor.my_home_solar_energie
filters:
- filter: lowpass
time_constant: 2
precision: 2
- platform: filter
name: "em_home_load_smoothed"
entity_id: sensor.my_home_last_leistung
filters:
- filter: time_simple_moving_average
window_size: 3
precision: 2
- platform: filter
name: "em_powerwall_battery_power_smoothed"
entity_id: sensor.my_home_batterie_leistung
filters:
- filter: lowpass
time_constant: 6
precision: 2
# --- Template Sensors & Binary Sensors ---
template:
- sensor:
- name: "em_pv_power_corrected"
unit_of_measurement: "kW"
state: >-
{% set force = is_state('input_boolean.energy_manager_force_zero', 'on') %}
{% set raw = states('sensor.my_home_solar_energie') | float(0) %}
{% set sm = states('sensor.em_pv_power_smoothed') | float(0) %}
{% if force or raw < 0.02 %}
0
{% else %}
{{ sm | round(2) }}
{% endif %}
- name: "em_home_load_corrected"
unit_of_measurement: "kW"
state: >-
{% set force = is_state('input_boolean.energy_manager_force_zero', 'on') %}
{% set raw = states('sensor.my_home_last_leistung') | float(0) %}
{% set sm = states('sensor.em_home_load_smoothed') | float(0) %}
{% if force or raw < 0.02 %}
0
{% else %}
{{ sm | round(2) }}
{% endif %}
- name: "em_powerwall_charge_corrected"
unit_of_measurement: "kW"
state: >-
{% set force = is_state('input_boolean.energy_manager_force_zero', 'on') %}
{% set raw = states('sensor.my_home_batterie_leistung') | float(0) %}
{% set sm = states('sensor.em_powerwall_battery_power_smoothed') | float(0) %}
{% if force or (raw | abs) < 0.02 %}
0
{% else %}
{{ sm | round(2) }}
{% endif %}
- name: "em_energy_surplus"
unit_of_measurement: "kW"
state: >-
{{ (states('sensor.em_pv_power_corrected') | float(0) - states('sensor.em_home_load_corrected') | float(0)) | round(2) }}
- name: "em_pw_max_charge"
unit_of_measurement: "kW"
state: >-
{{ states('input_number.pw_max_charge') | float(4.6) }}
- name: "em_pw_current_charge"
unit_of_measurement: "kW"
state: >-
{{ (states('sensor.em_powerwall_charge_corrected') | float(0)) | abs | round(2) }}
- name: "em_available_for_heatpump"
unit_of_measurement: "kW"
state: >-
{% set surplus = states('sensor.em_energy_surplus') | float(0) %}
{% set pw_curr = states('sensor.em_pw_current_charge') | float(0) %}
{% set threshold = 0.02 %}
{% if surplus > 0 %}
{% set used = pw_curr if pw_curr > threshold else 0 %}
{{ [surplus - used, 0] | max | round(2) }}
{% else %}
0
{% endif %}
attributes:
note: "Surplus minus current battery charge (threshold 0.02 kW)"
- name: "em_target_flow_temp"
unit_of_measurement: "°C"
state: >-
{% set min_t = states('input_number.em_flow_temp_min') | float(0) %}
{% set max_t = states('input_number.em_flow_temp_max') | float(0) %}
{% set avail = states('sensor.em_available_for_heatpump') | float(0) %}
{% set max_power = 6 %}
{% set ratio = (avail / max_power) | float(0) %}
{% set ratio = [ratio, 0] | max %}
{% set ratio = [ratio, 1] | min %}
{% set target = min_t + (max_t - min_t) * ratio %}
{{ target | round(1) }}
- name: "em_current_flow_temp"
unit_of_measurement: "°C"
state: "{{ states('sensor.boiler_current_flow_temperature') | float(0) }}"
- name: "em_dhw_boiler_temp"
unit_of_measurement: "°C"
state: "{{ states('sensor.boiler_heat_carrier_forward_tc1') | float(0) }}"
- name: "em_dhw_charge_state"
state: >-
{{ 'on' if is_state('input_boolean.em_dhw_charging', 'on') else 'off' }}
- binary_sensor:
- name: "wp_laufzeit_startbedingung"
unique_id: wp_laufzeit_startbedingung
device_class: running
state: >-
{% set enabled = is_state('input_boolean.energy_manager_enabled','on') %}
{% set temp_ok = is_state('input_boolean.energy_manager_temp_ok','on') %}
{% set safe_off = is_state('input_boolean.em_safe_mode','off') %}
{% set avail = states('sensor.em_available_for_heatpump') | float(0) %}
{% set start_th = states('input_number.em_avail_start') | float(0) %}
{% set target_t = states('sensor.em_target_flow_temp') | float(0) %}
{% set current_t = states('sensor.em_current_flow_temp') | float(0) %}
{% set hysteresis = 0.2 %}
{{ enabled and temp_ok and safe_off and (avail > start_th) and (target_t > current_t + hysteresis) }}
{# Optional zusätzlich: or is_state('input_boolean.em_dhw_charging','on') #}
attributes:
em_enabled: "{{ states('input_boolean.energy_manager_enabled') }}"
em_temp_ok: "{{ states('input_boolean.energy_manager_temp_ok') }}"
em_safe_mode: "{{ states('input_boolean.em_safe_mode') }}"
avail_for_hp_kW: "{{ states('sensor.em_available_for_heatpump') }}"
avail_start_kW: "{{ states('input_number.em_avail_start') }}"
target_flow_temp_C: "{{ states('sensor.em_target_flow_temp') }}"
current_flow_temp_C: "{{ states('sensor.em_current_flow_temp') }}"
would_set_to_C: >-
{% set step = states('input_number.em_flow_temp_step_k') | float(0.5) %}
{% set max_t = states('input_number.em_flow_temp_max') | float(50) %}
{% set cand = (states('sensor.em_current_flow_temp') | float(0)) + step %}
{% set tgt = states('sensor.em_target_flow_temp') | float(0) %}
{% set capped = [cand, tgt, max_t] | min %}
{{ capped | round(1) }}
reason: >-
{# Variablen in Attribut-Template erneut setzen, da separat gerendert #}
{% set enabled = is_state('input_boolean.energy_manager_enabled','on') %}
{% set temp_ok = is_state('input_boolean.energy_manager_temp_ok','on') %}
{% set safe_off = is_state('input_boolean.em_safe_mode','off') %}
{% set avail = states('sensor.em_available_for_heatpump') | float(0) %}
{% set start_th = states('input_number.em_avail_start') | float(0) %}
{% set target_t = states('sensor.em_target_flow_temp') | float(0) %}
{% set current_t = states('sensor.em_current_flow_temp') | float(0) %}
{% set hysteresis = 0.2 %}
{% set reasons = [] %}
{% if not enabled %}{% set reasons = reasons + ['disabled'] %}{% endif %}
{% if not temp_ok %}{% set reasons = reasons + ['temp_not_ok'] %}{% endif %}
{% if not safe_off %}{% set reasons = reasons + ['safe_mode_on'] %}{% endif %}
{% if not (avail > start_th) %}{% set reasons = reasons + ['avail_below_start'] %}{% endif %}
{% if not (target_t > current_t + hysteresis) %}{% set reasons = reasons + ['target_not_above_current'] %}{% endif %}
{{ 'all_conditions_met' if reasons|length == 0 else reasons|join(',') }}
availability: >-
{{
(states('sensor.em_available_for_heatpump') not in ['unknown','unavailable','']) and
(states('sensor.em_target_flow_temp') not in ['unknown','unavailable','']) and
(states('sensor.em_current_flow_temp') not in ['unknown','unavailable',''])
}}
# --- Automationen (alle in einem Block) ---
automation:
- alias: "EM Temp OK Status aktualisieren"
description: "Setzt input_boolean.energy_manager_temp_ok basierend auf Temperatur mit Debounce 60s"
mode: restart
trigger:
- platform: state
entity_id: sensor.boiler_air_inlet_temperature_tl2
condition: []
action:
- choose:
- conditions:
- condition: template
value_template: >-
{% set temp = states('sensor.boiler_air_inlet_temperature_tl2') %}
{% set start = states('input_number.energy_manager_temp_start') %}
{{ temp not in ['unavailable', 'unknown', ''] and
start not in ['unavailable', 'unknown', ''] and
(temp | float(0)) < (start | float(0)) }}
sequence:
- delay: "00:01:00"
- condition: template
value_template: >-
{% set temp = states('sensor.boiler_air_inlet_temperature_tl2') %}
{% set start = states('input_number.energy_manager_temp_start') %}
{{ temp not in ['unavailable', 'unknown', ''] and
start not in ['unavailable', 'unknown', ''] and
(temp | float(0)) < (start | float(0)) }}
- service: input_boolean.turn_on
target:
entity_id: input_boolean.energy_manager_temp_ok
- conditions:
- condition: template
value_template: >-
{% set temp = states('sensor.boiler_air_inlet_temperature_tl2') %}
{% set stop = states('input_number.energy_manager_temp_stop') %}
{{ temp not in ['unavailable', 'unknown', ''] and
stop not in ['unavailable', 'unknown', ''] and
(temp | float(0)) > (stop | float(0)) }}
sequence:
- delay: "00:01:00"
- condition: template
value_template: >-
{% set temp = states('sensor.boiler_air_inlet_temperature_tl2') %}
{% set stop = states('input_number.energy_manager_temp_stop') %}
{{ temp not in ['unavailable', 'unknown', ''] and
stop not in ['unavailable', 'unknown', ''] and
(temp | float(0)) > (stop | float(0)) }}
- service: input_boolean.turn_off
target:
entity_id: input_boolean.energy_manager_temp_ok
# Automation: EM: Vorlauftemperatur regeln (nur Erhöhungen, kein Absenken)
- alias: "EM: Vorlauftemperatur regeln"
description: "Erhöht Selected flow temperature stufenlos mit Ramping (nur Anheben, kein aktives Absenken)"
trigger:
- platform: state
entity_id:
- sensor.em_available_for_heatpump
- sensor.em_current_flow_temp
- input_boolean.energy_manager_enabled
- input_boolean.energy_manager_temp_ok
condition:
- condition: state
entity_id: input_boolean.energy_manager_enabled
state: 'on'
- condition: state
entity_id: input_boolean.energy_manager_temp_ok
state: 'on'
- condition: state
entity_id: input_boolean.em_safe_mode
state: 'off'
# Hysterese-Bedingung: nur wenn verfügbar > Start-Schwelle
- condition: template
value_template: >-
{{ (states('sensor.em_available_for_heatpump') | float(0)) > (states('input_number.em_avail_start') | float(0)) }}
action:
- variables:
target_temp_raw: "{{ states('sensor.em_target_flow_temp') | float(0) }}"
current_temp: "{{ states('sensor.em_current_flow_temp') | float(0) }}"
step: "{{ states('input_number.em_flow_temp_step_k') | float(0) }}"
max_t: "{{ states('input_number.em_flow_temp_max') | float(0) }}"
last_change: "{{ state_attr('number.boiler_selected_flow_temperature', 'last_changed') }}"
time_since_change_min: >-
{% if last_change is none %}
9999
{% else %}
((as_timestamp(now()) - as_timestamp(last_change)) / 60)
{% endif %}
- choose:
- conditions:
# Nur erhöhen, wenn Ziel > Ist
- condition: template
value_template: >-
{{ target_temp_raw > current_temp }}
sequence:
- variables:
# Kandidat ist Ist + Schritt, aber nicht über Ziel
candidate_temp: >-
{% set cand = current_temp + step %}
{% if cand > target_temp_raw %}
{{ target_temp_raw }}
{% else %}
{{ cand }}
{% endif %}
# Kappe auf maximalen erlaubten Wert
new_temp_capped: >-
{{ [ (candidate_temp | float), (max_t | float) ] | min | round(1) }}
- service: number.set_value
data:
entity_id: number.boiler_selected_flow_temperature
value: "{{ new_temp_capped }}"
- service: system_log.write
data:
message: "EM: Vorlaufregelung erhöht von {{ current_temp }}°C auf {{ new_temp_capped }}°C (Ziel {{ target_temp_raw }}°C, Max {{ max_t }}°C)"
level: info
default: []
- alias: "EM: DHW Ladung steuern"
description: "Steuert DHW Charging basierend auf PV Überschuss und Boiler Temperatur, mit Hysterese"
trigger:
- platform: state
entity_id:
- sensor.em_available_for_heatpump
- sensor.em_dhw_boiler_temp
- input_boolean.energy_manager_enabled
- input_boolean.energy_manager_temp_ok
- input_boolean.em_dhw_charging
condition:
- condition: state
entity_id: input_boolean.energy_manager_enabled
state: 'on'
- condition: state
entity_id: input_boolean.energy_manager_temp_ok
state: 'on'
- condition: state
entity_id: input_boolean.em_safe_mode
state: 'off'
action:
- variables:
pv_avail: "{{ states('sensor.em_available_for_heatpump') | float(0) }}"
boiler_temp: "{{ states('sensor.boiler_heat_carrier_forward_tc1') | float(0) }}"
dhw_charging: "{{ is_state('input_boolean.em_dhw_charging', 'on') }}"
max_temp: "{{ states('input_number.em_dhw_max_temp') | float(0) }}"
min_temp: "{{ states('input_number.em_dhw_min_temp') | float(0) }}"
min_duration: "{{ states('input_number.em_dhw_charge_min_duration') | int }}"
last_on: "{{ state_attr('input_boolean.em_dhw_charging', 'last_changed') }}"
time_on_min: >-
{% if last_on is none %}
9999
{% else %}
((as_timestamp(now()) - as_timestamp(last_on)) / 60)
{% endif %}
start_thresh: "{{ states('input_number.em_avail_start') | float(0) }}"
stop_thresh: "{{ states('input_number.em_avail_stop') | float(0) }}"
- choose:
# Start DHW Charging wenn PV Überschuss über Startschwelle und Boiler Temp < max_temp
- conditions:
- condition: template
value_template: >-
{{ pv_avail > start_thresh }}
- condition: template
value_template: >-
{{ boiler_temp < max_temp }}
- condition: template
value_template: >-
{{ not dhw_charging or (dhw_charging and time_on_min > min_duration) }}
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.em_dhw_charging
- service: switch.turn_on
target:
entity_id: switch.boiler_dhw_one_time_charging
- service: system_log.write
data:
message: "EM: DHW Charging gestartet (Boiler {{ boiler_temp }}°C, PV Überschuss {{ pv_avail }} kW)"
level: info
# Stop DHW Charging wenn PV unter Stop-Schwelle oder Boiler Temp >= max_temp und Mindestladezeit erfüllt
- conditions:
- condition: template
value_template: >-
{{ (boiler_temp >= max_temp) or (pv_avail < stop_thresh) }}
- condition: template
value_template: >-
{{ dhw_charging and time_on_min > min_duration }}
sequence:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.em_dhw_charging
- service: switch.turn_off
target:
entity_id: switch.boiler_dhw_one_time_charging
- service: system_log.write
data:
message: "EM: DHW Charging gestoppt (Boiler {{ boiler_temp }}°C, PV Überschuss {{ pv_avail }} kW)"
level: info
- alias: "EM: Aux-Heater Steuerung"
description: "Blockiert Aux-Heater wenn nicht erlaubt oder Boiler Temp ausreichend, mit Hysterese"
trigger:
- platform: state
entity_id:
- input_boolean.em_allow_aux
- sensor.boiler_heat_carrier_forward_tc1
- input_boolean.em_dhw_charging
- sensor.em_available_for_heatpump
condition:
- condition: state
entity_id: input_boolean.em_safe_mode
state: 'off'
action:
- variables:
allow_aux: "{{ is_state('input_boolean.em_allow_aux', 'on') }}"
boiler_temp: "{{ states('sensor.boiler_heat_carrier_forward_tc1') | float(0) }}"
min_temp: "{{ states('input_number.em_dhw_min_temp') | float(0) }}"
dhw_charging: "{{ is_state('input_boolean.em_dhw_charging', 'on') }}"
pv_avail: "{{ states('sensor.em_available_for_heatpump') | float(0) }}"
start_thresh: "{{ states('input_number.em_avail_start') | float(0) }}"
stop_thresh: "{{ states('input_number.em_avail_stop') | float(0) }}"
- choose:
- conditions:
- condition: template
value_template: >-
{{ not allow_aux and boiler_temp > min_temp and dhw_charging and pv_avail > stop_thresh }}
sequence:
- service: switch.turn_off
target:
entity_id: switch.boiler_aux_heater_only
- service: system_log.write
data:
message: "EM: Aux-Heater deaktiviert wegen Energiemanager"
level: info
- conditions:
- condition: template
value_template: "{{ allow_aux }}"
sequence:
- service: switch.turn_on
target:
entity_id: switch.boiler_aux_heater_only
- service: system_log.write
data:
message: "EM: Aux-Heater erlaubt durch Energiemanager"
level: info
- alias: "EM: Force smoothed zero on startup"
description: "Setzt beim HA-Start kurzzeitig das Force-Zero-Flag, bis Rohsensoren initialisiert sind"
mode: single
trigger:
- platform: homeassistant
event: start
action:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.energy_manager_force_zero
- wait_for_trigger:
- platform: template
value_template: >-
{% set s1 = states('sensor.my_home_solar_energie') %}
{% set s2 = states('sensor.my_home_last_leistung') %}
{% set s3 = states('sensor.my_home_batterie_leistung') %}
{{ [s1, s2, s3] | select('match', '^(?!unknown$|^unavailable$|^$).+') | list | count > 0 }}
timeout: "00:00:20"
- delay: "00:00:02"
- service: homeassistant.update_entity
target:
entity_id:
- sensor.em_pv_power_smoothed
- sensor.em_home_load_smoothed
- sensor.em_powerwall_battery_power_smoothed
- sensor.em_pv_power_corrected
- sensor.em_home_load_corrected
- sensor.em_powerwall_charge_corrected
- sensor.em_energy_surplus
- sensor.em_available_for_heatpump
- sensor.em_pw_current_charge
- sensor.em_pw_max_charge
- sensor.em_target_flow_temp
- sensor.em_current_flow_temp
- sensor.boiler_heat_carrier_forward_tc1
- delay: "00:00:01"
- service: input_boolean.turn_off
target:
entity_id: input_boolean.energy_manager_force_zero
- alias: "EM: Aux-Heater max Laufzeit"
description: "Schaltet den Aux-Heater automatisch nach definierter Zeit wieder aus (Failsafe)"
mode: restart
trigger:
- platform: state
entity_id: switch.boiler_aux_heater_only
to: "on"
for: "00:20:00"
condition: []
action:
- service: switch.turn_off
target:
entity_id: switch.boiler_aux_heater_only
- service: system_log.write
data:
message: "EM: Aux-Heater wurde nach 20 Minuten automatisch abgeschaltet (Failsafe)"
level: warning
- alias: "EM: Aux-Heater aus bei keinem PV-Überschuss"
description: "Schaltet den Aux-Heater aus, wenn kein ausreichender PV-Überschuss vorhanden ist"
mode: restart
trigger:
- platform: numeric_state
entity_id: sensor.em_available_for_heatpump
below: 0.3
for: "00:02:00"
condition: []
action:
- condition: state
entity_id: switch.boiler_aux_heater_only
state: "on"
- service: switch.turn_off
target:
entity_id: switch.boiler_aux_heater_only
- service: system_log.write
data:
message: "EM: Aux-Heater deaktiviert wegen fehlendem PV-Überschuss"
level: warning
- alias: "EM: Moduswechsel ausführen"
mode: single
trigger:
- platform: state
entity_id: input_select.energy_manager_mode
action:
- service: script.em_set_mode
- alias: "EM: HARD Restore Modus nach Neustart"
mode: single
trigger:
- platform: homeassistant
event: start
action:
# ⏱ wirklich warten bis alles stabil ist
- delay: "00:00:20"
# 🧠 Modus hart lesen (mit Fallback!)
- variables:
mode: "{{ states('input_select.energy_manager_mode') | default('Winter') }}"
# 🧯 Debug zur Kontrolle
- service: system_log.write
data:
message: "EM START: gespeicherter Modus = {{ mode }}"
level: warning
# 🔥 HARTE WIEDERHERSTELLUNG
- choose:
- conditions:
- condition: template
value_template: "{{ mode == 'Sommer' }}"
sequence:
- service: script.em_set_mode
- conditions:
- condition: template
value_template: "{{ mode == 'Winter' }}"
sequence:
- service: script.em_set_mode
Da ich das hier schon einige Male gelesen habe.
Warmwassertemperaturen von 60 und mehr sind nicht zu empfehlen. Zum einen belasten Sie die Wärmepumpe bzw. den Kompressor unnötig und zum anderen fördern sie die Verkalkung des Wärmetauschers.
@Thomassh Danke für den Hinweis ![]()
Grundsätzlich hast du recht – dauerhaft hohe Temperaturen sind für Effizienz und Lebensdauer nicht optimal.
Bei mir geht es aber eher um PV-Überschussnutzung, d. h. ich fahre höhere Temperaturen nur gezielt, wenn genug Solarleistung da ist. Im Normalbetrieb bleibt die Temperatur deutlich niedriger.
wie groß ist den dein WW Speicher ?
Ich würde, statt den Wärmetauscher durch Kalkausfall zu riskieren bei der normalen WW Bereitung, die bei einem entsprechend gedämmten Speicher und der passenden Temperatur ja sowieso nur einmal pro Tag bzw. sogar nur alle 2 Tage stattfindet, den Zeitpunkt so legen das PV Überschuss vorhanden ist und dann mit dem Heizstab unterstützen/arbeiten.
Die in den kleinen Wassermengen eines Speichers einlagerbare Energie ist sowieso begrenzt.
PV mit einer WP einspeichern funktioniert eigentlich nur gut mit einer FBH da dort der Beton mit entsprechend großer Masse als Speicher funktioniert.
Dazu reicht es aus die VL Temperatur zu erhöhen.
Weitere Eingriffe in das System halte ich bei einer richtig eingestellten FBH und WP sogar für kontraproduktiv.
Das Zusammenspiel von Außentemperatur geführter WP und der Heizkurve klappt normalerweise sehr gut und bewirkt im Winter Laufzeiten von Monaten. Das ist für die WP gesünder als ständige Eingriffe und häufige Starts.
Das funktioniert bei mir tatsächlich.
Nur jetzt speise ich Tag für Tag durchschnittlich 10 kWh ein, obwohl ich den Akku voll habe und den 290 Liter Speicher auf 65° aufgeheizt habe. Das letztere geht automatisch: Fonius meldet Überschuss von 5000W über eine halbe Stunde, dann kriegt die WP per Bus die Information, dass die PV genügend produziert und geht automatisch in die erhöhte Warmwasserbereitung. Wenn ich jetzt noch den Heizstab mit 3kW dazu schalten könnte, wäre ich ja einen entscheidenden Schritt weiter.
Ich würde auf keinen Fall die WP benutzen um den Speicher auf 65 Grad zu erhitzen.
Das belastet zum einen die WP sehr stark und fördert zum anderen die Verkalkung des Wärmetauschers.
Wenn du deinen Speicher um 20 Grad erhitzt kannst du ungefähr
6,74 kw/h speichern.
Die Bosch sollte eigentlich einen Menüpunkt bieten um nur mit Heizstab aufzuheizen, wie der genau heißt kann ich dir nicht sagen weil ich keine habe.
Hej Thomassh, Danke für den Hinweis, bisher habe ich nichts gefunden, aber jetzt suche ich weiter!
Die Frage ist ja auch ob du dadurch überhaupt sparst.
Wenn einmal am Tag WW gemacht wird und zwar während sowieso Überschuss da ist der für die WP genutzt wird ,macht es keinen Sinn den WW Speicher zu überhöhen da sowieso nur PV Energie benutzt wird.
Die einzige Konstellation in der es Sinn machen würde wäre wenn nachgeheizt werden müsste während kein PV Überschuss da ist und durch das überhöhen dies verhindert würde.
Schau da mal Evt hilft das ja
Hallo @Reluca
erst einmal vielen Dank für deine Arbeit und dass wir sie nutzen dürfen. Ich konnte mich jetzt recht gut durch die Materie arbeiten, entsprechend auch die Variablen an meine Umgebung anpassen - aber was ich überhaupt nicht verstehe ist folgendes aus deinem Dashboard:
type: custom:button-card
entity: sensor.wp_laufzeit_bei_uberschuss_heute_neu
name: WP Laufzeit bei Überschuss heute
icon: mdi:clock-time-five-outline
show_icon: false
show_name: true
show_state: false
show_label: true
label: |
[[[
// raw = Stunden im Dezimalformat (z.B. 1.75 = 1h45min)
const raw = states[‘sensor.wp_laufzeit_bei_uberschuss_heute_neu’]?.state;
const val = parseFloat(raw);
if (isNaN(val)) return “–”;
// Umrechnung: Dezimalstunden → Sekunden
const totalSeconds = Math.round(val * 3600);
const hours = Math.floor(totalSeconds / 3600);
const minutes = Math.floor((totalSeconds % 3600) / 60);
const seconds = totalSeconds % 60;
// Format hh:mm:ss
return `${hours.toString().padStart(2,'0')}:` +
`${minutes.toString().padStart(2,'0')}:` +
`${seconds.toString().padStart(2,'0')}`;
]]]
styles:
card:
- font-size: 18px
- text-align: center
- padding: 8px
label:
- font-weight: bold
- color: var(–primary-text-color)
Hier bekomme ich immer die Meldung die Entity sensor.wp_laufzeit_bei_uberschuss_heute_neu ist unbekannt. In deiner energy_manager.yaml finde ich aber auch nichts, was ich irgendwie in Zusammenhang bringen könnte. Ich verstehe daher nicht so recht, woher du die Daten für diese Berechnung erhältst. Vielleicht kannst du mir da eine kleine Hilfestellung geben?
Beste Grüße
Marcus
Hallo Marcus,
entschuldige bitte meine etwas verspätete Antwort.
Die von dir angesprochene Entity
sensor.wp_laufzeit_bei_uberschuss_heute_neu
kommt nicht aus dem Dashboard und ist auch kein Bestandteil der energy_manager.yaml.
Sie wird stattdessen als eigener Sensor per YAML definiert, genauer gesagt als history_stats‑Sensor.
Ich habe diesen Sensor in einer separaten Datei angelegt:
/homeassistant/integration_sensors/laufzeit_wp.yaml
mit folgendem Inhalt:
- platform: history_stats
name: "WP Laufzeit bei Überschuss heute neu"
unique_id: wp_laufzeit_bei_uberschuss_heute_neu
entity_id: binary_sensor.wp_laufzeit_startbedingung
state: "on"
type: time
start: "{{ now().replace(hour=0, minute=0, second=0, microsecond=0) }}"
end: "{{ now() }}"
- platform: history_stats
name: "WP Laufzeit bei Überschuss Monat"
unique_id: wp_laufzeit_bei_uberschuss_monat
entity_id: binary_sensor.wp_laufzeit_startbedingung
state: "on"
type: time
start: "{{ now().replace(day=1, hour=0, minute=0, second=0, microsecond=0) }}"
end: "{{ now() }}"
Dieser history_stats‑Sensor wertet die Laufzeit eines Binary‑Sensors aus (in meinem Fall
binary_sensor.wp_laufzeit_startbedingung) und berechnet daraus, wie lange dieser heute bzw. im aktuellen Monat auf on stand.
Das Ergebnis ist eine Laufzeit in Dezimalstunden (z. B. 1.75 = 1 h 45 min).
Damit Home Assistant diesen Sensor überhaupt kennt, habe ich die Datei zusätzlich in der configuration.yaml eingebunden:
# Allgemeine Sensoren (verschiedene Integrationen)
sensor: !include_dir_merge_list integration_sensors/
Erst dadurch wird sensor.wp_laufzeit_bei_uberschuss_heute_neu erzeugt und kann anschließend im Dashboard (z. B. in der button-card) verwendet werden.
Die JavaScript‑Logik in der Card dient dann nur noch dazu, den Stundenwert optisch als hh:mm:ss darzustellen.
Ich hoffe, damit ist klarer, woher die Daten kommen und warum die Entity bei dir als „unbekannt“ auftaucht, wenn dieser Sensor nicht angelegt ist.
Viele Grüße
Rene
Vielen lieben Dank für die ausführliche Antwort. Da werde ich mich dann auch einmal reinwuchsen ![]()