Modbus configuration for Wallbox Access

Hello, I am new to Openhab and would like to acces my Alfen Wallbox via Modbus TCP/IP.
Im struggeling with the configuration since I cannot find all the parameters which are described in the Wallbox interface description.
My System:

  • Respberry 4 with buster
  • Openhab 2.5.12
  • Modbus binding installed
  • Wallbox as Modbus Slave configured

In the description it says that I need a Slave-Address of 200 to access the data in the Wallbox

Where can I configure the salve adres 200 ?

My current coinfiguration looks like this:
→ I have no idea where to put the salve address 200?

Bridge modbus:tcp:wallbox “Alfen Wallbox” [host = “ip-adress”, port=502, id=1] {

    // holding register starten bei 40001--> 40101

    Bridge poller holding [start=100, length=17, refresh=5000, type="holding"] {

            //Name der Wallbox

            Thing data AlfenWallboxName1 [readStart="100", readValueType="int16"]

            Thing data AlfenWallboxName2 [readStart="102", readValueType="int16"]

            Thing data AlfenWallboxName3 [readStart="104", readValueType="int16"]

            Thing data AlfenWallboxName4 [readStart="106", readValueType="int16"]

            Thing data AlfenWallboxName5 [readStart="108", readValueType="int16"]

            Thing data AlfenWallboxName6 [readStart="110", readValueType="int16"]

    }

}

after reading the data I want to convert them into a string to display in Openhab
Following Items are defined for testing:

Number WallboxName1 “Wallbox Name [%d]” { channel=“modbus:data:wallbox:holding:AlfenWallboxName1:number” }
DateTime InputWalboxName1 “Input registers [%1$tA, %1$td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS]” { channel=“modbus:data:wallbox:holding:AlfenWallboxName1:lastReadSuccess” }

All data are empty, so it looks loike there is no communication to the Wallbox.
In the Paper UI the Walbox itme is green --< looks like the Binding has basic access to the wallbox ??

Any ideas ?

Bridge modbus:tcp:wallbox “Alfen Wallbox” [host = “ip-adress”, port=502, id=200] {

Look in your openhab.log for messages when you’ve fixed that.

It’s actually quite difficult to read bytes from Modbus registers and assemble them into an ASCII string. Do you really need to do that? Just seeing that you get the raw bytes is good enough toprove it works, and you already know your device model, it’s not going to change ever.

Thanks for your help.
The id=200 was the solution.

The data are now reported. :slight_smile:

one other question:
do I have to read all data as a number?
for example I would like to display the date and time of the box directly in the sidemap and not as different single numbers :
Date: 21.03.2021
instead of
Day: 21
Month: 03
Year: 2021
Is there any possibility to put the data into a date string ?

It’s Modbus, everything comes in 16-bit chunks.

You can load your data into a selection of Items, and assemble those into some other combination Item in a rule.

Thansk for your help.

I have also float64 registers to read.
This seems not to be supported by the binding.
How can I read such registers from the Wallbox ?

That’s true. It won’t happen for OH2 now.
It’s hard to see how useful 64-bit floats really are outside of astronomy!

We’ve not really dealt with this before, a previous look died due to no follow up.

should be possible to get two uint32 from Modbus binding, and reassemble into the 64-bit image. Quite how you persuade java to take that as a double type I’m not sure.

Before you get that far, you’d need to determine what order the Alfen thingy puts the registers in.

Hello,
I managed to assemble the most things into a string to display in Openhab

Now I have still open, how to convert the uint16 values which contain 2 characters each.
I started spliiting it up into 2 8bit values → but I have no glue how to convert this decimal numbers into a character to put it into a string.
Already tried with type conversion as stated in Java, but this is not allowed in Openhab.
var int char = (char)number;

Then the final stage would be to assemble all characters into a string.

maybe someone has an idea.

Hello,
I have now converted my numbers into characters which can be displayed in Openhab:
Maybe not the best way, but it works :slight_smile:

in the rules file:
WallboxName.sendCommand(String::format("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(((WallboxName1.state as DecimalType).intValue())/256) as char,
(((WallboxName1.state as DecimalType).intValue())%256) as char,
(((WallboxName2.state as DecimalType).intValue())/256) as char,
(((WallboxName2.state as DecimalType).intValue())%256) as char,
(((WallboxName3.state as DecimalType).intValue())/256) as char,
(((WallboxName3.state as DecimalType).intValue())%256) as char,
(((WallboxName4.state as DecimalType).intValue())/256) as char,
(((WallboxName4.state as DecimalType).intValue())%256) as char,
(((WallboxName5.state as DecimalType).intValue())/256) as char,
(((WallboxName5.state as DecimalType).intValue())%256) as char,
(((WallboxName6.state as DecimalType).intValue())/256) as char,
(((WallboxName6.state as DecimalType).intValue())%256) as char,
(((WallboxName7.state as DecimalType).intValue())/256) as char,
(((WallboxName7.state as DecimalType).intValue())%256) as char,
(((WallboxName8.state as DecimalType).intValue())/256) as char,
(((WallboxName8.state as DecimalType).intValue())%256) as char,
(((WallboxName9.state as DecimalType).intValue())/256) as char,
(((WallboxName9.state as DecimalType).intValue())%256) as char
)
)

You haven’t given us much to work with here. Let’s assume you’re working in a DSL rule and have some integer values.
Manipulating bytes is always a pain in DSL rules. This feels clumsy, but seems to work.

var myInt = 65  // code for A
var nextInt = 97 // code for a
var myString = String::valueOf(Character::toChars(myInt)) + String::valueOf(Character::toChars(nextInt)))
// contains "Aa"

