How to write one value to multiple registers simultaneously

Hi,

i have a rule for my wallbox that sets the maximum current the car can charge with. The Modbus thing of that looks like this:

Bridge modbus:tcp:ebox [ host="192.168.0.99", port=502 ]  {
   Bridge poller holdingRegisters [ start=1012, length=17, refresh=5000, type="holding" ] {
      Thing data maxCurrentP1 [ readStart="1012", readValueType="float32", writeStart="1012", writeValueType="float32", writeType="holding" ]
      Thing data maxCurrentP2 [ readStart="1014", readValueType="float32", writeStart="1014", writeValueType="float32", writeType="holding" ]
      Thing data maxCurrentP3 [ readStart="1016", readValueType="float32", writeStart="1016", writeValueType="float32", writeType="holding" ]
   }

   Bridge poller inputRegisters [ start=1006, length=6, type="input", refresh=5500] {
      Thing data currentP1 [ readStart="1006", readValueType="float32" ]
      Thing data currentP2 [ readStart="1008", readValueType="float32" ]
      Thing data currentP3 [ readStart="1010", readValueType="float32" ]
   }
}

I want to set maxCurrent for P1-P3 simultaniously. When i try to set them seperately strange things happen, guess due to parallell writing of values. So i want to set them all with one transaction.

I think i saw a property related to that: writeMultipleEvenWithSingleRegisterOrCoil but i’m not sure how to use it.

For example in my rule i want to call this:

maxCurrent.sendCommand(12); // set max current to 12A

If i call

maxCurrentP1.sendCommand(12)
maxCurrentP2.sendCommand(12)
maxCurrentP3.sendCommand(12)

the above mentioned strange things happen, so how can i do it, that i write those 3 registers in one go?

Thanks in advance!

Samuel

I don’t know if you can enforce that but I doubt it.
But this is an XY problem. It is highly unlikely that whatever you see is happening because of single-writes (vulgo: that it would disappear when you did in parallel).
Of course there’s an impact on P2 and P3 when you set P1 - that’s inherent to the electrics involved.
Possibly you are using a wrong parameter that is not intended for this purpose. Or you have to wait a couple of seconds for the box to sort command impacts out.

If I send them all individually it works, but if I send them too often or all 3 at once I get timeouts on console, so my assumption is that the modbus communication is busy somehow.

I saw in a python script that people send multiple register in one go so I thought it was possible here too.

Fairly new to modbus so I do not know all the limitations yet.

Each command to a Modbus channel fires off a write cycle, there is no way to batch up openHAB commands.

The binding will already be implementing ‘multiple write’ (i.e. using Modbus FC16) because a 32-bit value comprises multiple standard 16-bit registers.

There isn’t a writeValueType="float96" or anything that currently allows bigger blocks to be written by this binding.
But as Markus says, probably not the fix anyway.

Maybe the mystery device docs offer a clue. Are you supposed to halt it before changing these? Or does changing one cause a halt, so that it won’t accept another for a while?

The obvious thing to do is a little rule that imitates that, with time delay.

rule "my demo"
when
   Item MasterMaxCurrent received command
then
   val newValue = receivedCommand as Number
   maxCurrentP1.sendCommand(newValue)
   createTimer(now.plusSeconds(5)) [ maxCurrentP2.sendCommand(newValue) ]
   createTimer(now.plusSeconds(10)) [ maxCurrentP3.sendCommand(newValue) ]
end

Actually the device takes the lowest of the three currents. So if P1 is 6A, P2/P3 are 16A, it will set 6A on all phases, even if P2/P3 are still on 16A. So no need to set all phases (except for the looks). I just learned that, so the timeout workaround could also be a solution i can take. But i guess i will just set one phase only and leave the others if there is no real need to change them.

I was just wondering about the many timeouts like this:

2021-08-26 23:21:55.839 [ERROR] [ing.ModbusSlaveConnectionFactoryImpl] - re-connect reached max tries 1, throwing last error: Connection refused (Connection refused). Connection TCPMasterConnection@
1ea786f[socket=Socket[unconnected]]. Endpoint ModbusTCPSlaveEndpoint@f576f7[address=192.168.0.99,port=502]
2021-08-26 23:21:55.839 [ERROR] [ing.ModbusSlaveConnectionFactoryImpl] - Error connecting connection TCPMasterConnection@1ea786f[socket=Socket[unconnected]] for endpoint ModbusTCPSlaveEndpoint@f576f
7[address=192.168.0.99,port=502]: Connection refused (Connection refused)

