Skip to content

Commit bef358c

Browse files
committed
Add support for WPE-I (brine/water, no DHW)
address #363 Panel verified against a WPE-I 08 HK 230 Premium: the WPE-I speaks the same WPM protocol as the WPL models (temperatures, setpoints, heat curves, energy counters, VERDICHTER_STARTS and efficiency all match the panel exactly), so the variant builds on wxx_base.yaml and WPE_I joins the existing property groups. Properties it shares with other models live in common sections instead of being repeated: - WAERMEERTRAG_2WE_HEIZ_SUM_KWH/MWH move to the common block, they are served by every family - WP_WASSERVOLUMENSTROM, REGELABWEICHUNG and LAUFZEIT_VD_HEIZEN move to a shared WPE_I/WPL_17 section - LAUFZEIT_NHZ1, NHZ2 and NHZ1_2 move to a shared WPE_I/WPL_17/WPL_23 section What is specific to the WPE-I: - no integrated DHW, so it includes wxx_base.yaml rather than wpl_base.yaml - 0x02e2 is the water volume flow as on the WPL17, not the WPL13 WAERMEPUMPEN_STATUS word (raw 280/285 = 28.0/28.5 l/min next to VOLUMENSTROM = 27.7 l/min). The WPE-I reports its own status on 0x4eda (bit 4 = passive cooling active, verified by switching the pump to standby and watching the valve follow) and the plant status arrives as a broadcast towards the room unit, so both words are exposed as raw sensors and only the verified bits become binary sensors. - runtime counters, panel exact: LAUFZEIT_VD_HEIZEN 6327 h and LAUFZEIT_NHZ1/NHZ2/NHZ1_2 0/0/4 h. LAUFZEIT_VD_KUEHLEN answers 0x8000 because the WPE-I only cools passively, so it is not exposed. - MINTEMP/MAXTEMP (HK2) and REGELABWEICHUNG are clamped to their valid range with ignore_out_of_range, so the marker words the WPM sends for "AUS" (0x9000) and "not available" (0x8000) leave the entity unavailable instead of publishing an impossible value Unlike WPL_13 builds, WPE_I does not shift the Betriebsart raw value by 8 bits: the WPE-I sends PROGRAMMSCHALTER (0x4f1b) as a low byte (raw 0x02 = Programm, verified while the panel showed PROGRAMMBETRIEB).
1 parent 4c1a851 commit bef358c

4 files changed

Lines changed: 145 additions & 9 deletions

File tree

