How to read data as Modbus RTU master and serve it as Modbus/TCP slave?

I’m reading data as Modbus RTU master and I need to serve it as Modbus/TCP slave.

I think I could use the custom register blockm but I don’t know how to write the information read as Modbus RTU master to the file /tmp/regfile.

Any alternative solution?

Thanks in advance.

Hello,

In your case, I would suggest a simpler solution - using Modbus TCP over Serial Gateway. This will allow you to send Modbus TCP requests to your router, which will then translate TCP to RTU and redirect the request to your serial Modbus Slave. Essentially, this would allow you to access Modbus RTU slave via Modbus TCP. You can find more information on this functionality on our wiki page here.

Kind Regards,

I have several Modbus RTU devices attached to a RS485 bus, so I need to read from several slaves and serve these data as Modbus/TCP. The router RUT955 should work as a gateway in this case.

I’m open to different solutions: mqtt, Modbus/TCP, … anything that allows to concentrate data from several slaves.

Hi,

Well, with serial gateway the device acts as a gateway. It receives Modbus TCP requests sent to the router, interprets these requests, and then communicates with the Modbus RTU slaves to retrieve the requested data. Once it has the data, it sends this information back in response to the original Modbus TCP request. So in both cases, you send Modbus TCP requests to the router.

If you are looking to concentrate all the data from different slaves, then I assume you need to collect this data (no need to set registers). Correct?

If so, what about the data to server functionality? You can collect all the data from your Modbus slave devices and send it to the server over HTTP or MQTT in JSON format. This would probably be the best option.

MQTT Gateway can also be used, but this would be similar to Serial Gateway with the main difference that MQTT is used instead of Modbus. So you will need to send MQTT messages that will be translated to Modbus RTU and sent to the Modbus slaves.

Kind Regards,

Correct, that’s right.

In fact, I’m using Mosquitto on a RBPi and it works (I’m publishing values from another device), but I have configured a RUT955 as Publisher but nothing appears on Mosquitto.
How can I publish the read Modbus data on Mosquitto ?

Thanks in advance.

Hi,

There no need to configure MQTT publisher in this case. Simply configure ‘Data to Server’. Select Modbus as the data source, MQTT as the protocol, enter the JSON format, and fill in the rest of the settings according to your needs. Though, you need to have Modbus Serial Master configured with the requests on the device. Data from these requests is stored in the database and is periodically sent by ‘Data to Server’.

Kind Regards,

I’m following this example but no luck: How can I get Modbus data on the local or a remote MQTT broker

This is my setup:

  • RUT955 configured as Modbus/TCP slave and master. The router is reading registers 42 (name) and 2 (uptime) every 10 seconds. I’m using “TEST” button to check that these values are read.
  • Data to Server:
    Enable: On
    Name: test
    Data source: Modbus data
    Protocol: MQTT
    JSON format: {“ID”:“%i”,“TS”:“%t”,“ST”:“%s”,“VR”:%a}
    Segment count: 1
    Send as object: off
    URL / Host / Connection string: Mosquitto_server_IP → also tested with local RUT955 MQTT broker, but same result
    Port: 1883
    Keepalive: 60
    Topic: /router
    Client ID:
    Period: 10
    QoS: 0
    Data filtering: All data

Unfortunately, MQTT explorer is not showing the topic “/router”, where is the problem?

I think it would be much easier to map the collected Modbus data to the custom register block, avoiding external protocols as MQTT, but it’s not currently possible.

Edit:

  1. ssh on RUT955:
    root@RUT955:~# netstat -ptan | grep 204
    tcp 0 0 192.168.9.137:55350 192.168.9.204:1883 ESTABLISHED 6452/modbus_data_se

  2. /var/log/mosquitto/mosquitto.log on RBPi

    1689104184: New client connected from 192.168.9.137:36806 as auto-5AB8F07C-880F-7C71-F946-2566DB8901A4 (p2, c1, k60).
    1689104247: Client mqtt-explorer-6a4a20db disconnected.
    1689104248: New connection from 192.168.9.20:36748 on port 1883.
    1689104248: New client connected from 192.168.9.20:36748 as mqtt-explorer-6a4a20db (p2, c1, k60).
    1689104346: Client auto-5AB8F07C-880F-7C71-F946-2566DB8901A4 closed its connection.
    1689104347: New connection from 192.168.9.137:60968 on port 1883.
    1689104347: New client connected from 192.168.9.137:60968 as auto-11A6DD36-3326-B0C1-FDD3-F681850BCCB2 (p2, c1, k60).
    1689104438: Client auto-11A6DD36-3326-B0C1-FDD3-F681850BCCB2 has exceeded timeout, disconnecting.
    1689104551: New connection from 192.168.9.137:55350 on port 1883.
    1689104551: New client connected from 192.168.9.137:55350 as auto-179ED496-8F77-0F97-626D-04A48F22EF95 (p2, c1, k60).

But no data is pushed to Mosquitto.

Thanks in advance.

Hi,

Have you enabled Modbus Master and Requests in the Modbus TCP Master?

Kind Regards,

Thanks! It works now!

