Bus Protokoll Körting/EBV Gamma 2B

#4256222
Lesenswert?

Hallo,

ich besitze als Heizungssteuerung eine Körting Gamma 2B und bin an dem 
Protokoll interessiert, das die über RS485 spricht. Ich habe mal meine 
bisherigen Informationen und Code-Zeilen in ein Github-Repository und 
Wiki unter https://github.com/bogeyman/gamma/wiki gesammelt.

Ich habe einen RaspberryPi und einen USB-RS485 Dongle geholt und mir 
eine ganze Weile aus Spaß die Bytes angeguckt, die da rausfallen. Nach 
ein wenig Programmieren und Probieren hab ich einen kleines Python 
Programm geschrieben, dass die Nachrichten etwas auswertet und loggt. 
Zurzeit bekomme ich Datum und Uhrzeit, drei Temperaturen und eine 
Handvoll noch nicht zugeordneter Werte von der Heizung. Die Brenn-Zeiten 
versuche ich gerade zu ermitteln. Ein kleines Munin Skipt zum grafischen 
Auswerten der Temperaturen ist auch dabei.

Wenn jemand eine Körting, EBV(, Hoval Toptronic?), Typen Gamma/KB 2B, 
23B, 233B, 223B, 2233B oder ähnliche hat und Lust hat zu helfen, wäre 
ich über ein Feedback sehr froh. Klar kann es gut sein, dass je nach 
EEPROM Version und Hersteller die sich ganz anders verhalten.

Richtig interessiert bin ich natürlich an Mitschnitten von der 
Raumstation RS-10 oder einer Steuersoftware, falls jemand dazu Zugriff 
hat. Dann wäre vielleicht ein schreibender Zugriff möglich zum Ändern 
der Warmwasser Temperatur, Party-Taste-Emulation, usw. Wenn jemand ein 
EEPROM Dump hat, vielleicht lässt sich damit auch was anfangen ;)

Da meine Heizung plus Heizungssteuerung nicht mehr die neuste ist, habe 
ich aber nicht vor, z.B. viel Geld für eine Raumstation auszugeben. Ich 
gucke regelmäßig nach gebrauchen, aber die liegen meist um den original 
Preis und das bin ich nicht bereit zu investieren. Aber am Protokoll zu 
basteln macht jedoch noch genug Spaß, ich kann Daten auswerten, und 
vielleicht ist ja noch mehr möglich.

Schöne Grüße,
Tim
Gast #4256907
Lesenswert?

Hi,
Ich habe mir die Raumstation 10 vor einiger Zeit gekauft. Wollte anfangs 
auch was eigenes basteln, hatte jedoch nicht die Zeit dazu und noch 
nicht das benötigte know-how .... Mein Plan war es mal den Datenbus 
abzuhören um per SMS oä die Heizung steuern zu können. Habe leider bis 
mitte November wenig Zeit mich mit weiteren Projekten zu beschäftigen 
:-/ Es wäre hilfreich wenn du eine Verdrahtungsskizze des Pi's mit noch 
evtl. benötigter Hardware online stellen würdest, dann könnte ich mir 
das schnell nachbauen und ein paar Sachen dumpen =)

mfG

NighFox
#4257671
Lesenswert?

Ich freu mich über jeden, der sich meldet. Ich hatte schon befürchtet, 
dass ich keinen mehr finde, der Interesse an der doch etwas betagten 
Hardware hat. Zeit ist immer ein knappes Gut, ist bei mir nicht anders. 
Um so schöner, dass Du eine Interesse (und Raumstation) hast. Ich bau in 
der nächsten Zeit mal die Mitmach-Seite im Wiki aus, damit jeder im 
besten Fall auch ohne Ahnung einfache Listen abarbeiten kann: Hardware 
bestellen, an Heizung anschließen, Pi einrichten. Ich schreib hier, wenn 
es was neues gibt.

Aus Interesse noch ein paar schnelle Fragen:
- Hast Du die Raumstation selber angeschlossen, oder das machen lassen? 
Anschluss über "Schraubklemmen" auf der Rückseite oder 5pol DIN Stecker?
- Wie ist die genaue Bezeichnung der Raumstation und Heizungsteuerung, 
am besten von der Bedienungsanleitung? Also Hersteller und Modellname
- Erfahrung Pi/Linux/Shell?

Schöne Grüße,
Tim
Gast #4259722
Lesenswert?

Hi,
Wenn ich alles aufgebaut habe sind ja schnell ein paar Szenarien 
durchgespielt und Protokollmitschnitte gezogen. Raspberrys hab ich noch 
genügend übrig ;) Ich brauche nur einen RS485 Adapter, kannst du mir da 
einen empfehlen, nicht dass ich mir schon die Uhr breche um den am 
Raspberry zum laufen zu bringen.
Zu deinen Fragen:
-Die RS habe ich selbst über die 4-polige Schraubklemme angeschlossen 
(leider über ein nicht-abgeschirmtes Kabel, ~6m, es sind bisher aber 
noch keine Probleme aufgetaucht)
-Die Heizungssteuerung ist die Gamma 2B, firmware version 1.09.
Von der "Raumstation Gamma RS-10" finde ich keine genauere Bezeichnung. 
Eventuell steht da mehr auf der Rückseite. Firmware 1.20
- Erfahrung mit Pi, Linux und Shell habe ich schon etwas.

mfG
#4271010
Lesenswert?

Hi,

leider ist der Adapter, den ich damals geholt habe nicht mehr verfügbar. 
Aber eigentlich sollte jeder gehen, den Du bei Amazon/ebay/usw mit "usb 
rs485 adapter" findest, solange der Treiber beim Pi dabei ist. Ich habe 
mir zu testen mal einen zur Reseve bei ebay für unter 5 Euro direkt aus 
China geordert, dauert halt nur drei Wochen bis das ankommmt. Conrad und 
Reichelt und Co hab ich mir noch nicht angeguckt.

Zur Verkabelung und Inbetirebnahme hab ich schon was geschrieben, aber 
noch nicht im Wiki.  Bis zum Wochenende komm ich dazu, denke ich.

Schöne Grüße,
Tim
Gast #4339441
Lesenswert?

Hallo Tim,

ich habe inzwischen meinen (neuen) RasPi mit USB-Dongle an die RS485 
Schnittstelle der Heizung angeschlossen. Ich habe eine Körting KB233 
(V 1.03) mit RS10 Raumstation.

Nach ein bischen ausprobieren kann ich die Brenner, Vorlauf, Außen- und 
Wassertemperatur auslesen. Ebenso das Datum.
Nachrichtentypen sind 2004, 0905 und 4002 wie auch z.T. von Dir 
dokumentiert.

Realisiert habe ich dies mit Node-RED unter Iobroker zur Einbindung in 
die Hausautomatisierung. Nachdem ich 20 Jahre nicht mehr programmiert 
hatte, war die Hürde Javascript. Hat mich dann 2-3 Tage gekostet, die 
Syntax zu verstehen. Danach geht die Datenauswertung als reines 
Info-System unter Node-RED mit wenigen Zeilen Code.