I have a question about the Modbus binding in regards to a Wallbox.

I got the ABB Terra AC 11kw Wallbox. According to the specification this wallbox can communicate over Modbus , ( ModBus-RTU-Bus-Master ).

What is the way to connect to openHAB if at all possible?

From what i read this needs a converter modbus rtu to tcp/ip, correct? The second question is, can a Modbus master communicate with openHab at all? From what i understand Master just do request informations or am i wrong.

Thanks for sharing some insights. I am pretty new to this, so sorry for these basic questions.

It seems unlikely a device like this will act as a master, but if that’s true then it will be difficult for you.

I think you may be looking at a port intended for the ABB to read from an external meter. That’s no good for general communication.

If you want to communicate with an serial RTU device over networked TCP, then yes you would need a gateway.

OpenHAB binding also supports RTU over wired serial directly e.g. via an RS485 USB dongle.

Not using the binding. You can write your own script and have that communicate with openHAB.

1 Like

From what Alfen manual did you take the picture?
On the Alfen website I do not find any pdf with the Modbus codes.

Do you mind sharing your poller things? If I am correct they all need to be created manually (using OH3.1) or are they being discovered by the Modbus binding?

I found the complete manual in the internet. Could also not find it on the Alfen Webside.

here you can find my poller things:
→ I am using still OH2.5

