Seite 1 von 1

ESERA EC1 in Openhab integrieren

Verfasst: 4. Sep 2025 12:45
von Cowy
Hallo,

Ich versuche das ESERA EC1 Modul in Openhab zu integrieren und komme leider nur sehr langsam voran ;-)
Konnte leider keine Beispiele ergoogeln welche mir weiter geholfen hätten.
Mit etwas Hilfe vom englischen Forum hab ich die Sensordaten hinbekommen.

Wäre euch sehr verbunden wenn ihr mir hier weiter unter die Arme greifen könntet.
Binding: SmartHome/J TCP/UDP Binding https://docs.smarthomej.org/4.3.0-SNAPS ... cpudp.html
Verbindung klappt soweit dass ich folgenden String ausgelesen bekomme.

Code: Alles auswählen

1_EVT|12:22:58
1_OWD1|2362
1_OWD2|2387
1_OWD3_1|255
1_OWD3_2|11111111
1_OWD3_3|12
1_OWD3_4|00001100

Code: Alles auswählen

Thing tcpudp:client:string "my ESERA Data" [ host="192.168.0.60", port="5000", protocol="TCP", timeout="15000" ] {
    Channels:
        Type string : TCPChannel "my ESERA TCP Channel" [ stateContent="GET,SYS,DATA" ]
        Type switch : ESERA_S1      "Esera test switch 1" [ commandTransformation = "MAP:|0=set,owd,out,3,1,0 ; 1=set,owd,out,3,1,1", 
                                                            onValue="1_OWD3_4|*******1" , offValue="1_OWD3_4|*******0"]}
Items:

Code: Alles auswählen

String              ESERA_1Wire_String          "ESERA OneWire String"            { channel="tcpudp:client:string:TCPChannel"}     
Switch              ESERA_TestSwitch            "ESERA Test Switch"                { channel="tcpudp:client:string:ESERA_S1"}

Code: Alles auswählen

rule "ESERA OneWire"
when
    Item ESERA_1Wire_String changed 
then
      var Number newValue = Integer::parseInt(transform("REGEX", ".*OWD1\\|(\\d+).*", ESERA_1Wire_String.state.toString))
      newValue = newValue / 100
      Temp_Solar_New.postUpdate(newValue)
end
Die Sensorwerte habe ich schlussendlich über eine Rule abgedeckt da ich mit einer zuweisung mehrerer Items zum channel die division durch 100 nicht hinbekommen habe. Und für jedes "Gerät" (OWD1...3) einen Channel anzulegen hat das Problem generiert dass jeder Channel die selbe Abfrage durchführt. Soweit ich verstanden habe ist zu jedem Channel in diesem Binding zwingend ein "stateContent" zu definieren (GET,SYS,DATA)
Wenn es wesentlich Sinnvoller ist dies dennoch über die Channel/Item Definition abzudecken als über eine Rule bitte um Hilfe wie ich dies bewerkstelligen sollte.

Nun zum eigentlichen Problem einen Schaltbefehl auszuführen.
Über das Terminalprogram Hercules kann ich mit dem OFFBefehl "set,owd,out,3,1,0" und ONBefehl "set,owd,out,3,1,1" den entsprechenden Ausgang schalten. Habe mit obiger Channel Definition (Mapping) versucht es umzusetzen aber es klappt leider nicht.
Weiters beim onValue bin ich nicht sicher of * als Platzhalter funktioniert da dieses Modul 8 Ausgänge hat und der ensprechende Ausgang der letzten Stelle "1_OWD3_4|00001100" entspricht.

Vielen Lieben Dank
Christoph

Re: ESERA EC1 in Openhab integrieren

Verfasst: 5. Sep 2025 01:13
von udo1toni
Herzlich willkommen im openHAB Forum!

