Since a few weeks I have my electric car and could therefore test also the wallbox integration. As it has proven itself now for a few weeks, I´m happy to share my integration.
// Funktion zum Lesen von Input-Registern wird von der Wallbox nicht unterstützt, Register können nur als Holding-Register gelesen werden
Bridge modbus:tcp:wallbox "Alfen Wallbox" [host = "XXX.XXX.XXX.XX", port=502, id=200] {
Bridge poller wb_status [start=1100, length=5, refresh=60000, type="holding"] {
Thing data WB_MaxLadestrom_Station [readStart="1100", readValueType="float32"]
Thing data WB_Temperatur [readStart="1102", readValueType="float32"]
// Thing data WB_Status_OCPP [readStart="1104", readValueType="uint16"]
// Anzahl Sockets --> Wallbox hat nur einen Ausgang
}
// SCN Register: Nur relevant für Smart Charging Network (Mehrere Wallboxen direkt miteinander per Bus verbunden)
}
Bridge modbus:tcp:wallboxsocket "Alfen Wallbox" [host = "192.168.178.57", port=502, id=1] {
Bridge poller wb_leistungsmessung [start=300, length=94, refresh=5000, type="holding"] {
//Name der Wallbox
//Thing data WB_Energiemessung_Status [readStart="300", readValueType="uint16"]
//Thing data WB_Energiemessung_Update [readStart="301", readValueType="uint64"]
//Thing data WB_Energiemessung_Typ [readStart="305", readValueType="uint16"]
Thing data WB_Spannung_L1 [readStart="306", readValueType="float32"]
Thing data WB_Spannung_L2 [readStart="308", readValueType="float32"]
Thing data WB_Spannung_L3 [readStart="310", readValueType="float32"]
Thing data WB_Strom_L1 [readStart="320", readValueType="float32"]
Thing data WB_Strom_L2 [readStart="322", readValueType="float32"]
Thing data WB_Strom_L3 [readStart="324", readValueType="float32"]
Thing data WB_Strom_Gesamt [readStart="326", readValueType="float32"]
Thing data WB_Frequenz [readStart="336", readValueType="float32"]
Thing data WB_Leistung_L1 [readStart="338", readValueType="float32"]
Thing data WB_Leistung_L2 [readStart="340", readValueType="float32"]
Thing data WB_Leistung_L3 [readStart="342", readValueType="float32"]
Thing data WB_Leistung_Gesamt [readStart="344", readValueType="float32"]
//Thing data WB_Arbeit_Geliefert_L1 [readStart="362", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
//Thing data WB_Arbeit_Geliefert_L2 [readStart="366", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
//Thing data WB_Arbeit_Geliefert_L3 [readStart="370", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
//Thing data WB_Arbeit_Geliefert_Gesamt [readStart="374", readValueType="int64"]
Thing data WB_Arbeit_Geliefert_Gesamt_1 [readStart="374", readValueType="uint16"]
Thing data WB_Arbeit_Geliefert_Gesamt_2 [readStart="375", readValueType="uint16"]
Thing data WB_Arbeit_Geliefert_Gesamt_3 [readStart="376", readValueType="uint16"]
Thing data WB_Arbeit_Geliefert_Gesamt_4 [readStart="377", readValueType="uint16"]
//Thing data WB_Arbeit_Bezogen_L1 [readStart="378", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
//Thing data WB_Arbeit_Bezogen_L2 [readStart="382", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
//Thing data WB_Arbeit_Bezogen_L3 [readStart="386", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
//Thing data WB_Arbeit_Bezogen_Gesamt [readStart="390", readValueType="int64"] //Reserviert, gibt kein Wert zurück (nur NaN)
}
Bridge poller wb_statusundkonfig [start=1200, length=16, refresh=2500, type="holding"] {
Thing data WB_Status_Ausgang [readStart="1200", readValueType="uint16"]
Thing data WB_Status_Mode3_1 [readStart="1201", readValueType="uint16"]
Thing data WB_Status_Mode3_2 [readStart="1202", readValueType="uint16"]
Thing data WB_Status_Mode3_3 [readStart="1203", readValueType="uint16"]
Thing data WB_Status_Mode3_4 [readStart="1204", readValueType="uint16"]
Thing data WB_Status_Mode3_5 [readStart="1205", readValueType="uint16"]
Thing data WB_MaxLadestrom_Aktiv [readStart="1206", readValueType="float32"]
Thing data WB_MaxLadestrom_Timeout [readStart="1208", readValueType="uint32"]
Thing data WB_MaxLadestrom_Vorgabe [readStart="1210", readValueType="float32", writeStart="1210", writeType="holding", writeValueType="float32"]
Thing data WB_AnzahlPhasen [readStart="1215", readValueType="int16", writeStart="1215", writeType="holding", writeValueType="int16"]
}
}
Number WB_MaxLadestrom_Station "Max. Ladestrom [%.1f A]" { channel="modbus:data:wallbox:wb_status:WB_MaxLadestrom_Station:number" }
Number WB_Temperatur "Temperatur [%.1f °C]" <temperature> { channel="modbus:data:wallbox:wb_status:WB_Temperatur:number" }
Number WB_Auto "Auto [%s]" // 1=Cupra Born, (2=Zweitwagen), 3=Sonstige, 4=Geschäft
//Number WB_Energiemessung_Status "Status Energiemessung [%s]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Energiemessung_Status:number" }
//Number WB_Energiemessung_Update "Energiem. letzes Update [%ms]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Energiemessung_Update:number" }
//Number WB_Energiemessung_Typ "Energiemessung Typ/Quelle [%s]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Energiemessung_Typ:number" }
Number WB_Strom_L1 "Ladestrom L1 [%.1f A]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Strom_L1:number" }
Number WB_Strom_L2 "Ladestrom L2 [%.1f A]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Strom_L2:number" }
Number WB_Strom_L3 "Ladestrom L3 [%.1f A]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Strom_L3:number" }
Number WB_Strom_Gesamt "Ladestrom [%.1f A]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Strom_Gesamt:number" }
Number WB_Leistung_Gesamt "Ladeleistung [%.0f W]" <energy> { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Leistung_Gesamt:number" }
Number WB_Arbeit_Geliefert_Gesamt "Ladeenergie Gesamt [%.1f kWh]"
Number WB_Arbeit_Geliefert_Gesamt_1 "Arbeit geliefert - Hilfszelle [%s]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Arbeit_Geliefert_Gesamt_1:number" }
Number WB_Arbeit_Geliefert_Gesamt_2 "Arbeit geliefert - Hilfszelle [%s]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Arbeit_Geliefert_Gesamt_2:number" }
Number WB_Arbeit_Geliefert_Gesamt_3 "Arbeit geliefert - Hilfszelle [%s]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Arbeit_Geliefert_Gesamt_3:number" }
Number WB_Arbeit_Geliefert_Gesamt_4 "Arbeit geliefert - Hilfszelle [%s]" { channel="modbus:data:wallboxsocket:wb_leistungsmessung:WB_Arbeit_Geliefert_Gesamt_4:number" }
String WB_Status "Status [%s]" <status>
Number WB_Status_Ausgang "Status [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_Status_Ausgang:number", expire="5m,state=2" }
String WB_Status_Mode3 "Status Mode 3 [%s]"
Number WB_Status_Mode3_1 "Status Mode 3 - Register 1 [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_Status_Mode3_1:number" }
Number WB_Status_Mode3_2 "Status Mode 3 - Register 2 [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_Status_Mode3_2:number" }
Number WB_Status_Mode3_3 "Status Mode 3 - Register 3 [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_Status_Mode3_3:number" }
Number WB_Status_Mode3_4 "Status Mode 3 - Register 4 [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_Status_Mode3_4:number" }
Number WB_Status_Mode3_5 "Status Mode 3 - Register 5 [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_Status_Mode3_5:number" }
Number WB_Lademodus "Lademodus [%s]" <settings> // 1=PV, 2=Zeitvorgabe, 3= 50 %, 3=100 %
Number WB_MaxLadestrom_Aktiv "Max. Ladestrom (Aktiv) [%.1f A]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_MaxLadestrom_Aktiv:number" }
Number WB_MaxLadestrom_Timeout "Max. Ladestrom Timeout [%.0f s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_MaxLadestrom_Timeout:number" }
Number WB_MaxLadestrom_Vorgabe "Max. Ladestrom [%.1f A]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_MaxLadestrom_Vorgabe:number" }
Number WB_AnzahlPhasen "Anzahl Phasen [%s]" { channel="modbus:data:wallboxsocket:wb_statusundkonfig:WB_AnzahlPhasen:number" }
rule "String zusammen setzen - Mode 3"
when
Item WB_Status_Mode3_1 changed
then
Thread::sleep(50)
var Int1_1 = ((WB_Status_Mode3_1.state as DecimalType).intValue())/256
var Int1_2 = ((WB_Status_Mode3_1.state as DecimalType).intValue()) - Int1_1 * 256
var String Mode3_String = String::valueOf(Character::toChars(Int1_1))
if (Int1_2 != 0) Mode3_String = Mode3_String + String::valueOf(Character::toChars(Int1_2))
//logInfo("Wallbox: Mode3-String", "Mode3_String: " + Mode3_String + ", Länge Mode3_String: " + Mode3_String.length)
WB_Status_Mode3.postUpdate(Mode3_String)
end
rule "Wallbox Statusstring"
when
Item WB_Status_Ausgang received update or
Item WB_Status_Mode3 changed or
Time cron "0 0 0 * * ?" // Status nicht betriebsbereit ist sonst nicht zuverlässig gesetzt
then
var String Ausgabe
if (WB_Status_Ausgang.state != 1) Ausgabe = "Nicht betriebsbereit"
else {
// Mode 3: Siehe ACE Service Installer und https://tff-forum.de/t/ladestatus-mode-3-nach-iec-62196-1-iec-61851/83576
var String Mode3_String = WB_Status_Mode3.state
if (Mode3_String == "A") Ausgabe = "Nicht eingesteckt"
else if (Mode3_String == "B1") Ausgabe = "Eingesteckt (kein PWM)"
else if (Mode3_String == "B2") Ausgabe = "Eingesteckt"
else if (Mode3_String == "C1") Ausgabe = "Auto nicht bereit zum Laden"
else if (Mode3_String == "C2") Ausgabe = "Ladevorgang läuft"
else if (Mode3_String == "D1") Ausgabe = "Auto nicht bereit zum Laden"
else if (Mode3_String == "D2") Ausgabe = "Ladevorgang läuft, Belüftung erforderlich"
else if (Mode3_String == "E") Ausgabe = "Kein Kabel angeschlossen"
else if (Mode3_String == "F") Ausgabe = "Fehler"
else Ausgabe = "Code: " + Mode3_String
}
WB_Status.postUpdate(Ausgabe)
end
rule "Umwandlung Wert: Arbeit_Gesamt"
when
Item WB_Arbeit_Geliefert_Gesamt_1 received update
then
// https://babbage.cs.qc.cuny.edu/ieee-754.old/64bit.html
// https://babbage.cs.qc.cuny.edu/IEEE-754/
// https://en.wikipedia.org/wiki/Double-precision_floating-point_format
// https://de.wikipedia.org/wiki/IEEE_754
// https://community.openhab.org/t/serial-port-and-pulse-counter-byte-array-little-endian-to-double-precision/24782/15
Thread::sleep(50)
var int1 = WB_Arbeit_Geliefert_Gesamt_1.state as Number
var int2 = WB_Arbeit_Geliefert_Gesamt_2.state as Number
var int3 = WB_Arbeit_Geliefert_Gesamt_3.state as Number
var int4 = WB_Arbeit_Geliefert_Gesamt_4.state as Number
var int1_hex = Integer::toHexString(int1.intValue)
var int2_hex = Integer::toHexString(int2.intValue)
var int3_hex = Integer::toHexString(int3.intValue)
var int4_hex = Integer::toHexString(int4.intValue)
while (int1_hex.length < 4) int1_hex = "0" + int1_hex
while (int2_hex.length < 4) int2_hex = "0" + int2_hex
while (int3_hex.length < 4) int3_hex = "0" + int3_hex
while (int4_hex.length < 4) int4_hex = "0" + int4_hex
var hex_komplett = String::format(int1_hex + int2_hex + int3_hex + int4_hex)
//logInfo("Float64 konvertieren", "Hex-String: " + hex_komplett)
var hex_vorzexp = hex_komplett.substring(0, 3)
var hex_sig = hex_komplett.substring(3, hex_komplett.length)
//logInfo("Float64 konvertieren", "Geteilter Hex-String: Erste 3 Zeichen (Vorzeichen + Exponent): " + hex_vorzexp + ", Rest (Signifikant): " + hex_sig)
var dec_vorzexp = new DecimalType(Integer.parseInt(hex_vorzexp, 16))
var dec_sig = new DecimalType(Long.valueOf(hex_sig, 16).longValue())
//logInfo("Float64 konvertieren", "Vorzeichen + Exponent als Dezimalwert: " + dec_vorzexp + ", Signifikant (roh-Wert): " + dec_sig)
var bin_vorzexp = Integer::toBinaryString(dec_vorzexp.intValue)
//logInfo("Float64 konvertieren", "Vorzeichen + Exponent als Binärwert: " + bin_vorzexp)
var vorz = 0
var double dec_exp = 0
if (bin_vorzexp.substring(0, 1) == "1" && bin_vorzexp.length == 12) {
vorz = -1
dec_exp = (dec_vorzexp - Math.pow(2, bin_vorzexp.length - 1)).doubleValue
}
else {
vorz = 1
dec_exp = (dec_vorzexp).doubleValue
}
//logInfo("Float64 konvertieren", "Vorzeichen: " + vorz + ", Exponent (roh-Wert): " + dec_exp)
var sig = (1 + (dec_sig / Math.pow(2,52)))
//logInfo("Float64 konvertieren", "Signifikant: " + sig)
var double exp = dec_exp - 1023
//logInfo("Float64 konvertieren", "Exponent: " + exp)
var ergebnis = vorz * sig * Math.pow(2, exp)
//logInfo("Float64 konvertieren", "Wert: " + ergebnis)
//logInfo("Float64 konvertieren", "Wert (formatiert): " + String::format("%1$.3f", ergebnis))
WB_Arbeit_Geliefert_Gesamt.postUpdate(ergebnis / 1000)
end