I also get them when i have for example two pollers with refresh=5000. So i was wondering if i did something wrong and that is why i wanted to send all 3 registers in one go. But it seems there is another underlying problem with those timeouts.

The binding docs tell you howto get DEBUG logging for further diagnostics.
But I don’t think there’s much more to see with “Connection refused”.

Modbus slaves are entitled to say “Nope, I’m busy, go away”. There are neater ways to say that, but many Modbus slave implementations are uhhh crude and dirty.
If that’s the problem, there’s little you can apart from tuning your retry strategy perhaps.

But just as likely is that the slave is sluggish handling rapid TCP
connect/reconnect requests.
Recommended reading -

It is actually possible to write bulk of registers with single request using the “json write” functionality. It will be quite clunky, as the functionality is only available as a transformation so you would need a proxy String item glueing the P1 & P2 & P3 values together.

Probably worth investigating the reason for the connection issue(s) as advices above. Do you really need to write them at once or is the actual issue the connection issues you are seeing?

Hi @ssalonen
I have been sitting with a modbus problem for days, and I refused to accept an error in openHAB modbus binding. This is because I read many of your postings, and they seem very solid.

Finally, I identfied that my modbus hardware needs to have a minimum of 6 registers sent in the same transaction to actually react on the input. I used Wireshark and other trace apps to identify this.

So I need several holding registers to be sent in one transaction:
322: always 0
323: always 0
324: always 0
325: 1, 2, 3 or 4. The actual stuff we need to change, and this is stored in a openHAB item
326: always 0
327: always 0

If I send 325 alone nothing happens. Only the combination above works. Then I have looked at your suggestion with json to control the content being sent, but I am not sure how to do this with a transformation as you wrote in the documentation. If you could assist with an example, it will greatly appreciated.

Thanks in advance.

Yeah, there are so many weird devices…

The transformation should output json similar to below

[
    {
        "functionCode": 16,
        "address": 322,
        "value": [0, 0, 0, VALUE, 0, 0]
    }
]

VALUE should be the number from the command

In practice, one can use data thing’s writeTransformation with the following inline-JS transformation

JS(|"[{ \"functionCode\": 16, \"address\": 322, \"value\": [0, 0, 0, " + input + ", 0, 0] }]")

I have not tested this, hopefully it works with the binding

Thanks - this was very good and I adopted it with a few needed add-ons.
The line in my Thing file is

Thing data ThHCH5prmRomIdxSpeedLevel			"HCH5prmRomIdxSpeedLevel"							@ "Ventilat" [readStart="324", readValueType="uint16", readTransform="default", writeStart="324", writeValueType="int16", writeType="holding", writeTransform="JS(modbus_dantherm.js)", writeMultipleEvenWithSingleRegisterOrCoil="true", writeMaxTries="1"]

The transformation js file looks like this:

(function(value0) {
    var functionResult = {
        "functionCode": 16,
        "address": 322, 
        "value": [0,0,0,Number(value0),0,0]
    };
    return "[ " + JSON.stringify(functionResult)  + " ]";
})(input)

I had to convert the numeric input from a string to a number plus add [ and ] to avoid errors in the openhab log. However, when the results were reviewed with Modbus Poller tool it seems that all 8 rightmost bit are either always set to 1 or 0. Which means a value of either 255 or 0.

The Thing is connected to a Number type item, which has the value 1, 2, 3 or 4. Do you know, if I need to do some convert in the js file to send the correct bits to the register?

Thanks in advance.

Yeah, the transformation does look correct.

Some devices return different data when read, and that might be the case here. Protocol itself does not make any guarantees that after write you would get the same data bacl

Set TRACE level logging to org.openhab.core.io.transport.modbus (check docs for howto). This allows you to see written write request as hex string (there will be lot of logs, but search for “Going execute transaction with read request” - yes, there seems to be typo in logging - it says read request but you can note it is the write request as FC=16) .

You can decode the hex with Online Modbus RTU Parser & Modbus TCP Parser

Would JSON.stringify work in javascript?
Eample:

var PAYLOAD=(JSON.stringify({"humidity": humidity, "temperature": temperature, "pressure": pressure}))

Hi again
I never found out why all the rightmost bits were always 1 or 0. I traced this with Modbus Poller tool.

But I found out that only need to set one register to zero after the real register, so I ended up with this one, which works fine:

(function(value0) {
    var functionResult = {
        "functionCode": 16,
        "address": 324, 
        "value": [Number(value0), 0]
    };
    return "[ " + JSON.stringify(functionResult)  + " ]";
})(input)

Thanks for all your support.