Wie kann ich ggfs. noch unterstützen? Interessant wäre das Verändern der 
Parameter.

Viele Grüße
Thomas
#4342849
Lesenswert?

Hallo Thomas,

das hört sich gut an. Iobroker kannte ich noch gar nicht, aber ich hab 
mal eine zeit lang Javascript beruflich entwickelt, das gucke ich mir 
mal an. Ich knabbere gerade ein wenig am Timing der Steuerung und der 
Raumstation (ich habe eine günstig überlassen bekommen). Da werden 
Bytes, die ich sende schon mal schnell ignoriert, wenn sie nicht 
punktgenau ankommen. Leider haben die USB-RS485 Dongles zum effizienten 
Übertragen vieler Daten über den USB Bus einen Timer btw. eine 
Minimum-Paketgröße bzw. ein bestimmbares Event-Byte, wann der Buffer vom 
Dongle an den Rechner übertragen wird. Und das macht erstmal mein Timing 
kaputt. Ich bin aber dran. (Zur Erklärung: bei 9600 baud mit Start und 
Stopbit kommt man auf knapp 1ms pro Byte, der Minimuntimer beim 
USB-Dongle ist auch 1ms. Das scheint auch grob die Toleranz bei der 
Raumstation und der Heizungssteuerung zu sein :/ )

Wenn mir die Simulation einer Heizungssteuerung gegen einer echten 
Raumstation oder die Simulation einer Raumstation gegen einer echten 
Heizungssteuerung gelingt, dann sind die Werte nur noch eine kleine 
Detektivarbeit.

Wen Du noch Erkenntnisse hast, die noch nicht unter 
https://github.com/bogeyman/gamma/wiki/Protokoll dokumentiert sind, sag 
mal Bescheid.

Magst Du mir Deinen Javascript mal geben, zum probieren? Im wiki steht 
auch eine email Adresse.

Wenn es einen Durchbruch gibt schreib ich auch nochmal hier.

Beste Grüße,
Tim
Gast #4349757
Lesenswert?

Hallo, mal eine ähnliche Frage. Ich hab ein gebrauchte KBM 233b gekauft. 
Da ist ein Code für die Fachmann Einstellung. Gibt es einen Weg den zu 
deaktivieren oder zurück zu setzen? Muss die Vorrang Einstellung ändern.

Grüße
Bernd
#4351873
Lesenswert?

Hallo Bernd,

wir haben leider keinen Fachmann Ebenen Code. Für mich wäre der 
interessant, da man dort die Busadresse ändern könnte. Aus Erfahrung, da 
ich auch gesucht habe:

- Du findest häufig Aussagen, wie "Ich kenne den auch nicht , aber 
probier doch mal (0000|1234|0123|0815|0615|9999) oder Kombinationen 
daraus". Ich habe was rumprobiert, aber nach dem fünfzehnten Code macht 
das keinen Spaß mehr.

- Dann gibt es Leute in Foren, die sagen "Ich hab den Code jetzt, geb 
den aber nur via PM weiter". Abgeschrieben, nichts passiert. Beiträge 
waren aber auch in der Regel einige Jahre alt...

- Frag einen entsprechenden "Fachmann". Werde ich bei meiner 
Heizungswartung jetzt machen. ;) Klar, doof, kostet Geld. Und kann sein, 
dass der sagt, dass er das entsprechend einstellt, aber Dir den Code 
nicht verrät. Weil man da Sachen einstellen kann, die die Hardware auch 
eher kaputt machen können...

Hoffe es ist wenigstens eine kleine Hilfe,
Tim
#5753415
Lesenswert?

Hallo zusammen,

mittlerweile habe ich verschiedene Daten von der Gamma und Ceta Serie 
bekommen (RS-485), die ich gerade in einen Parser einarbeite, damit die 
Leute möglichst viele Werte auslesen können. Bei der Theta Serie konnte 
mir noch niemand verraten, wie das Protokoll auf Hardware-Ebene 
funktioniert (T2B), so dass man das z.Z. gar nicht anschließen kann. Das 
Schreiben von Nachrichten ist noch nicht ganz gelöst, aber ich habe das 
Interesse noch nicht verloren ;) Da es aber darauf hinauslaufen wird, 
ein separates Programm oder Hardware neben der Heimautomatisierung 
nutzen zu müssen, tendiere ich gerade dazu die Werte z.B. via JSON zur 
Verfügung zu stellen, dann muss ich weniger Code pflegen. Updates sollen 
in den nächsten Wochen folgen...

Grüße, Tim
Gast #5753839
Lesenswert?

Tim G. schrieb:
> Bei der Theta Serie konnte
> mir noch niemand verraten, wie das Protokoll auf Hardware-Ebene
> funktioniert (T2B), so dass man das z.Z. gar nicht anschließen kann.

Das Signal wird über einen Trafo ausgekoppelt. Auf der Theta findest du 
hinter der Abdeckung oben rechst eine Debug-Schnittstelle. Dort liegt 
das Signal vom UART (µC) mit Logikpegel.
#5753852
Lesenswert?

Da geht was schrieb:
> Tim G. schrieb:
>> Bei der Theta Serie konnte
>> mir noch niemand verraten, wie das Protokoll auf Hardware-Ebene
>> funktioniert (T2B), so dass man das z.Z. gar nicht anschließen kann.
>
> Das Signal wird über einen Trafo ausgekoppelt. Auf der Theta findest du
> hinter der Abdeckung oben rechst eine Debug-Schnittstelle. Dort liegt
> das Signal vom UART (µC) mit Logikpegel.
Ich habe leider selber keinen Zugriff auf eine Theta. Hast Du noch ein 
paar mehr Infos dazu? Hat die debug Schnittstelle einen Stecker? Ist das 
RS485 in nicht Standard? Mir würde es darum gehen, dass andere genug 
Infos bekommen, um irgendwelche Adapter anschließen zu können. Wäre 
spannend...
Gast #5753860
Lesenswert?

Tim G. schrieb:
> Hat die debug Schnittstelle einen Stecker

Es handelt sich um eine Buchsenleiste. Mit einem RS232 Wandler kannst du 
dort die Kommunikation mit lesen.

Ich muss erst wühlen bevor ich an die alten Adapter komme. Auf der 
Platine kann man die Rx/Tx Leitungen gut nachverfolgen.
Gast #6221870
Lesenswert?

Hallo!
Ich habe eine Hoval RS-10 Raumsteuerung für einen Hoval TopTronic 23B 
Controller an einem Holz-Stückgut-Brenner Hoval Agrolyt 20.

Der Hoval Holzbrenner hat verschiedene Betriebsstatus, die er auf seinem 
kleinen Kesseldisplay (das ist nur ein LED-Display) kund tut.
1 = Anheizphase
2 = volle Leistung
...
5 = Ausbrand
6 = Kessel-Restwärmeausnutzung
7 = Temperatur im Kessel zu hoch
8 = Türe offen