Ich fürchte, das wird so eher gar nicht funktionieren (allerdings habe ich keine Erfahrung mit dem Binding, ich kann mich da auch gut irren).
Mein Vorschlag: Betrachte den Channel als reinen Sende- und Empfangskanal.
Lege für jeden Switch und jeden Wert ein passendes Item an, welches aber nicht mit dem Channel verlinkt wird.
Stattdessen schreibst Du zwei Rules, die eine für die Senderichtung, die andere für die Empfangsrichtung. Innerhalb der beiden Rules errechnest Du dann aus dem gelieferten String die Zustände der Items und setzt diese per postUpdate bzw. Du nutzt die Itemzustände, um den passenden Befehlsstring zusammenzusetzen.
onValue und offValue wären für den switch Channel hier übrigens 1 bzw. 0. Aber es gibt im Thing keine Möglichkeit, den Sendestring korrekt zusammenzusetzen, wohl aber innerhalb einer Rule.
Items:

Code: Alles auswählen

String OneWireSend // wird nur zum Senden verwendet
String OneWireReceive // wird nur zum Empfang verwendet
DateTime OW_EventTime "Letzter Empfang um"
Number OWD1_Value   "Messwert D 1"
Number OWD2_Value   "Messwert D 2"
Number OWD3_1_Value "Messwert D 3.1"
Number OWD3_3_Value "Messwert D 3.3"
Group gOwd
Switch gOwd_3_4_1 "1-Wire 3-4 Ch. 1" (gOwd)
Switch gOwd_3_4_2 "1-Wire 3-4 Ch. 2" (gOwd)
Switch gOwd_3_4_3 "1-Wire 3-4 Ch. 3" (gOwd)
Switch gOwd_3_4_4 "1-Wire 3-4 Ch. 4" (gOwd)
Switch gOwd_3_4_5 "1-Wire 3-4 Ch. 5" (gOwd)
Switch gOwd_3_4_6 "1-Wire 3-4 Ch. 6" (gOwd)
Switch gOwd_3_4_7 "1-Wire 3-4 Ch. 7" (gOwd)
Switch gOwd_3_4_8 "1-Wire 3-4 Ch. 8" (gOwd)
Rule:

Code: Alles auswählen

rule "1-Wire Senderichtung"
when
    Member of gOwd received command // eines der Switch Items wurde betätigt
then
    val strChan = triggeringItem.name.split("_").get(3) // der Teilstring nach dem dritten Unterstrich
    val strOnOff = if(receivedCommand == ON) "1" else "0" 
    val myCommand = "set,owd,out,3," + strChan + "," + strOnOff
    OneWireSend.sendCommand(myCommand)
end
Es gibt ja noch OWD3_2, falls Du dieses mittels set,owd,out,1,n schalten kannst, könnte man die entsprechenden Switch Items einfach der Gruppe hinzufügen und die Rule um die Abfrage der vorletzten Stelle erweitern. Der String myCommand muss dann halt noch eine weitere Variable enthalten, deren Wert Du vorher aus dem Itemnamen errechnen musst.

Die Empfangsseite ist leider etwas komplexer, aber auch zu bewältigen. Meine Herangehensweise ist hier, das Ganze mit einer Schleife zu realisieren, statt REGEX zu verwenden.

Das Ganze fängt harmlos an und steigert sich zu einem furiosen Finale ;)

Code: Alles auswählen

rule "1-Wire Empfangsrichtung"
when
    OneWireReceive received update
then
    val lMessage = newState.split("\n") // newState -> aktueller Status des triggernden Items
    lMessage.forEach[entry|
        val strName = entry.split("\\|").get(0) // Teilstring links  vom |
        val strVal  = entry.split("\\|").get(1) // Teilstring rechts vom |
        switch(strName) {
            case "1_EVT"    : OW_EventTime.postUpdate(strVal)
            case "1_OWD1"   : OWD1_Value.postUpdate(Integer::parseInt(strVal).doubleValue/100)
            case "1_OWD2"   : OWD2_Value.postUpdate(Integer::parseInt(strVal).doubleValue/100)
            case "1_OWD3_1" : OWD3_1_Value.postUpdate(Integer::parseInt(strVal).doubleValue/100)
            case "1_OWD3_3" : OWD3_3_Value.postUpdate(Integer::parseInt(strVal).doubleValue/100)
            case "1_OWD3_2" : {
                val java.math.BigInteger biVal = java.math.BigInteger.valueOf(Integer::parseInt(strVal,2))
                gOwd.members.filter[i|i.name.split("_").get(1) == "2"].sortBy[name].forEach[i,count|
                    i.postUpdate(if(biVal.testBit(count)) ON else OFF)

                ]
            }
            case "1_OWD3_4" : {
                val java.math.BigInteger biVal = java.math.BigInteger.valueOf(Integer::parseInt(strVal,2))
                gOwd.members.filter[i|i.name.split("_").get(1) == "4"].sortBy[name].forEach[i,count|
                    i.postUpdate(if(biVal.testBit(count)) ON else OFF)
                ]
            }

        }
    ]
