11# SET-TOP-Zuordnung
22
33Welches State-Topic liest ein Set-Kommando zurück? Diese Datei beantwortet das
4- für alle 32 Set-Kommandos und alle 90 State-Topics der Firmware 3.9 .0 und hält
5- fest, wo es kein Gegenstück gibt.
4+ für alle 32 Set-Kommandos und alle 92 State-Topics der Firmware 3.10 .0 und
5+ hält fest, wo es kein Gegenstück gibt.
66
77Wozu: Eine Steuerung, die schreibt, muss prüfen können, ob der Wert angekommen
88ist. Die Wärmepumpe quittiert nichts — sie klemmt Werte außerhalb ihres
@@ -12,13 +12,13 @@ einzige Nachweis ist das Rücklesen des zugehörigen State-Topics. Wo diese
1212Spalte leer bleibt, schreibt die Steuerung blind.
1313
1414* In English: which state topic reads a set command back? This file maps all 32
15- set commands and all 90 state topics of firmware 3.9 .0 against each other and
15+ set commands and all 92 state topics of firmware 3.10 .0 against each other and
1616records where no counterpart exists. The heat pump acknowledges nothing and
1717silently clamps out-of-range values, so reading the matching state topic back
1818is the only proof a write arrived — where that column is empty, a controller
1919writes blind. Tables are language-neutral; the notes are German.*
2020
21- ** Stand:** 2026-08-19, Firmware 3.9 .0. Quelle sind ausschließlich die beiden
21+ ** Stand:** 2026-08-19, Firmware 3.10 .0. Quelle sind ausschließlich die beiden
2222Tabellen im Code — ` setCommands[] ` in [ ` src/commands.cpp ` ] ( src/commands.cpp )
2323und ` stateTopics[] ` in [ ` src/decode.cpp ` ] ( src/decode.cpp ) . Die Tabellen unten
2424sind nicht von Hand gepflegt, sondern von
@@ -43,7 +43,7 @@ Byte 7).
4343Zwei Eigenschaften des Protokolls tragen die ganze Auswertung:
4444
4545* ** Kommando- und Antworttelegramm benutzen dieselben Byte-Positionen.** Alle
46- 28 gefundenen Paare liegen auf identischer Position — Byte 38 schreibt die
46+ 30 gefundenen Paare liegen auf identischer Position — Byte 38 schreibt die
4747 Heizanforderung und Byte 38 liest sie zurück, ohne eine einzige Ausnahme. Die
4848 Zuordnung ist damit nicht geraten, sondern abgelesen.
4949* ** Das Kommandotelegramm ist 110 Bytes lang** (` QUERYSIZE ` , Indizes 0–109),
@@ -53,9 +53,9 @@ Zwei Eigenschaften des Protokolls tragen die ganze Auswertung:
5353
5454Daraus ergibt sich die Zweiteilung des Telegramms: Bytes 4–106 tragen
5555Einstellungen und spiegeln das Kommandotelegramm, ab Byte 110 kommen
56- Ist-Zustände und Messwerte. Jedes der 28 Paare liegt unter Byte 110.
56+ Ist-Zustände und Messwerte. Jedes der 30 Paare liegt unter Byte 110.
5757
58- ## 1. Set-Kommandos mit Rückmeldung (28 von 32)
58+ ## 1. Set-Kommandos mit Rückmeldung (30 von 32)
5959
6060Die Spalte * Bits* zählt wie das Projekt: ** Bit 1 ist das höchstwertige Bit** ,
6161` ganz ` heißt, das Kommando belegt das volle Byte. * Art* sagt, ob das Topic
@@ -72,6 +72,8 @@ SET6 | `Z1CoolRequestTemperature` | 39 | ganz | TOP28 | `Z1_Cool_Request_Temp` |
7272SET9 | ` OperationMode ` | 6 | ganz | TOP4 | ` Operating_Mode_State ` | teilweise ³
7373SET10 | ` ForceDHW ` | 4 | 1+2 | TOP2 | ` Force_DHW_State ` | voll
7474SET11 | ` DHWTemp ` | 42 | ganz | TOP9 | ` DHW_Target_Temp ` | voll
75+ SET14 | ` WaterPump ` | 4 | 3+4 | TOP104 | ` Water_Pump_Mode ` | voll ⁵
76+ SET15 | ` WaterPumpSpeed ` | 45 | ganz | TOP103 | ` Pump_Duty_Max ` | voll ⁵
7577SET16 | ` HeatDelta ` | 84 | ganz | TOP23 | ` Heat_Delta ` | voll
7678SET17 | ` CoolDelta ` | 94 | ganz | TOP24 | ` Cool_Delta ` | voll
7779SET18 | ` DHWHeatDelta ` | 99 | ganz | TOP22 | ` DHW_Heat_Delta ` | voll
@@ -154,14 +156,52 @@ Als Regelgröße ist TOP101 `Heat_Cool_SW_State` zu nehmen.
154156SET26 wird in Schritten zu 30 Minuten geschrieben, TOP98 meldet Minuten zurück:
155157` TOP98 = SET26 × 30 ` . Ein Vergleich ohne diese Umrechnung schlägt fehl.
156158
157- ## 2. Set-Kommandos ohne Rückmeldung (4)
159+ ### ⁵ Die zwei Pumpen-Rückmeldungen (neu in 3.10.0)
160+
161+ TOP103 und TOP104 sind die Rückmeldungen zu SET15 und SET14. Beide
162+ Byte-Positionen sind am 2026-08-19 an Stufe 1 im Hexlog ausgemessen worden statt
163+ aus Unterlagen übernommen — Wert verstellt, Rohbyte beobachtet, zurückgestellt
164+ ([ ` test/byte_monitor.py ` ] ( test/byte_monitor.py ) ):
165+
166+ Kommando | geschrieben | Byte | Rohwert
167+ :--- | :--- | ---: | :---
168+ SET15 ` WaterPumpSpeed ` | 100 → 110 → 100 | 45 | ` 0x65 ` → ` 0x6F ` → ` 0x65 `
169+ SET14 ` WaterPump ` | 0 → 1 → 0 | 4, Bits 3+4 | ` b01 ` → ` b10 ` → ` b01 `
170+
171+ Zweite Kontrolle ganz ohne Schreibvorgang: Die beiden Stufen sind auf
172+ verschiedene Werte konfiguriert (100 und 125), und Byte 45 zeigte an Stufe 2
173+ entsprechend ` 0x7E ` .
174+
175+ ** TOP103 ist eine Duty-Grenze, keine Drehzahl.** Bei laufender Pumpe folgte
176+ TOP92 ` Pump_Duty ` der Grenze exakt:
177+
178+ Byte 45 als ` X−1 ` | TOP92 ` Pump_Duty ` | TOP65 ` Pump_Speed ` | TOP1 ` Pump_Flow `
179+ ---: | ---: | ---: | ---:
180+ 100 | ** 100** | 2300 1/min | 11,95 l/min
181+ 80 | ** 80** | 1500 1/min | 6,93 l/min
182+
183+ Die Pumpe läuft im Handbetrieb also genau bis zur konfigurierten Obergrenze und
184+ nicht darüber. Der Kommandoname ` WaterPumpSpeed ` führt in die Irre und bleibt
185+ nur deshalb stehen, weil die Kaskadensteuerung darauf schreibt; die Ist-Werte
186+ sind weiter TOP65 und TOP92, TOP103 ist die Grenze zu TOP92.
187+
188+ ** TOP104 meldet den wirksamen Zustand** , nicht den Wunsch: Beim Umschalten auf
189+ ` Fix ` lief die Pumpe tatsächlich an (TOP65, TOP1 und TOP92 zogen alle nach).
190+ Der dritte Zustand ` Air purge ` (` b11 ` ) ist ** nicht** gemessen — ihn herzustellen
191+ hieße, an einer intakten Anlage eine Entlüftungsroutine auszulösen. Er stützt
192+ sich auf ` ProtocolByteDecrypt.md ` , so wie der zweite Zustand von TOP102
193+ ` External_SW_State ` .
194+
195+ ## 2. Set-Kommandos ohne Rückmeldung (2)
158196
159197SET | Kommando | Byte | Bits | Lage
160198:--- | :--- | ---: | :--- | :---
161199SET12 | ` ForceDefrost ` | 8 | 7 | Byte 8 ist im Antworttelegramm unbelegt — kein Rücklesen möglich
162200SET13 | ` ForceSterilization ` | 8 | 6 | dito
163- SET14 | ` WaterPump ` | 4 | 3+4 | Antwortbyte am Gerät belegt (Auto und On) — ** Lücke, direkt schließbar** , Abschnitt 4
164- SET15 | ` WaterPumpSpeed ` | 45 | ganz | Antwortbyte am Gerät belegt — ** Lücke, direkt schließbar** , Abschnitt 4
201+
202+ Byte 8 trägt im Antworttelegramm nichts — für diese beiden ist keine
203+ Rückmeldung möglich, das ist keine Lücke im Code. Die früher hier gelisteten
204+ SET14 und SET15 haben seit 3.10.0 ihr Rücklese-Topic, siehe Fußnote ⁵.
165205
166206Für die beiden Force-Kommandos gibt es keinen Rückgabewert, wohl aber einen
167207** Wirkungsnachweis** : Läuft die angestoßene Routine, meldet das ein
@@ -253,93 +293,13 @@ Kommandoname `WaterPumpSpeed` führt hier in die Irre, siehe Abschnitt 4.
253293
254294## 4. Was sich schließen ließe
255295
256- Nach Aufwand und Risiko geordnet. Die ersten beiden sind je eine Zeile in
257- ` decode.cpp ` und am Gerät ausgemessen — sie ergänzen nur die Leseseite, am
258- Schreibpfad ändert sich nichts. Erst der dritte Punkt fasst eine laufende
259- Anlage an.
260-
261- ** 1. Rücklesen für SET15 — ` Pump_Duty_Max ` auf Byte 45 (eine Zeile in
262- ` decode.cpp ` ).**
263-
264- ``` c
265- {103, 45, "Pump_Duty_Max", getIntMinus1, nullptr, Duty},
266- ```
267-
268- Dazu `NUMBEROFTOPICS` um eins hoch; die Klartextliste `Duty` gibt es schon
269- (TOP92). Kein Eingriff in den Schreibpfad. Zusammen mit Punkt 2 sind es zwei
270- neue Zeilen und `NUMBEROFTOPICS` 92.
271-
272- **Byte 45 ist am Gerät gemessen, nicht aus der Referenz übernommen**
273- (2026-08-19, Rohbytes über den Hexlog mit
274- [`test/byte_monitor.py`](test/byte_monitor.py)). Zwei Kontrollen: der Vergleich
275- der beiden Stufen, die verschiedene Werte konfiguriert haben, und eine
276- Änderung an Stufe 1 in beide Richtungen.
277-
278- Messung | `set/WaterPumpSpeed` | Byte 45 roh | Byte 45 als `X−1` | Byte 95 als `X−128`
279- :--- | ---: | ---: | ---: | ---:
280- Stufe 1, Ausgangslage | 100 | `0x65` | **100** | 20
281- Stufe 2, Ausgangslage | 125 | `0x7E` | **125** | 20
282- Stufe 1, auf 110 gesetzt | 110 | `0x6F` | **110** | 20
283- Stufe 1, zurück auf 100 | 100 | `0x65` | **100** | 20
284-
285- Damit ist belegt: Byte 45 trägt den Wert, die Umrechnung ist `X−1`, und die
286- Flanke folgt dem Kommando in beide Richtungen — beim Umschalten stand sie im
287- selben Mitschnitt (ein Telegramm mit dem alten, die folgenden mit dem neuen
288- Wert). Byte 95 blieb über alle vier Messungen unverändert bei 20 und ist die
289- Heiz/Kühl-Umschalttemperatur TOP79.
290-
291- **Der Wert ist ein Duty, keine Drehzahl** — und auch das ist gemessen, nicht
292- geschlossen. Bei laufender Umwälzpumpe (Wärmepumpe stand, Pumpe über SET14 von
293- Hand eingeschaltet) folgte TOP92 `Pump_Duty` der Grenze aus Byte 45 unmittelbar:
294-
295- Byte 45 als `X−1` | TOP92 `Pump_Duty` | TOP65 `Pump_Speed` | TOP1 `Pump_Flow`
296- ---: | ---: | ---: | ---:
297- 100 | **100** | 2300 1/min | 11,95 l/min
298- 80 | **80** | 1500 1/min | 6,93 l/min
299-
300- Die Pumpe läuft im Handbetrieb also genau bis zur konfigurierten Obergrenze und
301- nicht darüber; Drehzahl und Durchfluss gehen mit. `Pump_Duty_Max` ist damit die
302- Grenze zu TOP92, nicht dessen Ersatz — die Ist-Werte stehen weiter in TOP65 und
303- TOP92. Der Kommandoname `WaterPumpSpeed` führt in die Irre; ob er auf
304- `MaxPumpDuty` geändert wird, ist eine Entscheidung über die Kompatibilität der
305- Topic-Namen und steht hier bewusst nicht offen, denn die Kaskadensteuerung
306- schreibt heute auf den alten Namen.
307-
308- Beim Nachschlagen in `ProtocolByteDecrypt.md`: Byte 45 trägt dort in der ersten
309- Spalte die Nummer TOP95 — das ist die Topic-Nummer des Original-Projekts, keine
310- Byte-Position.
311-
312- **2. Rücklesen für SET14 — `Water_Pump_Mode` auf Byte 4 (eine Zeile in
313- `decode.cpp`).**
314-
315- ```c
316- {104, 4, "Water_Pump_Mode", getBit3and4, nullptr, WaterPumpMode},
317- ```
318-
319- Dazu die Klartextliste ` WaterPumpMode[] = {"Auto", "On", "Air purge", nullptr} `
320- — sie deckt den Indexbereich ` −1..2 ` des Dekodierers vollständig ab, wie es
321- seit 3.9.0 für alle Listen gilt.
322-
323- Am 2026-08-19 an Stufe 1 gemessen, bei stehender Wärmepumpe:
324-
325- ` set/WaterPump ` | Byte 4 roh | Bits 3+4 | dekodiert | Pumpe
326- ---: | ---: | :--- | :--- | :---
327- 0 (Ausgangslage) | ` 0x55 ` | ` 01 ` | Auto | steht
328- 1 | ` 0x65 ` | ` 10 ` | ** On** | läuft, 2300 1/min
329- 0 (zurück) | ` 0x55 ` | ` 01 ` | Auto | steht
330-
331- Das Antwortbyte führt das Feld also, und der Wert ` 0x65 ` deckt sich mit der
332- Referenz („Water pump on=65"). Dass die Pumpe dabei tatsächlich anlief, ist
333- über TOP65, TOP92 und TOP1 belegt — das Bitfeld meldet keinen Wunsch, sondern
334- den wirksamen Zustand.
335-
336- ** Ungemessen bleibt ` Air purge ` ** (` b11 ` , laut Referenz ` 0x75 ` ). Diesen Zustand
337- zu erzeugen hieße, an einer intakten Anlage eine Entlüftungsroutine
338- auszulösen — dafür gibt es keinen Anlass. Der Eintrag in der Klartextliste
339- stützt sich auf die Referenz, so wie der zweite Zustand von TOP102
340- ` External_SW_State ` , der an dieser Anlage ebenfalls nicht herstellbar ist.
296+ ** Erledigt in 3.10.0:** die Rückmeldungen für SET14 und SET15 (TOP103
297+ ` Pump_Duty_Max ` , TOP104 ` Water_Pump_Mode ` ) — je eine Zeile in ` decode.cpp ` ,
298+ beide Byte-Positionen vorher am Gerät ausgemessen, Belege in Fußnote ⁵. Damit
299+ hat jedes Set-Kommando, für das es überhaupt ein Antwortbyte gibt, eine
300+ Rückmeldung. Offen bleibt:
341301
342- ** 3 . ` Heating_Mode ` / ` Cooling_Mode ` als Set-Kommando (Byte 28).**
302+ ** 1 . ` Heating_Mode ` / ` Cooling_Mode ` als Set-Kommando (Byte 28).**
343303Der größte praktische Gewinn. Heute muss beim Ausfall der Kaskadensteuerung
344304jemand ans Bedienterminal und von Direkt- auf Kurvenbetrieb umschalten — die
345305Kurvenwerte werden dafür schon vorgehalten (SET27–SET34). Mit einem Set-Kommando
@@ -349,14 +309,17 @@ mit TOP76/TOP81 bereits vorhanden, der Nachweis also gratis.
349309Vorher zu klären, in dieser Reihenfolge:
350310
351311* Nimmt die Wärmepumpe Byte 28 überhaupt an? Ein Schreibversuch mit
352- anschließendem Rücklesen von TOP76 beantwortet das in einem Durchgang.
312+ anschließendem Rücklesen von TOP76 beantwortet das in einem Durchgang —
313+ dasselbe Vorgehen wie bei den Pumpen-Bytes, nur dass hier ein * Kommando*
314+ erprobt wird und nicht bloß eine Zuordnung.
353315* Byte 28 trägt beide Modi (Heizen Bits 7+8, Kühlen Bits 5+6). Die Masken
354316 müssen bitgenau greifen, sonst schaltet ein Kühl-Kommando die Heizung mit um
355317 — genau der Fehler, den 3.1.0 beseitigt hat.
356- * Ein Fehlversuch verstellt eine laufende Anlage. Nur bei stehender Anlage
357- testen und den Ausgangswert vorher notieren.
318+ * ** Ein Fehlversuch verstellt eine laufende Anlage.** Anders als bei den
319+ Pumpen-Messungen wird hier die Betriebsart der Heizung angefasst: nur bei
320+ stehender Anlage testen und den Ausgangswert vorher notieren.
358321
359- ** 4 . Der Rest aus Abschnitt 3a** , wenn ein konkreter Bedarf auftaucht. Jeder
322+ ** 2 . Der Rest aus Abschnitt 3a** , wenn ein konkreter Bedarf auftaucht. Jeder
360323dieser Werte ist eine Zeile in ` setCommands[] ` ; die Arbeit steckt nicht im
361324Code, sondern im Ausmessen des zulässigen Bereichs. Wie das geht und warum es
362325nötig ist, steht in [ ` MQTT-Topics.md ` ] ( MQTT-Topics.md ) — von den 21 Werten, die
@@ -395,7 +358,7 @@ Suche gilt als abgeschlossen, siehe [`MQTT-Topics.md`](MQTT-Topics.md).
395358 Am Gerät belegt sind die Kurven-Kommandos SET27–SET34 (Rücklesen an beiden
396359 Anlagen, 2026-08-10/11), SET3, SET4 und SET9 im laufenden Betrieb
397360 (2026-08-15/16) sowie SET14 auf Byte 4 und SET15 auf Byte 45, beide mit
398- Änderung in beide Richtungen (2026-08-19, Abschnitt 4 ). Die übrigen Paare
361+ Änderung in beide Richtungen (2026-08-19, Fußnote ⁵ ). Die übrigen Paare
399362 stützen sich auf die identische
400363 Byte-Position, die bei jedem einzelnen der 28 Paare zutrifft. Wo Zweifel an
401364 einer Zuordnung bestehen, klärt sie [ ` test/byte_monitor.py ` ] ( test/byte_monitor.py )
0 commit comments