Mich würde interessieren, ob man auf diese Betriebsmodi irgendwie über 
RS485 dran kommt. Auf der RS-10 habe ich die Modi nicht, daher ist 
fraglich, ob diese dem Bus grundsätzlich zugänglich sind. Die 
Programmierung der Kesselsteuerung ist nämlich so grottenschlecht 
umgesetzt, dass das System sehr viel Energie verschwendet, die 
Restwärmeausnutzung funktioniert nämlich mehr schlecht als recht.

Wäre seeeehr gut, diese in einen Raspberry einzulesen und übers 
SmartHome zugänglich zu machen. Ob das geht?
Ich mag irgendwie nicht an die Steuerplatine des LED-Displays ran. 
Theoretisch könnte man natürlich die LEDs alle abgreifen und über I/O 
Pins in einen Raspi einlesen...

Thx,
Sulla
#7236523
Lesenswert?

Hat an der Arbeit von Tim G. noch jemand angeknüpft?
Ich überlege, mittels ESP32 Daten der Heizungssteuerung per WLAN 
abrufbar zu machen. Die Idee: z.B. Einbindung in HomeAssistant. Wenn Tim 
G. seine ersten an der Schnittstelle mit dem Raspi gemacht hatte, wie er 
schreibt, dann sollte das mit dem ESP32 auch gehen. Hat da schon mal 
jemand etwas gemacht?
#7307324
Lesenswert?

Ich bin jetzt soweit und kann über ein RS485-Shield mittels Arduino wie von Tim G. beschrieben, das Protokoll mitlesen. Mein Problem: ich komme aus den Protokollwerten nicht auf die tatsächlichen Temperaturwerte, die mich interessieren. Die von Tim G. angegebenen Bytepositionen im Protokoll scheinen zwar die Temperaturwerte zu sein, jedoch habe ich noch keinen Zusammenhang gefunden, die Protokollwerte in tatsächliche Temperatur umzurechnen. Tim G. schreibt ja auch, dass dies über einen Faktor umgerechnet wird. Dieser ist aber nicht konstant. Beim Vergleich von Protokollwerten und tatsächlich gemessenen Temperaturen habe ich keinen linearen Zusammenhang erkennen können. Hat jemand hierzu Infos oder eine Idee?

#7309528
Lesenswert?

Centrus schrieb:

Naja. RS485 Adapter gibt es ja billigst auch in EU.

?! klar. Mit Vorbereiten meinte ich in meinem Falle eine Linux Installation des SBC, dass ich an den Adapter hänge.

Kim M. schrieb:

Ich bin jetzt soweit und kann über ein RS485-Shield mittels Arduino wie von Tim G. beschrieben, das Protokoll mitlesen.

Mitlesen bedeutet, dass man ein Remote Gerät benötigt, dass mit der Regelung spricht, oder ? Wie man das "ohne" antriggert, weisst Du nicht, oder?

Mein Problem: ich komme aus den Protokollwerten nicht auf die tatsächlichen Temperaturwerte,

Hast Du mal ein paar Werte zum Mitgrübeln ?

Gruss, Tomas

#7309903
Lesenswert?

Mitlesen bedeutet, dass man ein Remote Gerät benötigt, dass mit der Regelung spricht, oder ? Wie man das "ohne" antriggert, weisst Du nicht, oder?

Wenn ich den Arduino über RS485 an das vordere Interface stecke, kann ich die Datagramme (wie von Tim G. beschrieben) ohne besondere Aktion meinerseits mitlesen. Das passt zumindest zu meinem Verständnis, dass es sich ja hier bereits um einen Bus handelt, auf dem zyklisch Daten ausgetauscht werden. Mit meinem Arduino will ich zunächst nur mitlesen. Aktives Auslesen oder Antriggern mache ich zumindest nicht bewußt.

Hast Du mal ein paar Werte zum Mitgrübeln ?

Hier mal ein paar Datagramm-Ausschnitte (beginnend mit "FF 82 10 20 20 4 ...") sowie abgelesene Werte. Die Beispiele 1.+2. liegen zeitlich nur wenige Min. auseinander. 1.) ... 85 10 1 10 0 0 0 0 0 0 0 0 0 0 0 7E 10 1 10 0 0 0 0 0 0 0 0 0 0 0 60 4C ... AußenT: 15,0 KesselT: 44 VorlaufT: 33 Brenner läuft

2.) ... 85 10 0 0 0 0 0 0 0 0 0 0 0 0 0 52 10 0 10 0 0 0 0 0 0 0 0 0 0 0 62 4C ... AußenT: 15,0 KesselT: 44 VorlaufT: 35 Brenner hat gestoppt

3.) ... 7B 10 1 10 0 0 0 0 0 0 0 0 0 0 0 7E 10 1 10 0 0 0 0 0 0 0 0 0 0 0 68 4C ... AußenT: 9,5 KesselT: 47 VorlaufT: 40

4.) ... 77 10 0 0 0 0 0 0 0 0 0 0 0 0 0 68 10 0 10 0 0 0 0 0 0 0 0 0 0 0 70 4C ... AußenT: 8,0 KesselT: 50 VorlaufT: 42

5.) ... 75 10 0 0 0 0 0 0 0 0 0 0 0 0 0 69 10 1 10 0 0 0 0 0 0 0 0 0 0 0 6E 4C ... AußenT: 6,5 KesselT: 50 VorlaufT: 44

Die Aussentemperatur wurde direkt an der Steuerung ausgelesen. Kessel- und Vorlauftemperatur wurden von analogen Anzeigen an der Heizung abgelesen. Da kann es also Ablese-/Anzeigefehler geben. Auch ist denkbar, dass diese analogen Anzeigen und die Steuerungsinternen Sensoren unterschiedlich träge sind, so dass es bei Temperaturänderungen zu Abweichungen kommt.

Gruß Kim

#7325027
Lesenswert?

Hi Kim, du machst nichts mit Gallipoli ? Ich hab es installiert und erstmal versucht ans Laufen zu bekommen, aber ich verstehe nicht so ganz, wie das funktionieren soll, also werde ich mich glaube ich jetzt auch erstmal ans manuelle Dekodieren machen. Ich schau mir Deine Beispiel-Datensätze mal an (Hatte völlig vergessen, dass ich Dich danach gefragt hatte und war zwischendurch krank).

#7325050
Lesenswert?

Nein, meine Idee war, mittels ESP32 und einem RS485-Adapter den Bus der Heizung mit zu lesen und die für mich interessanten Werte per http abfragbar zu machen. Daher hatte ich auf Basis der Doku von Tim G. die Dekodierung im ESP „zu Fuß“ vornehmen wollen und komme da jetzt nicht weiter.

#7325650
Lesenswert?

Ok, so werde ich das "langfristig" vermutlich auch machen, bzw. nicht per http, sondern der ESP wird die Werte per MQTT pushen.