end
Zunächst wird der empfangene String an den Zeilenumbrüchen gesplittet. lMessage ist anschließend eine Liste aller Zeilen.
Anschließend wird für jeden Eintrag in der Liste der gleiche Code abgearbeitet.
Die Zeile wird an der Pipe gesplittet, links steht der Name, der landet in strName, rechts der Wert, der in strVal gespeichert wird.
Nun wird abhängig von strName unterschiedlicher Code ausgeführt. Da es etliche unterschiedliche Namen gibt, bietet sich hier switch() an.

Falls strName die Werte 1_EVT, 1_OWD1, 1_OWD2, 1_OWD3_1 oder 1_OWD3_3 enthält, wird der String in strVal als Integer eingelesen und anschließend als Float mit doppelter Genauigkeit durch 100 geteilt. Danach wird das Ergebnis im jeweiligen Item gespeichert.

Enthält strName stattdessen 1_OWD3_2 oder 1_OWD3_4, wird es zugegebenermaßen übel...
Im ersten Schritt wird strVal als Binärwert in BigInteger gewandelt. Leider sieht das sehr kompliziert aus, das liegt allerdings nur daran, dass java.math.BigInteger gewöhnlich nicht zur Verfügung steht, es muss also importiert werden.
Warum BigInteger hier der "richtige" Datentyp ist? Weil nur BigInteger eine Methode .testBit() hat, und die macht uns gleich das Leben so viel leichter...

Nun wird die Gruppe der Switch Items gefiltert (die haben wir ja schon, also können wir sie auch ruhig intensiv nutzen...), und zwar auf die Items, welche in dem ausgewerteten Byte dargestellt werden.
Die entstehende Liste der Items wird nun durchlaufen und für jedes Item wird das korrespondierende Bit ausgewertet.
Ist das Bit gesetzt (true), so wird als Wert ON für den Switch gesetzt, ansonsten OFF.

Weil dieser Code schon ziemlich... äh... ist, habe ich das Ganze in openHAB5.1.0 getestet (allerdings nur gegen den String, der im Ausgangspost steht... ich habe kein Device, welches mit TCP/UDP angesteuert werden müsste...) Der Code sollte mit jeder openHAB Version funktionieren - bis hinunter zu openHAB1.0 (mit ein paar kleineren Anpassungen...).

Wichtig ist natürlich noch, dass die Namen der Items passend gewählt werden, nur so kann man die Gruppe effizient durchlaufen. Die Itemnamen müssen dabei nicht exakt so aussehen wie im Beispiel, wichtig ist nur, dass die Unterscheidungsmerkmale, nach denen gefiltert oder gesucht wird immer an identischer Stelle zu finden sind, so dass man die Werte berechnen und auswerten kann.

Re: ESERA EC1 in Openhab integrieren

Verfasst: 5. Sep 2025 14:45
von Cowy
Vielen Lieben Dank für die extrem ausführliche Antwort und grandiose Unterstützung ... bin die nächste Woche unterwegs und habe es derzeit mit meinem "alten" 1Wire system gelöst. Werde das wohl erst in ein paar Wochen wieder angehen. Derzeit versuche ich mein neues Vaillantsystem via Ebusd und mqtt ans laufen zu bekommen ;-) Alles Liebe aus Wien