I think you should ask the railduino makers to add coil functions to their modbus implementation, in the interest of all their users. The way they do it now makes it awkward for any user, not just openHAB.
Assuming that isn’t going to happen soon, we’ll need to build a workaround.
We will use a Number Item to hold an “image” of the register in the slave, and allow individual Switch Items to set/reset bits in that image by openHAB commands.
When the image changes, we will write the whole register to Modbus.
Changed your poller thing for the relays
Bridge poller relayRegisters [ start=0, length=1, refresh=500, type="holding" ]
{
Thing data roAll [ readStart="0", readValueType="uint16", writeStart="0", writeValueType="uint16", writeType="holding", writeMultipleEvenWithSingleRegisterOrCoil=true]
Thing data ro01 [ readStart="0.0", readValueType="bit" ]
Thing data ro02 [ readStart="0.1", readValueType="bit" ]
Thing data ro03 [ readStart="0.2", readValueType="bit" ]
Thing data ro04 [ readStart="0.3", readValueType="bit" ]
Thing data ro05 [ readStart="0.4", readValueType="bit" ]
Thing data ro06 [ readStart="0.5", readValueType="bit" ]
}
This should read-poll the whole register representing the relays. And write it using FC16.
We keep the one-bit channels for each relay, but read-only, just to make it easier to update our Switch Items.
Now for some Items
Number ROALL "Relays register [%d]" { channel="modbus:data:rail2:relayRegisters:roAll:number", autoupdate="false" }
Group ROgroup
Switch RO01 "Relays index 1 [%s]" (ROgroup) { channel="modbus:data:rail2:relayRegisters:ro01:switch", autoupdate="false" }
Switch RO02 "Relays index 2 [%s]" (ROgroup) { channel="modbus:data:rail2:relayRegisters:ro02:switch", autoupdate="false" }
Switch RO03 "Relays index 3 [%s]" (ROgroup) { channel="modbus:data:rail2:relayRegisters:ro03:switch", autoupdate="false" }
Switch RO04 "Relays index 4 [%s]" (ROgroup) { channel="modbus:data:rail2:relayRegisters:ro04:switch", autoupdate="false" }
Switch RO05 "Relays index 5 [%s]" (ROgroup) { channel="modbus:data:rail2:relayRegisters:ro05:switch", autoupdate="false" }
Switch RO06 "Relays index 6 [%s]" (ROgroup) { channel="modbus:data:rail2:relayRegisters:ro06:switch", autoupdate="false" }
So we have a Number to represent our relays register, and linked some Switches to the read-only channels.
I’ve added autoupdate="false" to each Item to stop autoupdate interfering when we use commands.
Each of our Switches goes into a group, just to make it easier later.
At this stage, our Switch Items should show what state the railduino’s relays are in. But nothing happens when we ON/OFF them from openHAB - we need a rule to do that part.
import java.lang.Math // we need this for testBit
rule "update relay register"
when
Member of ROgroup received command
then
var BigInteger register = 0 // we need BigInteger to use testBit
if ( ROALL.state != NULL && ROALL.state != UNDEF) { // avoid invalid register
register = (ROALL.state as DecimalType).toBigDecimal.toBigInteger // use existing image
}
switch triggeringItem.name { // act on switched Item name
case "RO01" : {
if (receivedCommand = ON) {
register = register.setBit(0)
} else {
register = register.clearBit(0)
}
case "RO02" : {
if (receivedCommand = ON) {
register = register.setBit(1)
} else {
register = register.clearBit(1)
}
case "RO03" : {
if (receivedCommand = ON) {
register = register.setBit(2)
} else {
register = register.clearBit(2)
}
case "RO04" : {
if (receivedCommand = ON) {
register = register.setBit(3)
} else {
register = register.clearBit(3)
}
case "RO05" : {
if (receivedCommand = ON) {
register = register.setBit(4)
} else {
register = register.clearBit(4)
}
case "RO06" : {
if (receivedCommand = ON) {
register = register.setBit(5)
} else {
register = register.clearBit(5)
}
}
// at last, write to Modbus
ROALL.sendCommand(register.toString) // not sure you can send BigInt as a command
end
This is all untested, and I’m sure there are neater ways to write it.
It’s less than ideal because race conditions can arise if several commands or states happen very quickly. I would avoid sending commands to more than one switch at a time without a delay between.
Note this setup relies on everyone agreeing which end of the register is “bit 0” !!
Warning - if you send a non-ON/OFF command (like REFRESH) to any of the switches, it will clear that relay. Most people won’t be doing that, but I’m not sure if that might kick in at boot time. You could code round that if it is a problem by reworking bits else to else if