Wenn ich mir Deine Werte so anschaue, dann passt die Aussentemperatur auf jeden Fall mit den Angaben in https://github.com/bogeyman/gamma/wiki/Protokoll

ueberein:

#2 dez x/2-52 Aussentemp 85 133 14.5 15 85 133 14.5 15 7b 123 9.5 9,5 77 119 7.5 8,0 75 117 6.5 6,5

die Kesseltemperatur, mit einer relativ konstanten Abweichung (die analoge Anzeige duerfte nicht zu genau sein) auch:

#32 dez x/2 Kessel 60 96 48 44 62 98 49 44 68 104 52 47 70 112 56 50 6e 110 55 50

Hinter den Vorlaufwert bin ich noch nicht gekommen, aber da kann natuerlich tatsaechlich die von Dir genannten Traegheit zum Tragen kommen, denn die Vorlauftemperatur aendert sich ja bei offenen Ventilen relativ schnell. Gruss/Tomas

#7326905
Lesenswert?

Ich hab gestern meine Steuerung mal angeklemmt und im Nachgang ist mir aufgefallen, dass ich die falschen Klemmen benutzt habe, (weil die mit AB bezeichnet waren und an den RC Klemmen keine Polaritaet angegeben war). Die Datagramme, die da raus kommen, sehen ein wenig anders aus, aber beinhalten vermutlich die gleichen Informationen etwas anders repraesentiert. Ich hab's erstmal nicht umgeklemmt, weil ich hoffe eventuell das Brenner ein/ausschalten mitbekommen zu koennen. Ich hab die ganze Nacht geloggt, in der Hoffnung, dass ich was erkennen kann:

https://termbin.com/l48z

#7334542
Lesenswert?

Hallo zusammen.

Ich hab den Thread nur halb gelesen aber da das hier eine von zwei Konversationen die man übernhaupt im Internet zu dem Thema findet ist erwähne ich es mal:

Ich habe in den letzten Tagen eine Brücke von meiner Theta N 23B zu MQTT und Home Assistant geschrieben (per serieller Debug-Schnittstelle). Mein Code dazu und info zum Protokoll das das Ding verwendet ist hier zusammengefasst:

https://github.com/phiresky/ebv-theta-to-mqtt

Das was ich sehe sieht recht ähnlich aus was Thomas in seiner letzten Nachricht geschickt hat, und recht anders als das was in dem Wiki zur Gamma oben verlinkt ist.

#7334915
Lesenswert?

Phire S. schrieb:

Das was ich sehe sieht recht ähnlich aus was Thomas in seiner letzten Nachricht geschickt hat, und recht anders als das was in dem Wiki zur Gamma oben verlinkt ist.

Nun ja, deine ist eine Theta, die oben eine Gamma. Das sind unterschiedliche Steuerungsgenerationen, und die haben bis auf den selben Hersteller nicht allzu viel miteinander zu tun.

Oliver

#7346465
Lesenswert?

Phire S. schrieb:

Das was ich sehe sieht recht ähnlich aus was Thomas in seiner letzten Nachricht geschickt hat, und recht anders als das was in dem Wiki zur Gamma oben verlinkt ist.

Ich hab etwas ähnliches über die Ceta angefangen:

https://github.com/tmuehlhoff/ceta

Da Du -speziell in Sachen MQTT- schon weiter bist werde ich vermutlich das ein oder andere von Dir übernehmen! Danke ;)

#7346536
Lesenswert?

Ich hab etwas ähnliches über die Ceta angefangen

Super!

Das Nachrichtenformat sieht echt ziemlich gleich aus, du könntest mal versuchen meinen Code unverändert bei dir laufen zu lassen. Also erst justdump.py um zu loggen und dann protocol_parse.py um die logs zu parsen (und einen plot zu erstellen mit den interesting_values über zeit.

Lass mich wissen wenn ich irgendwie helfen kann.

Bis auf das grundlegende Nachrichtenformat (210a0a + 16-bit nachrichten typ + nachrichten länge + ... + CRC16) ist an meinem Code eigentlich nichts speziell. Die Nachrichteninhalte sind in deklarative liste von interessanten Offsets/Namen in interesting_values.yaml.

#7346539
Lesenswert?

Phire S. schrieb im Beitrag #7346536: ...

versuchen meinen Code unverändert bei dir laufen zu lassen. Also erst justdump.py um zu loggen und dann protocol_parse.py um die logs zu parsen (und einen plot zu erstellen mit den interesting_values über zeit.

Ich hatte die Plots schon von Hand in gnumeric erstellt, sehen Deinen ziemlich ähnlich. Kann ich natütlich trotzdem mal machen. Vor allem diese Stati sind mir noch unklar, da wollte ich mal ein paar Sachen "rumstellen" an der Steuerung und die entsprechenden Änderungen anschauen... Bin ich noch nicht zu gekommen.

Ich bin nicht so firm in JSON, ist irgendwie nicht mein Format, aber muss ich mich wohl durchwuseln ;) Macht ja für SONOFF-MQTT eh Sinn.

#7346549
Lesenswert?

1
root@bananapim2ultra:/home/tomas/ebv-theta-to-mqtt# python3 protocol_parse.py  dump-2023-02-12T23\:03\:59+01\:00.jsonl 
2
Traceback (most recent call last):
3
  File "/home/tomas/ebv-theta-to-mqtt/protocol_parse.py", line 75, in <module>
4
    timestamp: datetime, message: bytes, plot_data: dict[str, list[dict]] | None
5
TypeError: unsupported operand type(s) for |: 'types.GenericAlias' and 'NoneType'

Hab ich da eine falsche Lib ?

#7346552
Lesenswert?

Wenn du sie schon hast ist nat. auch gut ;)

Ich hab grad mal deinen dump von oben durch meinen code geschoben:

1
wget https://termbin.com/l48z
2
cat l48z|cut -c 1-52 > cut
3
pdm run protocol_parse.py cut

und es hat sie tatsächlich richtig verarbeitet. Also die CRC summe und das nachrichtenformat sind gleich.

Du hast in deinem dump irgendwie in jeder Zeile irgendwie links eine valide nachricht und rechts noch eine die abgeschnitten aussieht - zumindest endet sie nicht in einer CRC16 summe und die nachrichtenlänge scheint auch nicht zu stimmen.

unsupported operand type

Äh ja du brauchst für meinen code python 3.10 weil ich gerne im cutting edge lebe ^^, der syntax fehler kommt von python <=3.9.

#7346563
Lesenswert?

Mit folgender interesting_values.yaml:

  • message_type: [0x84, 0x17] byte_offset: 1 format: u8
  • message_type: [0x84, 0x17] byte_offset: 3 format: u16le
  • message_type: [0x84, 0x17] byte_offset: 5 format: u16le
  • message_type: [0x84, 0x17] byte_offset: 7 format: u16le
  • message_type: [0x84, 0x17] byte_offset: 9 format: u16le

gibt mein code für deinen obigen paste-bin dump folgendes aus: (siehe Anhang)

