@ showup: Thanks for your great work…
Thank you for the nice script.
Does anybody now if I can I read energy and power metrics for each output separately?
What differentiates MYPV integration started - #54 by showup from this HA integration?
… your work!
I don’t know if you got a solution on how to read energy and power for each output. The easyest way is to install one power/energy meter on each output. Simple solutions are better than try and error. As sleepymaxx wrote…(and yes i recommend to read the whole article top to bottom).
I recommend to use this HA integration, I’m maintaining it regularly: GitHub - dneprojects/mypv: Home Assistant custom integration for myPV devices
Hallo zusammen, ich musste meinen Home assistant komplett umbauen, dabe habe ich aus der gesamten sache von oben einen Bluprint erstellt welche nun beide Automatisierungen ersetzen kann. mfg
blueprint:
name: ELWA Pro - Ultimate (Watt-Logik, Nachtsperre & Flex-Schwelle)
description: "Stabile 0.9-Logik. Nutzt negative Watt-Werte (Einspeisung) und besitzt eine Sonnenstands-Sperre."
domain: automation
input:
smart_meter_export:
name: Smart-Meter Export (Watt)
description: "Sensor für den Netz-Zähler. Einspeisung MUSS negativ sein (z.B. -500W)."
default: sensor.smart_meter_summe_der_aktiven_momentanleistung
selector:
entity:
domain: sensor
battery_discharge:
name: Batterie Entladung (kW)
default: sensor.master_battery_discharge
selector:
entity:
domain: sensor
elwa_consumption:
name: ELWA Aktueller Verbrauch (Watt)
default: sensor.elwa_e_2_mypv_stromverbrauch_aktuell
selector:
entity:
domain: sensor
elwa_temp_top:
name: Temperatur oben
default: sensor.elwa_e_2_trinkwasser_temperatur_oben
selector:
entity:
domain: sensor
elwa_temp_bottom:
name: Temperatur unten
default: sensor.elwa_e_2_trinkwasser_temperatur_unten
selector:
entity:
domain: sensor
timer_helper:
name: Timer-Helfer für Pause
default: timer.elwa_pause
selector:
entity:
domain: timer
temp_max:
name: Max. Temperatur oben
default: 60
selector:
number:
min: 53
max: 67
step: 1
unit_of_measurement: "°C"
temp_freigabe_oben:
name: Freigabe oben
default: 53
selector:
number:
min: 45
max: 60
step: 1
unit_of_measurement: "°C"
temp_freigabe_unten:
name: Freigabe unten
default: 40
selector:
number:
min: 30
max: 45
step: 1
unit_of_measurement: "°C"
export_threshold:
name: Einspeise-Schwelle (Watt)
description: "Ab wie viel Watt Einspeisung soll die ELWA starten? (Positiver Wert, z.B. 4)"
default: 10
selector:
number:
min: 5
max: 45
step: 1
unit_of_measurement: "W"
pause_time:
name: Pausenzeit (min)
default: 60
selector:
number:
min: 30
max: 180
step: 1
unit_of_measurement: "min"
mode: single
triggers:
- trigger: state
entity_id: !input smart_meter_export
- trigger: state
entity_id: !input battery_discharge
- trigger: state
entity_id: !input elwa_temp_top
# Marker 1: Nur bei Tag ausführen (wie in der Original-Automation)
conditions:
- condition: sun
after: sunrise
before: sunset
actions:
- variables:
timer_ent: !input timer_helper
top_ent: !input elwa_temp_top
bot_ent: !input elwa_temp_bottom
export_ent: !input smart_meter_export
elwa_ent: !input elwa_consumption
# Schwellenwerte
threshold: !input export_threshold
t_freigabe_o: !input temp_freigabe_oben
t_freigabe_u: !input temp_freigabe_unten
t_max: !input temp_max
p_time: !input pause_time
temp_oben: "{{ states(top_ent) | float(0) }}"
temp_unten: "{{ states(bot_ent) | float(0) }}"
is_paused: "{{ not is_state(timer_ent, 'idle') }}"
needs_heat: "{{ temp_oben < (t_freigabe_o | float) or temp_unten < (t_freigabe_u | float) }}"
# 1. PAUSE ABBRECHEN bei Bedarf
- if:
- condition: template
value_template: "{{ is_paused and needs_heat }}"
then:
- action: timer.finish
target:
entity_id: !input timer_helper
# 2. HAUPT-ENTSCHEIDUNG
- choose:
# FALL A: Max-Temperatur erreicht
- conditions:
- condition: template
value_template: "{{ temp_oben >= (t_max | float) }}"
sequence:
- action: rest_command.update_elwa_power
data:
power: 0
- if:
- condition: template
value_template: "{{ is_state(timer_ent, 'idle') }}"
then:
- action: timer.start
target:
entity_id: !input timer_helper
data:
duration: "{{ (p_time | int * 60) }}"
# FALL B: Regelbetrieb
- conditions:
- condition: template
value_template: "{{ is_state(timer_ent, 'idle') or needs_heat }}"
sequence:
- if:
- condition: numeric_state
entity_id: !input battery_discharge
below: 0.16
# Dynamische Prüfung auf negativen Wert (Einspeisung)
- condition: template
value_template: "{{ (states(export_ent) | float(0)) < (threshold | float * -1) }}"
then:
- action: rest_command.update_elwa_power
data:
power: >-
{% set exp = states(export_ent) | float(0) %}
{% set cons = states(elwa_ent) | float(0) %}
{# exp ist negativ, daher * -1 um positive Watt zu erhalten. Dann Schwelle abziehen. #}
{{ (((exp * -1 - (threshold | float)) + cons) * 0.93) | round(0) }}
else:
- action: rest_command.update_elwa_power
data:
power: 0
default:
- action: rest_command.update_elwa_power
data:
power: 0
Again i redesingnt the whole steering - biggest rules! 1: not Battery drain 2: no Grid use 3. maximum availabe Engery for the Elwa.
!! Change All ip´s to your Needs !!
!! Change All names(of your Sensors) to your Needs !!
you have to add the following Helper in HA:
Timer Helper: timer.elwa_pause
you have to use the rest integration (Get it throug HACS)
You have to add this to your config.yaml (the used Sensors/input commands)
modbus: !include modbus.yaml
You have to add this to your modbus.yaml (the used Sensors/input commands)
# Config modbus MYPV-Meter
- name: elwa_hub
type: tcp
host: 192.168.2.60
port: 502
retry_on_empty: true
delay: 2
timeout: 5
message_wait_milliseconds: 200
sensors:
- name: "Elwa E 2 MyPV Stromverbrauch aktuell"
unique_id: "elwa_e2_modbus_power"
address: 1000
slave: 1
unit_of_measurement: "W" # Modbus liefert meist Watt
device_class: power
state_class: measurement
scan_interval: 3
- name: "Elwa E 2 Trinkwasser Temperatur unten"
unique_id: "elwa_e2_modbus_temp_unten"
address: 1001
slave: 1
unit_of_measurement: "°C"
device_class: temperature
scale: 0.1 # Modbus liefert Ganzzahlen (z.B. 255 für 25,5°C)
precision: 1
scan_interval: 30
- name: "Elwa E 2 Trinkwasser Temperatur Oben"
unique_id: "elwa_e2_modbus_temp_oben"
address: 1030
slave: 1
unit_of_measurement: "°C"
device_class: temperature
scale: 0.1
precision: 1
scan_interval: 30
number:
- name: "Elwa E 2 Max Power Setting"
unique_id: "elwa_e2_maxpwr_limit"
address: 1017 # Register für Max Power (siehe MyPV Handbuch)
slave: 1
min_value: 0
max_value: 3500
step: 100
unit_of_measurement: "W"
And you have to Add this Blueprint:
blueprint:
name: ELWA Pro - Hybrid Ultimate
description: "Dynamische Volatilitätsdämpfung, Temperatur-Freigabe oben/unten, robuste Sanitierung und stabile Pause-Logik. Grundregeln: 1) keine Batterieentladung 2) kein Netzbezug 3) maximale Überschussnutzung bei Warmwasserbedarf 4) adaptive Reserve bei Wolkenwechsel 5) stabile Logik."
domain: automation
input:
smart_meter_export:
name: Smart-Meter Export (Watt)
description: "Einspeisung MUSS negativ sein (z.B. -500W)."
default: sensor.smart_meter_summe_der_aktiven_momentanleistung
selector:
entity:
domain: sensor
volatility_sensor:
name: Volatilitäts-Sensor (Statistics)
description: "Sensor für die Standardabweichung des Netzes."
default: sensor.smart_meter_netz_volatilitaet_1min
selector:
entity:
domain: sensor
battery_discharge:
name: Batterie Entladung (kW)
description: "Sensor in kW (z.B. 0.05 für 50W)."
default: sensor.master_battery_discharge
selector:
entity:
domain: sensor
battery_charge:
name: Batterie Ladung (kW)
description: "Sensor für die aktuelle Ladeleistung in kW."
default: sensor.master_battery_charge
selector:
entity:
domain: sensor
elwa_consumption:
name: ELWA Aktueller Verbrauch (Watt)
default: sensor.elwa_e2_modbus_power
selector:
entity:
domain: sensor
elwa_temp_top:
name: Temperatur oben
default: sensor.elwa_e2_modbus_temp_oben
selector:
entity:
domain: sensor
elwa_temp_bottom:
name: Temperatur unten
default: sensor.elwa_e2_modbus_temp_unten
selector:
entity:
domain: sensor
timer_helper:
name: Timer-Helfer für Pause
default: timer.elwa_pause
selector:
entity:
domain: timer
temp_max:
name: Max. Temperatur oben
default: 60
selector:
number:
min: 53
max: 67
unit_of_measurement: "°C"
temp_freigabe_oben:
name: Freigabe Temperatur oben
description: "Unter diesem Wert wird die Pause ignoriert (oben)."
default: 53
selector:
number:
min: 45
max: 60
unit_of_measurement: "°C"
temp_freigabe_unten:
name: Freigabe Temperatur unten
description: "Unter diesem Wert wird die Pause ignoriert (unten)."
default: 34
selector:
number:
min: 30
max: 40
unit_of_measurement: "°C"
reserve_min:
name: Minimale Reserve (Watt)
description: "Sicherheitsabstand bei Kaiserwetter."
default: 40
selector:
number:
min: 0
max: 50
reserve_max:
name: Maximale Reserve (Watt)
description: "Sicherheitsabstand bei Wolken-Chaos."
default: 400
selector:
number:
min: 50
max: 2000
battery_discharge_limit:
name: Max. Batterie-Entladeschwelle (Watt)
description: "Ab wie viel Watt Entladung soll die ELWA stoppen? (Bereich 10-40W). Hinweis: battery_discharge ist in kW."
default: 32
selector:
number:
min: 10
max: 40
unit_of_measurement: "W"
pause_time:
name: Pausenzeit (min)
default: 60
selector:
number:
min: 30
max: 180
mode: restart
#mode: queued
#max: 2
triggers:
- trigger: state
entity_id: !input smart_meter_export
- trigger: state
entity_id: !input battery_discharge
- trigger: state
entity_id: !input elwa_temp_top
- trigger: state
entity_id: !input elwa_temp_bottom
conditions:
- condition: sun
after: sunrise
before: sunset
actions:
- variables:
# Entity-Referenzen (YAML-Variablen, NICHT in Jinja)
export_entity: !input smart_meter_export
batt_entity: !input battery_discharge
batt_charge_entity: !input battery_charge
vola_entity: !input volatility_sensor
elwa_entity: !input elwa_consumption
temp_o_entity: !input elwa_temp_top
temp_u_entity: !input elwa_temp_bottom
timer_entity: !input timer_helper
hub_name: "elwa_hub" # Name aus deiner modbus configuration.yaml
# Rohwerte sicher auslesen (Jinja mit entity-Variablen)
export_val: "{{ states(export_entity) | float(0) }}"
batt_val: "{{ states(batt_entity) | float(0) }}"
vola_val: "{{ states(vola_entity) | float(0) }}"
elwa_cons: "{{ states(elwa_entity) | float(0) }}"
temp_o: "{{ states(temp_o_entity) | float(0) }}"
temp_u: "{{ states(temp_u_entity) | float(0) }}"
batt_charge_val: "{{ states(batt_charge_entity) | float(0) * 1000 }}"
# Parameter
p_time: !input pause_time
batt_limit_w: !input battery_discharge_limit
batt_limit_kw: "{{ (batt_limit_w | float) / 1000 }}"
t_max: !input temp_max
t_freig_o: !input temp_freigabe_oben
t_freig_u: !input temp_freigabe_unten
x_res: !input reserve_max
y_res: !input reserve_min
# Volatilitätsfaktor (angepasst, 0..1)
vola_factor: "{{ [ (vola_val | float(0)) / 800, 0.98 ] | min }}"
# Dynamische Reserve (skaliert zwischen y_res und x_res)
dynamic_reserve: "{{ (y_res | float) + (vola_factor * ((x_res | float) - (y_res | float))) }}"
# Status-Flags (robust)
is_too_hot: "{{ (temp_o | float) >= (t_max | float) }}"
is_grid_draw: "{{ (export_val | float) > 0 }}"
is_batt_drain: "{{ (batt_val | float) > (batt_limit_kw | float) }}"
is_paused: "{{ is_state(timer_entity, 'active') }}"
is_batt_charging: "{{ batt_charge_val > 10 }}"
# Bedarf an Wärme: untere Temp und, obere Temp
needs_heat: >-
{{ (temp_u | float) < (t_freig_u | float) or
(temp_o | float) < (t_freig_o | float) }}
# 1) Pause sofort beenden, wenn Wasser zu kalt ist (Priorität Warmwasser)
- if:
- condition: template
value_template: "{{ is_paused and needs_heat }}"
then:
- action: timer.finish
target:
entity_id: !input timer_helper
# 2) Entscheidungslogik (Hier wird Fall A und Fall B abgehandelt)
- choose:
# FALL A: Sofort-Stopp (Hitze, Netzbezug oder Batterie-Entladung)
- conditions:
- condition: template
value_template: "{{ is_too_hot or is_grid_draw or is_batt_drain or is_batt_charging}}"
sequence:
- action: modbus.write_register
data:
hub: "{{ hub_name }}"
address: 1000
slave: 1
value: 0
- if:
- condition: template
value_template: "{{ is_too_hot and not is_paused }}"
then:
- action: timer.start
target:
entity_id: !input timer_helper
data:
duration: "{{ (p_time | int) * 60 }}"
# FALL B: Regelbetrieb (Hier ist die neue "Option A" Logik integriert!)
- conditions:
- condition: template
value_template: >-
{{ (not is_grid_draw and not is_batt_drain and not is_batt_charging) and (not is_paused or needs_heat) }}
sequence:
- action: modbus.write_register
data:
hub: "{{ hub_name }}"
address: 1000
slave: 1
value: >-
{# 1. Echter Gesamt-Überschuss = Einspeisung (invertiert) + aktueller ELWA-Verbrauch #}
{% set total_available = (export_val * -1) + elwa_cons %}
{# 2. Abzug der Reserve & Sicherheitsfaktor #}
{% set raw_final = (total_available - dynamic_reserve) * 0.98 %}
{# 3. Ergebnis-Ausgabe #}
{% set final_power = (raw_final | float(0)) | round(0) | int %}
{{ [0, final_power] | max }}
default:
- action: modbus.write_register
data:
hub: "{{ hub_name }}"
address: 1000
slave: 1
value: 0
If you want you can add this to your DASHBOARD for debug/graphic control:
type: vertical-stack
cards:
- type: horizontal-stack
cards:
- type: gauge
entity: sensor.smart_meter_summe_der_aktiven_momentanleistung
name: Netz (Watt)
min: -5000
max: 5000
severity:
green: -5000
yellow: 0
red: 100
needle: true
- type: gauge
entity: sensor.elwa_e_2_mypv_stromverbrauch_aktuell
name: ELWA Ist
min: 0
max: 3500
severity:
green: 500
yellow: 2500
red: 3200
needle: true
unit: W
- type: gauge
entity: sensor.smart_meter_netz_volatilitaet_1min
min: 0
max: 100
needle: true
unit: "%"
severity:
green: 20
yellow: 40
red: 60
name: Lastwechsel
- type: history-graph
entities:
- entity: sensor.elwa_e_2_mypv_stromverbrauch_aktuell
hours_to_show: 1
refresh_interval: 10
- type: entities
title: Energie
entities:
- entity: timer.elwa_pause
name: Pausen-Timer (Sperre)
secondary_info: last-changed
- entity: sensor.elwa_e_2_mypv_stromverbrauch_aktuell
name: ELWA Leistung (W)
- entity: sensor.smart_meter_summe_der_aktiven_momentanleistung
name: Smart-Meter (W)
- entity: sensor.master_battery_discharge
name: Batterie Entladung (kW)
- entity: sensor.master_battery_charge
name: Batterie Ladung (kW)
- type: entities
title: Temperaturen
entities:
- entity: sensor.elwa_e_2_trinkwasser_temperatur_oben
name: Temperatur oben (°C)
- entity: sensor.elwa_e_2_trinkwasser_temperatur_unten
name: Temperatur unten (°C)
- type: custom:mushroom-template-card
primary: Entscheidungslogik
secondary: >
{% set smart =
states('sensor.smart_meter_summe_der_aktiven_momentanleistung') | float(0)
%} {% set batt_dis = states('sensor.master_battery_discharge') | float(0)
%} {% set batt_chg = states('sensor.master_battery_charge') | float(0) %}
{% set temp_top = states('sensor.elwa_e_2_trinkwasser_temperatur_oben') |
float(0) %} {% set temp_bot =
states('sensor.elwa_e_2_trinkwasser_temperatur_unten') | float(0) %} {%
set pv = (smart * -1) if smart < 0 else 0 %} {% set reserve = 100 %}
{% if temp_top >= 60 %}
Temperatur-Pause aktiv
{% elif batt_dis > 0.01 %}
Batterie-Schutz aktiv
{% elif smart > 0 %}
Netz-Schutz aktiv
{% elif pv <= (batt_chg * 1000 + reserve) %}
Kein echter PV-Überlauf
{% elif temp_top < 55 or temp_bot < 45 %}
✔ ELWA darf heizen
{% else %}
Bedingungen nicht erfüllt
{% endif %}
icon: mdi:shield-check
icon_color: >
{% set temp_top = states('sensor.elwa_e_2_trinkwasser_temperatur_oben') |
float(0) %} {% if temp_top >= 60 %}
amber
{% else %}
blue
{% endif %}
Afterwards config your Blueprint and have fun!
Looks like you are still fight about the Elwa ![]()
I move my system to Modbus TCP device respond is better and by far all the system works better
modbus:
- name: ELWA
type: tcp
host: 192.168.1.200
port: 502
delay: 2
timeout: 5
message_wait_milliseconds: 200
sensors:
- name: "ELWA_Power"
slave: 1
address: 1000
input_type: holding
unit_of_measurement: "W"
scan_interval: 10
- name: "ELWA_Temp"
slave: 1
address: 1001
input_type: holding
scale: 0.1
unit_of_measurement: "°C"
scan_interval: 10
- name: "ELWA_Target"
slave: 1
address: 1002
input_type: holding
scale: 0.1
unit_of_measurement: "°C"
scan_interval: 10
P.S. I try your blueprint above… Nice work.
nO figth … only interest … and NERDism … ![]()
how have you integrated the second Temperatrue … and why do you use it as a target temp?
How have you rewritten your Automation? – will try it also out —
Great idea! … modbus is way more practically ( only your timeout is a little much? )
Sorry for the delay…I was away for a few days. Well the target temp it only show where is the setup temp of the elwa. Nothing special. The automation is here:
alias: ElwaUpdate
description: ElwaUpdate
triggers:
- entity_id: sensor.vxxout
trigger: state
conditions:
- condition: numeric_state
entity_id: sensor.vxxout
above: 800
- condition: numeric_state
entity_id: sensor.elwaxx_temp
below: 55
- condition: template
value_template: >
{% set last_triggered = state_attr('automation.elwaupdate',
'last_triggered') %} {{ last_triggered is none or (now() -
last_triggered).total_seconds() > 60 }}
- condition: state
entity_id: input_boolean.elwaupdate_running
state: "off"
actions:
- target:
entity_id: input_boolean.elwaupdate_running
action: input_boolean.turn_on
- repeat:
sequence:
- data:
hub: ELWA
unit: 1
address: 1000
value: >
{% set vxx = states('sensor.vxxout') | float(0) %} {{ vxx if vxx
<= 3000 else 3000 }}
action: modbus.write_register
- delay: "00:00:05"
until:
- condition: template
value_template: "{{ states('sensor.vxxout') | float <= 800 }}"
- target:
entity_id: input_boolean.elwaupdate_running
action: input_boolean.turn_off
mode: queued
Sensor VXXOUT is my export sensor.
P.S. So long it works perfect and with 0 errors.
P.S.2 The time outs…I try a lot of changes…looks as it is now, is working correct.
P.S.3 The bootlean is only to check if it runs the automation…to avoid double runs…
input_boolean:
elwaupdate_running:
name: ElwaUpdate Running
initial: off
I have also this automation to run when thre is no solar power… night times or bad weather
alias: ELWA Start From 40 Until 60°C
description: Start ELWA when water temp is below 40°C and keep heating until 60°C
triggers:
- entity_id: sensor.vxxout
below: 1
trigger: numeric_state
- minutes: /5
trigger: time_pattern
conditions:
- condition: numeric_state
entity_id: sensor.vxxout
below: 1
- condition: numeric_state
entity_id: sensor.elwaxx_temp
below: 40
actions:
- repeat:
until:
- condition: numeric_state
entity_id: sensor.elwaxx_temp
above: 59.9
sequence:
- data:
hub: ELWA
unit: 1
address: 1000
value: 2000
action: modbus.write_register
- delay: "00:00:05"
mode: single
Thank you very Much!
After your great Interrupt i redesignt my last updated Blueprint and editet it!
Works Flawlessly
Geat IDEA!
Also editet my post from MARCH 8. 2026 - SO this is my (today
) latest functioning Version
PS - Time is always a rare Value … so take yours! ![]()
So here is one clean and nice Elwa setup.
What is doing?
When solar kick inn heat with surplus when no solar goes on Backup mode and heat with grid till set temp of the automation ( Temperatures can setup as you like inside the automation). I have test it and runs very nice on my system also on a system of a friend.
So here is step by step how.
-
Make a bootlean
-
Settings
-
Devices & Services
-
Helpers
-
Click Create Helper
-
Choose → Toggle (Input Boolean)
-
Name it:
ELWA Heating Active
Add this automations:
Automation 1
alias: ELWA Keepalive
description: Sends ELWA power every 7s (solar + backup, timeout-safe)
trigger:
- platform: time_pattern
seconds: "/7"
mode: restart
condition:
- condition: state
entity_id: input_boolean.elwa_heating_active
state: "on"
action:
- variables:
surplus: "{{ states('sensor.vxxout') | float(0) }}"
solar_min: 800
solar_cap: 2000
solar_factor: 0.9
solar_power: "{{ [surplus * solar_factor, solar_cap] | min | int }}"
- choose:
# SOLAR MODE
- conditions:
- condition: template
value_template: "{{ surplus >= solar_min }}"
sequence:
- service: modbus.write_register
data:
hub: ELWA
unit: 1
address: 1000
value: "{{ solar_power }}"
default:
# BACKUP MODE (NO SOLAR)
- service: modbus.write_register
data:
hub: ELWA
unit: 1
address: 1000
value: 2000
Automation 2
alias: ElwaUpdate
description: ELWA heating permission controller (solar + backup split)
trigger:
- platform: state
entity_id:
- sensor.YOUR EXPORT SENSOR
- sensor.elwa_temp
- platform: time_pattern
minutes: "/5"
mode: restart
action:
- variables:
temp: "{{ states('sensor.elwaxx_temp') | float(0) }}"
surplus: "{{ states('sensor.YOUR EXPORT SENSOR') | float(0) }}"
solar_min: 800
- choose:
# HARD STOP (safety)
- conditions:
- condition: template
value_template: "{{ temp >= 70 }}"
sequence:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.elwa_heating_active
# BACKUP MODE (NO SOLAR, COLD TANK)
- conditions:
- condition: template
value_template: "{{ temp < 40 and surplus < solar_min }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.elwa_heating_active
# SOLAR MODE (NORMAL OPERATION)
- conditions:
- condition: template
value_template: "{{ temp < 70 and surplus >= solar_min }}"
sequence:
- service: input_boolean.turn_on
target:
entity_id: input_boolean.elwa_heating_active
default:
- service: input_boolean.turn_off
target:
entity_id: input_boolean.elwa_heating_active
Please notice this working with MODBUS TCP setup.
Enjoy