components/wp_core/mapper.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Mapper::Mapper() {
8585
#if defined(TTF_07_C)
8686
betriebsartMap = {{0x0000, "Notbetrieb"}, {0x0100, "Bereitschaft"}, {0x0200, "Programm"},
8787
{0x0300, "Komfort"}, {0x0400, "Eco"}, {0x0500, "Warmwasser"}};
88-
#elif defined(WPL_13) || defined(WPL_17) || defined(WPL_23)
88+
#elif defined(WPL_13) || defined(WPL_17) || defined(WPL_23) || defined(WPE_I)
8989
betriebsartMap = {{0x00, "Notbetrieb"}, {0x01, "Bereitschaft"}, {0x02, "Programm"},
9090
{0x03, "Komfort"}, {0x04, "Eco"}, {0x05, "Warmwasser"}};
9191
#else

components/wp_core/property.h

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,8 @@ struct Property : public oe32trta::detail::Property {
9595
PROPERTY(WAERMEERTRAG_HEIZ_TAG_KWH, 0x092f, Type::et_double_val);
9696
PROPERTY(WAERMEERTRAG_HEIZ_SUM_KWH, 0x0930);
9797
PROPERTY(WAERMEERTRAG_HEIZ_SUM_MWH, 0x0931, Type::et_double_val);
98+
PROPERTY(WAERMEERTRAG_2WE_HEIZ_SUM_KWH, 0x0928);
99+
PROPERTY(WAERMEERTRAG_2WE_HEIZ_SUM_MWH, 0x0929, Type::et_double_val);
98100

99101
// =======================================================================
100102
// 2. THZ & TTF SHARED PROPERTIES
@@ -173,8 +175,6 @@ struct Property : public oe32trta::detail::Property {
173175
PROPERTY(DRUCK_NIEDERDRUCK, 0x07a7, Type::et_cent_val);
174176
PROPERTY(WAERMEERTRAG_2WE_WW_SUM_KWH, 0x0924);
175177
PROPERTY(WAERMEERTRAG_2WE_WW_SUM_MWH, 0x0925, Type::et_double_val);
176-
PROPERTY(WAERMEERTRAG_2WE_HEIZ_SUM_KWH, 0x0928);
177-
PROPERTY(WAERMEERTRAG_2WE_HEIZ_SUM_MWH, 0x0929, Type::et_double_val);
178178
PROPERTY(HEIZ_KUEHL_LEISTUNG, 0xc0ee, Type::et_cent_val);
179179
PROPERTY(ABLUFTFEUCHTE, 0xc0ef);
180180
PROPERTY(VERDICHTER_STARTS, 0xc0f4);
@@ -271,7 +271,7 @@ struct Property : public oe32trta::detail::Property {
271271
// =======================================================================
272272
// 7. WPL VARIANTS
273273
// =======================================================================
274-
#if defined(WPL_13) || defined(WPL_17) || defined(WPL_23)
274+
#if defined(WPL_13) || defined(WPL_17) || defined(WPL_23) || defined(WPE_I)
275275
PROPERTY(RUECKLAUFTEMP, 0x0016, Type::et_dec_val);
276276
PROPERTY(MAXRUECKLAUFTEMP, 0x0028, Type::et_dec_val);
277277
PROPERTY(PUFFERISTTEMPERATUR, 0x0078, Type::et_dec_val);
@@ -341,16 +341,28 @@ struct Property : public oe32trta::detail::Property {
341341
PROPERTY(FROSTSCHUTZ, 0xfe07, Type::et_dec_val);
342342
#endif
343343

344-
#if defined(WPL_13) || defined(WPL_17)
344+
#if defined(WPL_13) || defined(WPL_17) || defined(WPE_I)
345345
PROPERTY(VERDICHTER_STARTS_K, 0x4ef0);
346346
PROPERTY(VERDICHTER_STARTS, 0x4ef1);
347347
PROPERTY(ZEITINTERVALL, 0x4f4d, Type::et_dec_val);
348348
#endif
349349

350-
#if defined(WPL_17) || defined(WPL_23)
350+
#if defined(WPE_I) || defined(WPL_17)
351+
// 0x02e2 carries the water volume flow on these models, unlike the WPL13
352+
// where the same index is the WAERMEPUMPEN_STATUS word (on the WPE-I it was
353+
// observed as raw 280/285 = 28.0/28.5 l/min next to VOLUMENSTROM 0x4f47)
354+
PROPERTY(WP_WASSERVOLUMENSTROM, 0x02e2, Type::et_dec_val);
355+
PROPERTY(REGELABWEICHUNG, 0x033d, Type::et_dec_val);
356+
PROPERTY(LAUFZEIT_VD_HEIZEN, 0x4efb);
357+
#endif
358+
359+
#if defined(WPE_I) || defined(WPL_17) || defined(WPL_23)
351360
PROPERTY(LAUFZEIT_NHZ1, 0x0259);
352361
PROPERTY(LAUFZEIT_NHZ2, 0x025a);
353362
PROPERTY(LAUFZEIT_NHZ1_2, 0x0805);
363+
#endif
364+
365+
#if defined(WPL_17) || defined(WPL_23)
354366
PROPERTY(STARTS_ABTAUEN, 0x0806);
355367
PROPERTY(ZEIT_ABTAUEN, 0x0807);
356368
#endif
@@ -359,16 +371,22 @@ struct Property : public oe32trta::detail::Property {
359371
PROPERTY(WAERMEPUMPEN_STATUS, 0x02e2);
360372
#endif
361373

374+
#if defined(WPE_I)
375+
// the WPE-I's Waermepumpen-Status word (broadcast by Kessel, 0x8000 while
376+
// in standby). Panel verified bits: 4 = passive cooling active, two of
377+
// {2, 13} = Kuehlbetrieb mode / Netzversorgung Inverter.
378+
PROPERTY(WAERMEPUMPEN_STATUS, 0x4eda);
379+
PROPERTY(EVU_SPERRE_AKTIV, 0x0074);
380+
#endif
381+
362382
#if defined(WPL_17)
363383
PROPERTY(MAXIMALE_VORLAUFTEMP_WW, 0x0181, Type::et_dec_val);
364-
PROPERTY(WP_WASSERVOLUMENSTROM, 0x02e2, Type::et_dec_val);
365384
PROPERTY(BIVALENZTEMPERATUR_WW, 0x01ad, Type::et_dec_val);
366385
PROPERTY(EINSATZGRENZE_HZG, 0x01ae, Type::et_dec_val);
367386
PROPERTY(EINSATZGRENZE_WW, 0x01af, Type::et_dec_val);
368387
PROPERTY(AUSSENTEMPERATUR_EINST, 0x01bf, Type::et_dec_val);
369388
PROPERTY(FESTWERTBETRIEB, 0x01c0, Type::et_dec_val);
370389
PROPERTY(WW_LERNFUNKTION, 0x027e);
371-
PROPERTY(REGELABWEICHUNG, 0x033d, Type::et_dec_val);
372390
PROPERTY(GRENZE_KUEHLEN, 0x03dc, Type::et_dec_val);
373391
PROPERTY(VORLAUFANTEIL_HEIZKREIS, 0x049d);
374392
PROPERTY(SENSORABGLEICH_VORLAUF_WP, 0x0658, Type::et_dec_val);
@@ -422,7 +440,6 @@ struct Property : public oe32trta::detail::Property {
422440
PROPERTY(INBETRIEBNAHME_NOTBETRIEB, 0x4ef5);
423441
PROPERTY(WW_SOLLTEMPERATUR, 0x4ef9, Type::et_dec_val);
424442
PROPERTY(EINGESCHALTETE_STUFEN, 0x4efa);
425-
PROPERTY(LAUFZEIT_VD_HEIZEN, 0x4efb);
426443
PROPERTY(LAUFZEIT_VD_KUEHLEN, 0x4efc);
427444
PROPERTY(LAUFZEIT_VD_WW, 0x4efd);
428445
PROPERTY(KUEHLART, 0x4f05);

esp32-standalone.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ packages:
130130
- "yaml/thz504.yaml"
131131
# - "yaml/thz5_5_eco.yaml"
132132
# - "yaml/ttf07.yaml"
133+
# - "yaml/wpe-i.yaml"
133134
# - "yaml/wpl13.yaml"
134135
# - "yaml/wpl17.yaml"
135136
# - "yaml/wpl23.yaml"

yaml/wpe-i.yaml

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
#########################################
2+
# #
3+
# ESPHome #
4+
# #
5+
#########################################
6+
# Stiebel Eltron WPE-I ... H(K) (brine/water, no integrated DHW).
7+
# Panel-verified on a WPE-I 08 HK 230 Premium. Shares the WPL13 property
8+
# set except: no Warmwasser energy counters, adds runtime counters, and
9+
# 0x02e2 is WP_WASSERVOLUMENSTROM (as on WPL17), NOT the WPL13 status
10+
# word — the WPL13 status-bit binaries are omitted until the WPE-I's
11+
# real status property is identified.
12+
esphome:
13+
platformio_options:
14+
build_flags:
15+
- "-DWPE_I"
16+
on_boot:
17+
- priority: -50
18+
then:
19+
- lambda: |-
20+
// Wärmepumpen-Status word 0x4eda: only panel-verified bits are decoded.
21+
// The raw word is exposed as a sensor so the remaining bits can be
22+
// identified from recorded history when the pump changes state.
23+
CallbackHandler::instance().addCallback(std::make_pair(CanNode::Kessel,Property::kWAERMEPUMPEN_STATUS),[](const SimpleVariant& value){
24+
const auto word{static_cast<std::uint16_t>(value)};
25+
id(WP_STATUS_RAW).publish_state(word);
26+
if (word != 0x8000U) { // 0x8000 = standby (Bereitschaft)
27+
const std::bitset<16U> status_bits{word};
28+
id(PASSIVKUEHLUNG_AKTIV).publish_state(status_bits.test(4U));
29+
}
30+
});
31+
// Anlagen-Status word 0x4ecd is broadcast by the pump towards the
32+
// room unit and arrives carrying HK2's sender id.
33+
CallbackHandler::instance().addCallback(std::make_pair(CanNode::HK2,Property::kBETRIEBS_STATUS),[](const SimpleVariant& value){
34+
const auto word{static_cast<std::uint16_t>(value)};
35+
const std::bitset<16U> status_bits{word};
36+
id(ANLAGE_STATUS_RAW).publish_state(word);
37+
id(HEIZKREISPUMPE_2).publish_state(status_bits.test(2U));
38+
});
39+
// EVU-Sperre-aktiv flag 0x0074, broadcast periodically (Manager id)
40+
CallbackHandler::instance().addCallback(std::make_pair(CanNode::Manager,Property::kEVU_SPERRE_AKTIV),[](const SimpleVariant& value){
41+
id(EVU_SPERRE_AKTIV).publish_state(static_cast<std::uint16_t>(value) == 1U);
42+
});
43+
- priority: -100
44+
then:
45+
- lambda: |-
46+
queueRequest(CanNode::Kessel, Property::kWAERMEPUMPEN_STATUS);
47+
48+
#########################################
49+
# #
50+
# Status raw words (diagnostic) #
51+
# #
52+
#########################################
53+
sensor:
54+
- platform: template
55+
name: WP_STATUS_RAW
56+
id: WP_STATUS_RAW
57+
icon: "mdi:numeric"
58+
accuracy_decimals: 0
59+
update_interval: never
60+
- platform: template
61+
name: ANLAGE_STATUS_RAW
62+
id: ANLAGE_STATUS_RAW
63+
icon: "mdi:numeric"
64+
accuracy_decimals: 0
65+
update_interval: never
66+
67+
# The WPM answers a setting that is switched off with a marker word instead
68+
# of a value (0x9000 shows as "AUS" on the panel, 0x8000 while a value is not
69+
# available), which decodes to an impossible temperature. Clamping to the
70+
# valid range with ignore_out_of_range drops those readings, so the entity
71+
# stays unavailable instead of publishing e.g. -2867.2 °C.
72+
- id: !extend MINTEMP
73+
filters:
74+
- clamp: { min_value: -60.0, max_value: 100.0, ignore_out_of_range: true }
75+
- id: !extend MAXTEMP
76+
filters:
77+
- clamp: { min_value: -60.0, max_value: 100.0, ignore_out_of_range: true }
78+
- id: !extend REGELABWEICHUNG
79+
filters:
80+
- clamp: { min_value: -50.0, max_value: 50.0, ignore_out_of_range: true }
81+
82+
#########################################
83+
# #
84+
# Global variables #
85+
# #
86+
#########################################
87+
globals:
88+
- id: heat_pump_variant
89+
type: std::string
90+
initial_value: '"WPE-I"'
91+
92+
#########################################
93+
# #
94+
# Packages #
95+
# #
96+
#########################################
97+
98+
packages:
99+
WXX_BASE: !include { file: wxx_base.yaml }
100+
101+
# 0x02e2 fluctuates with the circulation flow (raw 280/285 = 28.0/28.5 l/min,
102+
# consistent with VOLUMENSTROM 0x4f47) — same meaning as on the WPL17
103+
WP_WASSERVOLUMENSTROM: !include { file: templates/wp_generic.yaml, vars: { property: "WP_WASSERVOLUMENSTROM", unit: "l/min", icon: "mdi:water", accuracy_decimals: "1", target: "Heizmodul" }}
104+
105+
# runtime counters (panel: Info -> Wärmepumpe -> Laufzeit)
106+
LAUFZEIT_VD_HEIZEN: !include { file: templates/wp_generic.yaml, vars: { property: "LAUFZEIT_VD_HEIZEN", unit: "h", target: "Heizmodul" }}
107+
LAUFZEIT_NHZ1: !include { file: templates/wp_generic.yaml, vars: { property: "LAUFZEIT_NHZ1", unit: "h", target: "Heizmodul" }}
108+
LAUFZEIT_NHZ2: !include { file: templates/wp_generic.yaml, vars: { property: "LAUFZEIT_NHZ2", unit: "h", target: "Heizmodul" }}
109+
LAUFZEIT_NHZ1_2: !include { file: templates/wp_generic.yaml, vars: { property: "LAUFZEIT_NHZ1_2", unit: "h", target: "Heizmodul" }}
110+
111+
# status binaries decoded from the WPE-I's own status words (panel-verified bits only)
112+
PASSIVKUEHLUNG_AKTIV: !include { file: templates/wp_binary.yaml, vars: { name: "PASSIVKUEHLUNG_AKTIV" }}
113+
HEIZKREISPUMPE_2: !include { file: templates/wp_binary.yaml, vars: { name: "HEIZKREISPUMPE_2" }}
114+
EVU_SPERRE_AKTIV: !include { file: templates/wp_binary.yaml, vars: { name: "EVU_SPERRE_AKTIV" }}
115+
116+
# further panel-verified values
117+
REGELABWEICHUNG: !include { file: templates/wp_generic.yaml, vars: { property: "REGELABWEICHUNG", unit: "K", accuracy_decimals: "1", target: "Manager" }}
118+
WAERMEERTRAG_2WE_HEIZ_SUMME_MWH: !include { file: templates/wp_generic_combined.yaml, vars: { sensor_name: "WAERMEERTRAG_2WE_HEIZ_SUMME_MWH" , scaled_property: "WAERMEERTRAG_2WE_HEIZ_SUM_KWH" , property: "WAERMEERTRAG_2WE_HEIZ_SUM_MWH" , unit: "MWh", accuracy_decimals: "3", icon: "mdi:fire" , target: "Heizmodul", state_class: "total_increasing" }}

0 commit comments

Comments
 (0)