Sieht also ziemlich gut aus :)

Angehängte Dateien:
#7347536
Lesenswert?

Phire S. schrieb im Beitrag #7346552: ...

1
wget https://termbin.com/l48z

...

Du hast in deinem dump irgendwie in jeder Zeile irgendwie links eine valide nachricht und rechts noch eine die abgeschnitten aussieht -

Richtig ;) Ich hatte die Daten "da noch" mit dem Script von Tim ausgelesen, dass aber von einer festen und falschen Länge ausgegangen ist (von der Gamma halt). Ich hatte die Tage Corona und hab das mit Brummschädel erstmal nicht bemerkt, mir war zwar klar, dass da "irgendwas nicht in Ordnung" war, aber ich hatte mich erst mit den Werten beschäftigt.

Kann ich in Deinem Repo einen Branch aufmachen und meine Ceta Sachen einfach hinzufügen ?

Python 3.10, kein Thema, ich hatte die Büchse allerdings erst mühsam auf 2.7 runtergepatcht (was bei Debian 11 gar nicht so einfach war), um Tims Code laufen zu lassen. Bin selbst weder Coder noch mag ich Python sonderlich, daher ist das für mich einfacher die Umgebung so hinzubasteln, dass der Code läuft und nicht umgekehrt ;)

#7542042
Lesenswert?

Hallo zusammen,

dank eurer Vorarbeit hier im Forum habe ich meine CETA 100 erfolgreich verbinden können. Andere CETA Versionen sollten ähnlich sein.

Ich habe dazu einen ESP32 (Wemos D1 mini) mit einem RS485 Adapter verbunden. Als Platform habe ich ESPhome verwendet.

Über die UART kann ich jetzt folgende Parameter auslesen:

  1. Temperatur am Solarmodul
  2. Temperatur im Heizkessel
  3. Pumpenmodus / Zirkulationspumpe ein/aus
  4. Anzahl Pumpenstarts
  5. Betriebstunden

alles read-only!

Hier noch mein Code (bestimmt nicht schön geschrieben - aber es funktioniert :-)):

CETA100.YAML

1
esphome:
2
  name: "name"
3
  includes:
4
    - my_CETA100_uart.h
5

6
esp32:
7
  board: esp32dev
8
  framework:
9
    type: arduino
10

11
# Enable logging
12
logger:
13

14
# Enable Home Assistant API
15
api:
16
  encryption:
17
    key: "XXXXXXX"
18

19
ota:
20
  password: "XXXXXXX"
21

22

23
wifi:
24
  ssid: !secret wifi_ssid
25
  password: !secret wifi_password
26

27
  # Enable fallback hotspot (captive portal) in case wifi connection fails
28
  ap:
29
    ssid: "XXXXXXX"
30
    password: "XXXXXXX"
31

32
captive_portal:
33

34

35

36
#CETA100 control
37
uart:
38
  id: uart_bus
39
  tx_pin: 3
40
  rx_pin: 1
41
  baud_rate: 9600 #port = serial.Serial(serialDevice, baudrate=9600, timeout=60.0, bytesize=serial.EIGHTBITS, stopbits=serial.STOPBITS_ONE, parity=serial.PARITY_NONE, xonxoff=False, rtscts=False, dsrdtr=False)
42
  stop_bits: 1
43
#  debug:
44
#    direction: BOTH
45

46
binary_sensor:
47
  - platform: template
48
    name: "CETA100 Pumpen Mode"
49
    device_class: "running"
50
    lambda: |-
51
      if (id(CETA100_Pumpen_Mode).state > 0) {
52
        return true;
53
      } else {
54
        return false;
55
      }
56

57

58
sensor:
59
  - platform: custom
60
   #     auto CETA100_Sensor = new CETA100Sensor(id(uart_bus),60000);
61
    lambda: |-
62
      auto CETA100_Sensor = new CETA100Sensor(id(uart_bus));
63
      App.register_component(CETA100_Sensor);
64
      return {CETA100_Sensor->burnerMode_sensor,
65
              CETA100_Sensor->PVTemp_sensor,
66
              CETA100_Sensor->ActWasserspeicherTemp_sensor,
67
              CETA100_Sensor->BetriebsStundenPumpe_sensor,
68
              CETA100_Sensor->AnzahlStartsPumpe_sensor};
69
    sensors: 
70
    - name: "CETA100 Pumpen Mode temp"
71
      internal: true
72
      id: CETA100_Pumpen_Mode
73
#      filters:
74
#        - lambda: !lambda |-
75
#            if (x == 3) return {true};
76
#            return false;
77
    - name: "CETA100 Solar Modul Temperature"
78
      unit_of_measurement: °C
79
      device_class: temperature
80
      accuracy_decimals: 1
81
    - name: "CETA100 Speicher Temperature"
82
      device_class: temperature
83
      unit_of_measurement: °C
84
      accuracy_decimals: 1
85
    - name: "CETA100 Betriebsstunden Pumpe"
86
      unit_of_measurement: h
87
      device_class: duration
88
    - name: "CETA100 Anzahl Starts Pumpe"
89
      id: CETA100_Anzahl_Starts_Pumpe

my_CETA100_uart.h

1
#include "esphome.h"
2