Bridge modbus:tcp:wallbox "Alfen Wallbox" [host = "192.168.xxx.xx", port=502, id=200] {
        // holding register starten bei 40001--> 40101
        Bridge poller productreg [start=100, length=79, refresh=60000, type="holding"] {
                //Name der Wallbox
                Thing data AlfenWallboxName1    [readStart="100", readValueType="int16"]
                Thing data AlfenWallboxName2    [readStart="101", readValueType="int16"]
                Thing data AlfenWallboxName3    [readStart="102", readValueType="int16"]
                Thing data AlfenWallboxName4    [readStart="103", readValueType="int16"]
                Thing data AlfenWallboxName5    [readStart="104", readValueType="int16"]
                Thing data AlfenWallboxName6    [readStart="105", readValueType="int16"]
                Thing data AlfenWallboxName7    [readStart="106", readValueType="int16"]
                Thing data AlfenWallboxName8    [readStart="107", readValueType="int16"]
                Thing data AlfenWallboxName9    [readStart="108", readValueType="int16"]
                Thing data AlfenWallboxName10    [readStart="109", readValueType="int16"]
                Thing data AlfenWallboxName11    [readStart="110", readValueType="int16"]
                Thing data AlfenWallboxName12    [readStart="111", readValueType="int16"]
                Thing data AlfenWallboxName13    [readStart="112", readValueType="int16"]
                Thing data AlfenWallboxName14    [readStart="113", readValueType="int16"]
                Thing data AlfenWallboxName15    [readStart="114", readValueType="int16"]
                Thing data AlfenWallboxName16    [readStart="115", readValueType="int16"]
                Thing data AlfenWallboxName17    [readStart="116", readValueType="int16"]
                Thing data AlfenWallboxManuf1    [readStart="117", readValueType="int16"]
                Thing data AlfenWallboxManuf2    [readStart="118", readValueType="int16"]
                Thing data AlfenWallboxManuf3    [readStart="119", readValueType="int16"]
                Thing data AlfenWallboxManuf4    [readStart="120", readValueType="int16"]
                Thing data AlfenWallboxManuf5    [readStart="121", readValueType="int16"]
                Thing data AlfenWallboxFirm1     [readStart="123", readValueType="int16"]
                Thing data AlfenWallboxFirm2     [readStart="124", readValueType="int16"]
                Thing data AlfenWallboxFirm3     [readStart="125", readValueType="int16"]
                Thing data AlfenWallboxFirm4     [readStart="126", readValueType="int16"]
                Thing data AlfenWallboxFirm5     [readStart="127", readValueType="int16"]
                Thing data AlfenWallboxFirm6     [readStart="128", readValueType="int16"]
                Thing data AlfenWallboxFirm7     [readStart="129", readValueType="int16"]
                Thing data AlfenWallboxFirm8     [readStart="130", readValueType="int16"]
                Thing data AlfenWallboxFirm9     [readStart="131", readValueType="int16"]
                Thing data AlfenWallboxFirm10    [readStart="132", readValueType="int16"]
                Thing data AlfenWallboxFirm11    [readStart="133", readValueType="int16"]
                Thing data AlfenWallboxFirm12    [readStart="134", readValueType="int16"]
                Thing data AlfenWallboxFirm13    [readStart="135", readValueType="int16"]
                Thing data AlfenWallboxFirm14    [readStart="136", readValueType="int16"]
                Thing data AlfenWallboxFirm15    [readStart="137", readValueType="int16"]
                Thing data AlfenWallboxFirm16    [readStart="138", readValueType="int16"]
                Thing data AlfenWallboxFirm17    [readStart="139", readValueType="int16"]
                Thing data AlfenWallboxPlat1     [readStart="140", readValueType="int16"]
                Thing data AlfenWallboxPlat2     [readStart="141", readValueType="int16"]
                Thing data AlfenWallboxPlat3     [readStart="142", readValueType="int16"]
                Thing data AlfenWallboxPlat4     [readStart="143", readValueType="int16"]
                Thing data AlfenWallboxPlat5     [readStart="144", readValueType="int16"]
                Thing data AlfenWallboxPlat6     [readStart="145", readValueType="int16"]
                Thing data AlfenWallboxPlat7     [readStart="146", readValueType="int16"]
                Thing data AlfenWallboxPlat8     [readStart="147", readValueType="int16"]
                Thing data AlfenWallboxPlat9     [readStart="148", readValueType="int16"]
                Thing data AlfenWallboxPlat10    [readStart="149", readValueType="int16"]
                Thing data AlfenWallboxPlat11    [readStart="150", readValueType="int16"]
                Thing data AlfenWallboxPlat12    [readStart="151", readValueType="int16"]
                Thing data AlfenWallboxPlat13    [readStart="152", readValueType="int16"]
                Thing data AlfenWallboxPlat14    [readStart="153", readValueType="int16"]
                Thing data AlfenWallboxPlat15    [readStart="154", readValueType="int16"]
                Thing data AlfenWallboxPlat16    [readStart="155", readValueType="int16"]
                Thing data AlfenWallboxPlat17    [readStart="156", readValueType="int16"]
                Thing data AlfenWallboxSerN1     [readStart="157", readValueType="int16"]
                Thing data AlfenWallboxSerN2     [readStart="158", readValueType="int16"]
                Thing data AlfenWallboxSerN3     [readStart="159", readValueType="int16"]
                Thing data AlfenWallboxSerN4     [readStart="160", readValueType="int16"]
                Thing data AlfenWallboxSerN5     [readStart="161", readValueType="int16"]
                Thing data AlfenWallboxSerN6     [readStart="162", readValueType="int16"]
                Thing data AlfenWallboxSerN7     [readStart="163", readValueType="int16"]
                Thing data AlfenWallboxSerN8     [readStart="164", readValueType="int16"]
                Thing data AlfenWallboxSerN9     [readStart="165", readValueType="int16"]
                Thing data AlfenWallboxSerN10    [readStart="166", readValueType="int16"]
                Thing data AlfenWallboxSerN11    [readStart="167", readValueType="int16"]
                Thing data AlfenWallboxYear     [readStart="168", readValueType="int16"]
                Thing data AlfenWallboxMonth    [readStart="169", readValueType="int16"]
                Thing data AlfenWallboxDay      [readStart="170", readValueType="int16"]
                Thing data AlfenWallboxHour     [readStart="171", readValueType="int16"]
                Thing data AlfenWallboxMin      [readStart="172", readValueType="int16"]
                Thing data AlfenWallboxSec      [readStart="173", readValueType="int16"]
                Thing data AlfenWallboxUpT      [readStart="174", readValueType="uint64", readTransform="JS(divide1000.js)"]
                Thing data AlfenWallboxUTCOff   [readStart="178", readValueType="int16"]
        }

        Bridge poller StationReg [start=1100, length=5, refresh=60000, type="holding"] {
                //special topics
                Thing data AlfenWallboxMaxCurrent       [readStart="1100", readValueType="float32"]
                Thing data AlfenWallboxTemp             [readStart="1102", readValueType="float32"]
                Thing data AlfenWallboxOCPP             [readStart="1104", readValueType="uint16"]
                // Nr of Sockets --> only single Wallbox
        }
    }

