Have to implement call to Digital IO with Modbus protocol on Spring Boot project build by Maven.
It should be a pulsed call with some duration at the body (like 5 seconds, etc.)
Here is a snippet from the specification:
And more about Response and Errors:
Seems at this call application should behave like a master. And Web Relay should be like a slave in this case.
I suppose that taking some library for integrating with Modbus will be much more preferable than writing it from zero.
Which approach will be preferable to adopt this functionality with Spring Boot?
Here are Web Relay manuals.
UPDATE:
Tried answer by KevinHerron
Here is the code part:
@Override
public void callDigitalIO(String ipAddress, String relay) {
log.debug("call Digital IO by MODBUS");
checkNotEmpty(ipAddress, relay);
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder(ipAddress).build();
ModbusTcpMaster master = new ModbusTcpMaster(config);
master.connect();
ByteBuf buffer = Unpooled.buffer();
buffer.writeInt(0x00003F00);
buffer.writeInt(0x000040A0);
int relayNum = Integer.parseInt(relay);
WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(
relayNum,
0x02 * relayNum,
buffer
);
log.debug("MODBUS_REQUEST: {}", request);
master.sendRequest(request, 0xFF)
.whenCompleteAsync((response, ex) -> {
if (response != null) {
log.info("MODBUS_RESPONSE: {}", response);
} else {
log.error("EXECUTION_FAILED: {}", ex.getMessage(), ex);
}
});
master.disconnect();
}
Tried below snippet with a real device, the output is following:
2021-02-25 22-07-03.955 [carpark-ex-4] DEBUG c.s.s.dio.ModbusDigitalIoServiceImpl - MODBUS_REQUEST: WriteMultipleRegistersRequest(UnpooledByteBufAllocator$InstrumentedUnpooledUnsafeHeapByteBuf(ridx: 0, widx: 8, cap: 256))
2021-02-25 22-07-03.970 [ForkJoinPool.commonPool-worker-5] ERROR c.s.s.dio.ModbusDigitalIoServiceImpl - EXECUTION_FAILED: not connected
java.lang.Exception: not connected
at com.digitalpetri.netty.fsm.ChannelFsmFactory.lambda$null$2(ChannelFsmFactory.java:115)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
at java.base/java.lang.Thread.run(Thread.java:832)
Only when I did:
master.sendRequest(request, 0xFF).get()
it started to work.
This should be easy to accomplish using an existing library that supports the WriteMultipleRegisters function.
Try https://github.com/digitalpetri/modbus
An example of how to construct a WriteMultipleRegisters request based on that screenshot of documentation:
class Scratch {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ModbusTcpMasterConfig config = new ModbusTcpMasterConfig.Builder("ip_or_hostname").build();
ModbusTcpMaster master = new ModbusTcpMaster(config);
master.connect().get();
ByteBuf buffer = Unpooled.buffer();
buffer.writeInt(0x00003F00);
buffer.writeInt(0x000040A0);
WriteMultipleRegistersRequest request = new WriteMultipleRegistersRequest(
0x16,
0x04,
buffer
);
master.sendRequest(request, 0xFF).get();
}
}
Could you explain more details about this call? Have it should be done, is it possible to set timeout to it
Updated. Time for you to start experimenting. Write code and try it out.
could you help to understand meaning of
unitId
?It's in the spec. It's called slave id when it's Modbus over serial. Your device documentation mentions just using 0xFF, which is commonly used when talking directly to the server and not to a slave behind a gateway. See modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf
could you clarify one more place -
Pulse Duration (4 bytes, per relay): 0x3DCCCCCC – 0x47A8C000 (Little-endian Format: 0xCCCC3DCC – 0xC00047A8)
- how exactly this duration should be set depends on relay number?