3
class CETA100Sensor : public Component, public UARTDevice , public Sensor{
4
 public:
5
  
6
  CETA100Sensor(UARTComponent *parent) : UARTDevice(parent) {}
7
  
8
  Sensor *burnerMode_sensor = new Sensor();
9
  Sensor *PVTemp_sensor = new Sensor();
10
  Sensor *ActWasserspeicherTemp_sensor = new Sensor();
11
  Sensor *BetriebsStundenPumpe_sensor = new Sensor();
12
  Sensor *AnzahlStartsPumpe_sensor = new Sensor();
13
  
14
  
15
  void setup() override {
16
    // nothing to do here
17
  }
18

19
  std::vector<int> bytes;
20
  int count = 0;
21

22
//  void update() override {
23
  void loop() override {
24
    const int message_length = 43;
25
    const int pushinterval = 15;
26
    
27
    while (available()) {
28
        
29
      bytes.push_back(read()); //UART Read into Bytes variable.  HIer muss geändert werden auf die letzten 43 Bytes.
30

31
      if(bytes.size() < message_length)       
32
      {
33
        continue;  
34
      }
35
       //ESP_LOGD("custom", "checking bytes");
36
      if(bytes[0] != 0x21 || bytes[1] != 0x0A || bytes[2] != 0x15 ) {
37
      //sync to start
38
        bytes.erase(bytes.begin()); //remove first byte from buffer
39
        continue;
40
      } 
41

42
      if(bytes.size() == message_length) {
43
          
44
          if(count == pushinterval) {  //meachanism to only send every X received messages from UART - otherwise overflow of Data
45
          
46
          //burnerMode_sensor->publish_state(burnermode);
47
          burnerMode_sensor->publish_state(bytes[13]);
48
          //ESP_LOGD("custom", "Parsed burnerMode_sensor: %i", bytes[13]);
49
          
50
          //Temperatur Wärmelieferant
51
          TwoByte PVTemp;
52
          PVTemp.Byte[0] = bytes[14];
53
          PVTemp.Byte[1] = bytes[15];  
54
          PVTemp_sensor->publish_state(float(PVTemp.Int16)/10); 
55
          //ESP_LOGD("custom", "Parsed PVTemp_sensor: %.1f", float(PVTemp.Int16)/10);
56
          
57
          // Temperatur Wasserspeicher
58
          TwoByte ActWasserspeicherTemp;
59
          ActWasserspeicherTemp.Byte[0] = bytes[16];
60
          ActWasserspeicherTemp.Byte[1] = bytes[17];  
61
          ActWasserspeicherTemp_sensor->publish_state(float(ActWasserspeicherTemp.UInt16)/10);
62
          //ESP_LOGD("custom", "Parsed ActWasserspeicherTemp_sensor: %.1f", float(ActWasserspeicherTemp.UInt16)/10);
63
          
64
          // Betriebsstunden Pumpe
65
          TwoByte BetriebsStundenPumpe;
66
          BetriebsStundenPumpe.Byte[0] = bytes[18];
67
          BetriebsStundenPumpe.Byte[1] = bytes[19];  
68
          BetriebsStundenPumpe_sensor->publish_state(BetriebsStundenPumpe.UInt16);
69
          //ESP_LOGD("custom", "Parsed BetriebsStundenPumpe: %i", BetriebsStundenPumpe);
70
          
71
          // Starts Pumpe
72
          TwoByte AnzahlStartsPumpe;
73
          AnzahlStartsPumpe.Byte[0] = bytes[20];
74
          AnzahlStartsPumpe.Byte[1] = bytes[21];  
75
          AnzahlStartsPumpe_sensor->publish_state(AnzahlStartsPumpe.UInt16);
76
          //ESP_LOGD("custom", "Parsed AnzahlStartsPumpe: %i", AnzahlStartsPumpe.UInt16);     
77
          
78
          //ESP_LOGD("custom", "Countreached: %i", count);
79
          count=0;
80
          
81
          }
82
        //ESP_LOGD("custom", "Countinterim status: %i", count);
83
        bytes.clear();
84
        count++;
85
      }
86
    }
87
  }
88
  
89
typedef union
90
  {
91
    unsigned char Byte[2];
92
    int16_t Int16;
93
    uint16_t UInt16;
94
    unsigned char UChar;
95
    char Char;
96
  }TwoByte;  
97
  
98
};

grüße, Christian

#7675228
Lesenswert?

moin, ich beschäftige mich aktuell gerade etwas damit. zwar mit ESP32 + RS485 adapter.

für Arduino:

#include <HardwareSerial.h>

HardwareSerial rs485(1);

void setup() { // Seriellen Monitor starten Serial.begin(115200); Serial.println("Setup gestartet");

// RS485 Serial konfigurieren rs485.begin(9600, SERIAL_8N1, 17, 16); // RX_PIN = 17, TX_PIN = 16 Serial.println("RS485 Leser gestartet"); }

void loop() { // Prüfen, ob genügend Daten verfügbar sind if (rs485.available() >= 33) { // Mindestens 33 Bytes für alle Daten einschließlich Kesseltemperatur // Daten von RS485 lesen byte incomingData[33]; for (int i = 0; i < 33; i++) { incomingData[i] = rs485.read(); }

1
// Überprüfen, ob die Daten auf Warmwassertemperatur hinweisen
2
for (int i = 0; i < 33 - 3; i++) {
3
  // Überprüfen, ob das aktuelle Byte und die nächsten drei Bytes dem Muster entsprechen
4
  if (incomingData[i] == 0x04 && incomingData[i + 2] == 0x10 && (incomingData[i + 3] == 0x00 || incomingData[i + 3] == 0x02 || incomingData[i + 3] == 0xFF)) {
5
    // Hier können Sie weitere Bedingungen hinzufügen, um sicherzustellen, dass die Temperatur korrekt erkannt wird
6

7
    // Annahme: Die Temperatur befindet sich im nächsten Byte
8
    float temperatur = incomingData[i + 4];
9

10
    // Debug-Ausgabe der Warmwassertemperatur
11
    Serial.print("Potenzielle Warmwassertemperatur gefunden: ");
12
    Serial.println(temperatur);
13

14
    // Außentemperaturbedingungen überprüfen
15
    if (incomingData[0] == 0x04 && incomingData[2] == 0x10 && (incomingData[3] == 0x00 || incomingData[3] == 0x02 || incomingData[3] == 0xFF)) {
16
      // Außentemperatur berechnen
17
      float aussentemperatur = (int)incomingData[1] / 2.0 - 52.0;
18

19
      // Kesseltemperatur berechnen (aus hexadezimalem Wert)
20
      int kesselTempValue = int(incomingData[32]); // Hexadezimalwert in Ganzzahl umwandeln
21

22
      // Hier nehmen wir eine neue Formel an, um den Wert zu korrigieren
23
      float kesseltemperatur = kesselTempValue / 1.52; // Experimenteller Faktor, um den Wert zu korrigieren
24

25
      // Debug-Ausgaben
26
      Serial.print("Kesseltemperatur: ");
27
      Serial.println(kesseltemperatur);
28

29
      // Außentemperatur über den seriellen Monitor ausgeben
30
      Serial.print("Außentemperatur: ");
31
      Serial.println(aussentemperatur);
32
    }
33
  }
34
}
35

36
// Uhrzeit und Datum überprüfen und verarbeiten
37
if (incomingData[0] == 0x05 && (incomingData[1] == 0x00 || incomingData[1] == 0x02)) {
38
  byte sekunde = incomingData[2];
39
  byte minute = incomingData[3];
40
  byte stunde = incomingData[4];
41
  byte tag = incomingData[5];
42
  byte monat = incomingData[6] & 0x0F; // Einerstelle des Monats
43
  byte tagWoche = (incomingData[6] >> 4) & 0x07; // Tag in der Woche
44
  byte jahr = incomingData[7];
45

46
  // Überprüfen, ob die Uhrzeit und das Datum gültig sind
47
  if (stunde < 0x24 && minute < 0x60 && sekunde < 0x60 &&
48
      tag < 0x32 && monat < 0x13 && tagWoche < 0x07 && jahr >= 0x20) {
49

50
    // Wochentag ermitteln
51
    const char* wochentage[] = {"Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"};
52
    const char* monate[] = {"Januar", "Februar", "März", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Dezember"};
53

54
    Serial.print("Datum: ");
55
    Serial.print(wochentage[tagWoche - 1]); // Wochentage-Index beginnt bei 0
56
    Serial.print(", den ");
57
    Serial.print(tag, HEX);
58
    Serial.print(". ");
59
    Serial.print(monate[monat + 1]); // Monate-Index beginnt bei +1
60
    Serial.print(" 20");
61
    Serial.println(jahr, HEX);
62

63
    Serial.print("Uhrzeit: ");
64
    if (stunde < 0x10) Serial.print("0"); // Führende Null für einstellige Stunden
65
    Serial.print(stunde, HEX);
66
    Serial.print(":");
67
    if (minute < 0x10) Serial.print("0"); // Führende Null für einstellige Minuten
68
    Serial.print(minute, HEX);
69
    Serial.print(":");
70
    if (sekunde < 0x10) Serial.print("0"); // Führende Null für einstellige Sekunden
71
    Serial.println(sekunde, HEX);
72
  }
73
}

} }

#7827553
Lesenswert?

Hardy schrieb:

Hallo zusammen

falls es noch jemanden interessiert: ich bin dabei an einer Toptronic 23S rumzubasteln.

Die anbindende Hardware ist ein raspi5 + RS495-IF. Ich kann inzwischen ein paar Werte aus dem Datenstrom empfangen und per mqtt versenden.

Alles sehr experimentell, aber hier ist das Repo: https://github.com/rgrr/TopTronic23S

Hey Hardy, hast du bei dir noch was am Protocol angepasst oder das so von bogeyman übernommen?

Ich habe von Intercal ein RG23B Steuerung, die sieht der TopTronic sehr ähnlich. Mein RS485 Adapter kommt morgen, mal gucken was ich rausbekomme.

#7827920
Lesenswert?

:

hast du bei dir noch was am Protocol angepasst oder das so von bogeyman übernommen?

:

Hi Erik,

das Protokoll ist fast das gleiche. Die kleinen Unterschiede belaufen sich darauf, dass die TopTronic wohl Parity verwendet. Das sieht man recht schnell, wenn im Datenstrom Daten mit abwechselnden 0xff empfangen wird (zumindest unter Linux). Außerdem ist der Datenblock im cmd4 bei mir größer.

Ansonsten einfach mal die Skripte in https://github.com/rgrr/TopTronic23S/tree/main/testing anschauen.

#7885147
Lesenswert?

Hello,

Thank you all for sharing this useful information about the protocol behind Gamma device. I own one Gamma as well.

Has anyone had sucess in sending commands to this device rather than reading from it? Looks like Tim G had dumps from people owning an RS10 station that sends commands but these are not shared here.

Last resort would be to use the protocol for reading only, and using small servo-motors to rotate both knobs!

Thanks

Gast #7961440
Lesenswert?

Hallo zusammen :)