Bridge modbus:tcp:wallboxsocket "Alfen Wallbox" [host = "192.168.xxx.xx", port=502, id=1] {

          Bridge poller VoltCurrentPow [start=306, length=44, refresh=5000, type="holding"] {
                //Name der Wallbox
                Thing data AlfenWallboxVL1      [readStart="306", readValueType="float32"]
                Thing data AlfenWallboxVL2      [readStart="308", readValueType="float32"]
                Thing data AlfenWallboxVL3      [readStart="310", readValueType="float32"]
                Thing data AlfenWallboxIL1      [readStart="320", readValueType="float32"]
                Thing data AlfenWallboxIL2      [readStart="322", readValueType="float32"]
                Thing data AlfenWallboxIL3      [readStart="324", readValueType="float32"]
                Thing data AlfenWallboxISum     [readStart="326", readValueType="float32"]
                Thing data AlfenWallboxFreq     [readStart="336", readValueType="float32"]
                Thing data AlfenWallboxPL1      [readStart="338", readValueType="float32"]
                Thing data AlfenWallboxPL2      [readStart="340", readValueType="float32"]
                Thing data AlfenWallboPIL3      [readStart="342", readValueType="float32"]
                Thing data AlfenWallboxPSum     [readStart="344", readValueType="float32"]
        }
    }

Thanks, much appreciated!
Regarding the manual, quite easy, you have to email Alfen nd then they email it to you.

Apparently, I cannot use modbus and P1 together. Since my smart meter only supports P1, I had to look for another method to read the data.
Nick Douma created an excellent and easy to use python script for this. See Alfen-Eve
Would be great if some skilled programmer could make an Alfen binding out of this :wink:

Hi together,

Can someone share a ready-to-use Things definition for the Alfen wallbox in conjunction with OH3.X in the meanwhile? In best case combined with an Items file :slight_smile: .

They already did

You are right. It should work for OH3 in the same way.

However, the registers for the real energy delivered and consumed are missing (362 … 390) as well as all the status and transaction registers (1200 … 1215).

Apart from that, I thought, that someone created may also the corresponding Items file as well as Rules for e.g. putting the Strings for the wallbox name, firmware, etc. together.

Last but not least, when I look to the registers, I wonder how the real energy delivered and consumed is counting up. Is it a total counter over the lifetime? Or does it start from 0 for each charging cycle? (I don´t have the wallbox yet. I will receive it within the next days and then install it. So I can´t try it out yet.)

Personally, I would also like to realize an energy counter which sums up the consumed energy per day to incorporate it into my other daily energy counters and statistic.

Furthermore, I would like to distinguish the energy used by car, e.g., based on the RFID card which has been used for starting the charging session. Thereby I would like to distinguish whether the personal car or may a car from friends, parents or any other person has been charged. But as it looks to me, that can´t be read out from the wallbox.

I just want to ask if anybody has already worked on topics like that. If not, I will start to work on it sooner or later…

Has anybody solved this challenge already?

Dear Bernd,
I digged into the challenge of converting the Float64 values. And I think I actually succeeded. I can only not try it out practically yet as I miss a car to charge.

May you like to try the following code for converting the Float64 values? You have to read the registers as single int16 and provide the number to int1 … int4.

// 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

                                                            // Wallbox neu      // Ergebnis 112.34      // Ergebnis -1512.78    // Ergebnis 0
var int1 = WB_Energie_Geliefert_Gesamt_1.state as Number    // 16422            // 16476 (405C)         // 49303 (C097)         // 0
var int2 = WB_Energie_Geliefert_Gesamt_2.state as Number    // 0                // 5570  (15C2)         // 41758 (A31E)         // 0
var int3 = WB_Energie_Geliefert_Gesamt_3.state as Number    // 0                // 36700 (8F5C)         // 47185 (B851)         // 0
var int4 = WB_Energie_Geliefert_Gesamt_4.state as Number    // 0                // 10486 (28F6)         // 60293 (EB85)         // 0

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 = int1_hex + "0"
while (int2_hex.length < 4) int2_hex = int2_hex + "0"
while (int3_hex.length < 4) int3_hex = int3_hex + "0"
while (int4_hex.length < 4) int4_hex = int4_hex + "0"

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))

ergebnis = ergebnis / 1000

WB_Energie_Geliefert_Gesamt.postUpdate(ergebnis)
2 Likes