When I first read your reply, I entered to the router’s web from my phone and the radio buttons displayed properly, they made sense. When I accessed from a laptop, they shown in a confusing way, now it works like a charm:

I’m going to try reading this data from my SCADA.

I think it would be much easier to map the collected Modbus data to the custom register block, it’s the natural way.

Thanks for you excellent support!!

Hi,

I am having similar kind of problem. I want to read modbus data from slave device and publsh data to MQTT server. I am facing issue of decoding/degrouping of modbus address values. Can you please help with the same?

i.e. actual flow = value of 400001 address
pressure = value of 400007 address

I am not able to configure the above. By default the router is giving values like [2345], [3567] values as per the data sender segment configuration. Can we specify the same?

  1. Read data from devices configuring the option “MODBUS serial master” or “MODBUS TCP master”, depending on your architecture

  2. Use the option “Data to server” to write your MODBUS data to a MQTT broker

Please, upload a screenshot with your MODBUS requests configuration, I understand:

  • you should use the message “Read holding registers”
  • 400001 should be “1” or “0”, try to find the right register number
  • 400007 should be “7” or “6”, try to find the right register number
  1. We have used modbus TCP master.
  2. We have also used data server.

Router is sending both addresses values to the server. i.e. By writing “%a” in the jason format we get [2345], [3456] (register data) sequentially.

Whereas requirement is
actual flow = value of 40001 address
pressure = value of 40007 address.

I want to dedicate specific register values against specific string as mentioned in above thread. Hope i am able to make you understand the issue.

How can i access root? what is ubus command? I am new to it. I have read in some threads that we can call specific address/bit values using root and ubus command. How can i do that?

i am not facing any issue in data sending. Just want to extract register values as against specific string/texts.

Hello,

Modbus registers are 2 bytes long (16 bit). In the Modbus Master configuration, when you configure requests, you can specify the data type of how that register is presented. For this, you would need to refer to the modbus documentation of your Modbus Slave device to find out what data type to use (Byte order). This is applicable for each individual request.

Now for the format of the message as a whole, if you want to receive data as follows:

"request_name":"value"

Then, in Data to Server configuration, use the following JSON format:

{"%r":"%a"}

“%r” will be the request name from Modbus Master request configuration, and “%a” will be the modbus register value in a format that you set in the request configuration as well. You can either keep or remove quotes and brackets (square brackets for each request can be removed in Modbus Master configuration by enabling the ‘brackets’ option for requests).

Kind Regards,

{
“version” : “1.0”,
“onlinetag” : “06171422010486”,
“time” : %t,
“payload” : [ {
“subDeviceId” : “ttyCOM1_2”,
“deviceType” : “Modbus_2”,
“status” : {
“ActualFlow” : “Value of respective Modbus register address to be displayed here”,
“TotalFlow” : “Value of respective Modbus register address to be displayed here”,
“InsDiagnostic” : “Value of respective Modbus register address to be displayer here”,
“timestamp” : %t
}
} ]
}

i want to display user defined register values against actual flow/totalflow/InstDiagnostic strings…

Due to limitation of replies

AndzejJ,

Thank you for your prompt response. I have checked by changing all segment count to ‘all’, ‘1’, ‘2’ also but it is giving the values alternatively as mentioned above.

Router by default taking “strings+value of first register”, “strings+value of second register”, strings+value of third register" like that…if selected segment count “all”.

I want “strings+value of first register+value of second register+value of third register” like that.

I want to get values in following format.

{
“version” : “1.0”,
“onlinetag” : “06171422010486”,
“time” : %t,
“payload” : [ {
“subDeviceId” : “ttyCOM1_2”,
“deviceType” : “Modbus_2”,
“status” : {
“Request_ActualFlow” : “Value”, Value of 1st register
“Request_TotalFlow” : “Value”, Value of 2nd register
“Request_InsDiagnostic” : “Value”, Value of 3rd register
“timestamp” : %t
}
} ]
}

By simply using “%r” : "%a% , i am getting specific request alternatively…

{
“version” : “1.0”,
“onlinetag” : “06171422010486”,
“time” : %t,
“payload” : [ {
“subDeviceId” : “ttyCOM1_2”,
“deviceType” : “Modbus_2”,
“status” : {
“Request_ActualFlow” : “value"
“timestamp” : %t
}
} ]
}
{
“version” : “1.0”,
“onlinetag” : “06171422010486”,
“time” : %t,
“payload” : [ {
“subDeviceId” : “ttyCOM1_2”,
“deviceType” : “Modbus_2”,
“status” : {
“Request_TotalFlow” : “value”,
“timestamp” : %t
}
} ]
}

But I want all request values together as per below format. (address as per above mentioned reply)

{
“version” : “1.0”,
“onlinetag” : “06171422010486”,
“time” : %t,
“payload” : [ {
“subDeviceId” : “ttyCOM1_2”,
“deviceType” : “Modbus_2”,
“status” : {
“Request_ActualFlow” : “Value”,
“Request_TotalFlow” : “Value”,
“Request_InsDiagnostic” : “Value*”,
“timestamp” : %t
}
} ]
}

Hello,

In data to server configurations, change ‘segment count’ to ‘all’. This will include all segments in a single message.

Kind Regards,