ich habe da was in ESPHome gezaubert:

1
esphome:
2
  name: rs485
3
  friendly_name: RS485
4

5
esp32:
6
  board: esp32-c3-devkitm-1
7
  framework:
8
    type: esp-idf
9

10
logger:
11
  level: DEBUG
12

13
api:
14
  encryption:
15
    key: "******="
16

17
ota:
18
  - platform: esphome
19
    password: "********"
20

21
wifi:
22
  ssid: !secret wifi_ssid
23
  password: !secret wifi_password
24

25
captive_portal:
26

27
globals:
28
  - id: outside_temp
29
    type: float
30
    restore_value: true
31
    initial_value: '0.0'
32
  - id: mid_temp
33
    type: float
34
    restore_value: true
35
    initial_value: '0.0'
36
  - id: boiler_temp
37
    type: float
38
    restore_value: true
39
    initial_value: '0.0'
40
  - id: indoor_temp_06
41
    type: float
42
    restore_value: true
43
    initial_value: '0.0'
44
  - id: setpoint_06
45
    type: float
46
    restore_value: true
47
    initial_value: '0.0'
48
  - id: _setpoint_06_last_raw
49
    type: int
50
    restore_value: false
51
    initial_value: '0'
52
  - id: _setpoint_06_stable_count
53
    type: int
54
    restore_value: false
55
    initial_value: '0'
56

57
uart:
58
  id: uart_bus
59
  tx_pin: GPIO1
60
  rx_pin: GPIO3
61
  baud_rate: 9600
62
  parity: NONE
63
  stop_bits: 1
64
  debug:
65
    direction: BOTH
66
    dummy_receiver: true
67
    after:
68
      timeout: 50ms
69
    sequence:
70
      - then:
71
          - lambda: |-
72
              const uint8_t TERM_PRIMARY = 0x03;
73
              const uint8_t TERM_ALT_PREFIX = 0x06;
74
              const size_t MAX_PAYLOAD = 1024;
75

76
              auto format_hex = [&](const uint8_t *ptr, size_t len)->std::string {
77
                std::string s;
78
                for (size_t z = 0; z < len; ++z) {
79
                  char tmp[4]; snprintf(tmp, sizeof(tmp), "%02X", ptr[z]);
80
                  if (!s.empty()) s.push_back('.');
81
                  s += tmp;
82
                }
83
                return s;
84
              };
85

86
              auto crc16_kermit = [](const uint8_t *data, size_t len)->uint16_t {
87
                uint16_t crc = 0x0000;
88
                for (size_t i = 0; i < len; ++i) {
89
                  crc ^= (uint16_t)data[i];
90
                  for (int b = 0; b < 8; ++b) {
91
                    if (crc & 1) crc = (crc >> 1) ^ 0x8408; else crc = (crc >> 1);
92
                  }
93
                }
94
                return crc & 0xFFFF;
95
              };
96

97
              auto raw_to_out = [&](uint8_t v)->float { return ((v==0xFF)?NAN:((float)v)/2.0f - 52.0f); };
98
              auto raw_to_simple = [&](uint8_t v)->float { return ((float)v) / 2.0f; };
99

100
              // Framefinder und Parser
101
              for (size_t i = 0; i + 3 <= bytes.size(); ++i) {
102
                if (bytes[i] != 0x10 || bytes[i+1] != 0x20) continue;
103
                uint8_t LL = bytes[i+2];
104
                size_t content_len = (size_t)LL + 1;
105
                size_t cs = i + 3;
106
                size_t ce = cs + content_len;
107
                size_t crc_lo = ce;
108
                size_t crc_hi = ce + 1;
109
                size_t term = ce + 2;
110
                if (ce > bytes.size() || crc_hi >= bytes.size() || term >= bytes.size()) { i = ce; continue; }
111

112
                bool term_ok = (bytes[term] == TERM_PRIMARY) || (bytes[term] == TERM_ALT_PREFIX && term+1 < bytes.size() && bytes[term+1] == TERM_PRIMARY);
113
                if (!term_ok) { i = term; continue; }
114

115
                const uint8_t *crc_src = &bytes[i];
116
                size_t crc_src_len = ce - i;
117
                if (crc_src_len == 0 || crc_src_len > MAX_PAYLOAD) { i = term; continue; }
118
                uint16_t calc = crc16_kermit(crc_src, crc_src_len);
119
                uint16_t frame_crc = (uint16_t)bytes[crc_lo] | ((uint16_t)bytes[crc_hi] << 8);
120
                if (calc != frame_crc) { ESP_LOGW("CRC","CRC mismatch %04X!=%04X payload=%s", calc, frame_crc, format_hex(&bytes[cs], content_len).c_str()); i = term; continue; }
121

122
                const uint8_t *pl = &bytes[cs];
123
                size_t plen = content_len;
124
                if (plen == 0) { i = term; continue; }
125

126
                uint8_t mtype = pl[0];
127

128
                // TYPE 0x04: outside, mid, boiler (wie vorher)
129
                if (mtype == 0x04) {
130
                  if (plen > 1) {
131
                    float outside = raw_to_out(pl[1]);
132
                    if (outside >= -10.0f && outside <= 50.0f) id(outside_temp) = outside;
133
                  }
134
                  if (plen > 16) {
135
                    float mid = raw_to_simple(pl[16]);
136
                    if (mid >= -10.0f && mid <= 50.0f) id(mid_temp) = mid;
137
                  }
138
                  if (plen > 31) {
139
                    float boiler = raw_to_simple(pl[31]);
140
                    if (boiler >= -10.0f && boiler <= 50.0f) id(boiler_temp) = boiler;
141
                  }
142
                  ESP_LOGI("TYPE04","outside=%.2f mid=%.2f boiler=%.2f payload=%s",
143
                           id(outside_temp), id(mid_temp), id(boiler_temp), format_hex(pl, plen).c_str());
144
                }
145

146
                // mtype 0x06: zwei Verwendungen
147
                if (mtype == 0x06) {
148
                  // 1) Innenraumtemperatur (Offset 1)
149
                  if (plen > 1) {
150
                    float val = raw_to_simple(pl[1]);
151
                    if (val >= -10.0f && val <= 50.0f) {
152
                      id(indoor_temp_06) = val;
153
                      ESP_LOGI("INDOOR06","accepted %.2f °C from mtype06 payload=%s", val, format_hex(pl, plen).c_str());
154
                    } else {
155
                      ESP_LOGW("INDOOR06","ignored %.2f °C (out of range) payload=%s", val, format_hex(pl, plen).c_str());
156
                    }
157
                  }
158

159
                  // 2) Sollwert / Setpoint — Byteindex 3 (0-basiert)
160
                  if (plen > 3) {
161
                    uint8_t raw_sp = pl[3]; // z.B. 0x17 / 0x20 / 0x27 etc.
162
                    float temp_sp = (float)raw_sp / 2.0f;
163
                    if (std::isfinite(temp_sp) && temp_sp >= -10.0f && temp_sp <= 50.0f) {
164
                      int last_raw = id(_setpoint_06_last_raw);
165
                      int stable = id(_setpoint_06_stable_count);
166

167
                      if (raw_sp == last_raw) {
168
                        stable = stable + 1;
169
                      } else {
170
                        stable = 1;
171
                        id(_setpoint_06_last_raw) = raw_sp;
172
                      }
173
                      id(_setpoint_06_stable_count) = stable;
174

175
                      // Übernehme erst nach 2 gleichen Rohwerten in Folge (stabilitätsfilter)
176
                      if (stable >= 2) {
177
                        id(setpoint_06) = temp_sp;
178
                        ESP_LOGI("SETPOINT06","accepted %.2f °C (raw=0x%02X) payload=%s", temp_sp, raw_sp, format_hex(pl, plen).c_str());
179
                      } else {
180
                        ESP_LOGD("SETPOINT06","seen raw=0x%02X once, waiting for stability payload=%s", raw_sp, format_hex(pl, plen).c_str());
181
                      }
182
                    } else {
183
                      ESP_LOGW("SETPOINT06","ignored out-of-range %.2f payload=%s", temp_sp, format_hex(pl, plen).c_str());
184
                    }
185
                  }
186
                }
187

188
                i = term;
189
              }
190

191

192
sensor:
193
  - platform: template
194
    name: "Innenraum-Temperatur"
195
    icon: "mdi:home-thermometer"
196
    id: sensor_indoor_06
197
    unit_of_measurement: "°C"
198
    device_class: temperature
199
    accuracy_decimals: 1
200
    update_interval: 10s
201
    lambda: |-
202
      return id(indoor_temp_06);
203

204
  - platform: template
205
    name: "Außen-Temperatur"
206
    icon: "mdi:home-thermometer-outline"
207
    id: sensor_outside_temp
208
    unit_of_measurement: "°C"
209
    device_class: temperature
210
    accuracy_decimals: 1
211
    update_interval: 10s
212
    lambda: |-
213
      return id(outside_temp);
214

215
  - platform: template
216
    name: "Kessel-Temperatur"
217
    icon: "mdi:fire"
218
    id: sensor_boiler_temp
219
    unit_of_measurement: "°C"
220
    device_class: temperature
221
    accuracy_decimals: 1
222
    update_interval: 10s
223
    lambda: |-
224
      return id(boiler_temp);
225

226
  - platform: template
227
    name: "Brenner Durchschnitts-Temperatur"
228
    icon: "mdi:radiator-disabled"
229
    id: sensor_brenner_avg
230
    unit_of_measurement: "°C"
231
    device_class: temperature
232
    accuracy_decimals: 1
233
    update_interval: 10s
234
    lambda: |-
235
      return id(mid_temp);
236

237
  - platform: template
238
    name: "Brenner Abschalt-Temperatur"
239
    icon: "mdi:radiator-off"
240
    id: sensor_brenner_off
241
    unit_of_measurement: "°C"
242
    device_class: temperature
243
    accuracy_decimals: 1
244
    update_interval: 10s
245
    lambda: |-
246
      if (!std::isfinite(id(mid_temp))) return NAN;
247
      return id(mid_temp) + 4.0f;
248

249
  - platform: template
250
    name: "Brenner Einschalt-Temperatur"
251
    icon: "mdi:radiator"
252
    id: sensor_brenner_on
253
    unit_of_measurement: "°C"
254
    device_class: temperature
255
    accuracy_decimals: 1
256
    update_interval: 10s
257
    lambda: |-
258
      if (!std::isfinite(id(mid_temp))) return NAN;
259
      return id(mid_temp) - 4.0f;
260

261
  - platform: template
262
    name: "Innenraum-Soll-Temperatur"
263
    icon: "mdi:temperature-celsius"
264
    id: sensor_setpoint_06
265
    unit_of_measurement: "°C"
266
    device_class: temperature
267
    accuracy_decimals: 1
268
    update_interval: 10s
269
    lambda: |-
270
      if (!std::isfinite(id(setpoint_06))) return NAN;
271
      return id(setpoint_06);

Wichtig zu wissen, Der sensor Brenner Abschalt-Temperatur & Heizung Brenner Einschalt-Temperatur werden anhand von dem sensor Heizung Brenner Durchschnitts-Temperatur abgeleitet und mit der in der Gamma fest eingestellten "Brennerschaltdifferenz" errechnet, bei mir ist die Brennerschaltdifferenz 8k (Werkseinstellung ist 6k)

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren