ModBus TCP Read 32-bit registers

Dear community members, I am trying to read some parameters from the router via ModBus TCP but I do not know how to format the received messages.


What I receive it can be seen in the picture attached.

The router is a Teltonika RUT955, and information about ModBus TCP registers and format, it can be found in the manual at page 194.

Examples wich I found so far are for reading a 32-bit float register.

Thank you

ModBUS holding registers can store arbitrary binary data split into number of 16 bit registers. In reality you request how many 16 bit registers you want to read (the Quantity in the settings). As a result you receive byte array and it is up to the documentation on how to represent the data.

According to the tech spec for Teltonika RUT955 the numeric values are 32 bit. But in ModBUS registers are 16 bit. For example, to read the value of System uptime, you need to read 2 x 16-bit registers starting at address 1.

The Modbus Read module has two outputs. It seems the first returns an array of words (i.e. array of 16 bit elements). The second output returns the raw buffer (i.e. an array of bytes) which is stored under the property buffer:

image

Working with bytes is easier using NodeJS' Buffer class. You'll need three functions:

  1. Reading 32-bit unsigned int:
// Create new Buffer based on array bytes
const buf = Buffer.from(msg.payload.buffer);

// Represent these bytes as 32-bit unsigned int
const value = buf.readUInt32BE();

// save the value
msg.payload = value;

return msg;
  1. Reading 32-bit signed int:
// Create new Buffer based on array bytes
const buf = Buffer.from(msg.payload.buffer);

// Represent these bytes as 32-bit unsigned int
const value = buf.readInt32BE();

// save the value
msg.payload = value;

return msg;
  1. Converting the byte array to string:
// Create new Buffer based on array bytes
const buf = Buffer.from(msg.payload.buffer);

// Convert bytes to string
const value = buf.toString('ascii');
    
// Save the value
msg.payload = value;

return msg;

I've tested it using this flow:

Here is flow code:

[{"id":"2f0c2ece.bf0172","type":"modbus-read","z":"8fc1a5f.eb9d558","name":"Read System uptime","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"3","quantity":"2","rate":"10","rateUnit":"m","delayOnStart":false,"startDelayTime":"","server":"89cb9a7a.f6d138","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":310,"y":100,"wires":[["121ca9b9.542876"],["520ba567.23fc7c"]]},{"id":"121ca9b9.542876","type":"modbus-response","z":"8fc1a5f.eb9d558","name":"","registerShowMax":20,"x":570,"y":60,"wires":[]},{"id":"520ba567.23fc7c","type":"function","z":"8fc1a5f.eb9d558","name":"Convert byte array to UNSIGNED 32-bit integer","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Represent these bytes as 32-bit unsigned int\nconst value = buf.readUInt32BE();\n\n// save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":660,"y":120,"wires":[["b999f538.df72b8"]]},{"id":"b999f538.df72b8","type":"debug","z":"8fc1a5f.eb9d558","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":890,"y":380,"wires":[]},{"id":"b4339ef7.a41c5","type":"function","z":"8fc1a5f.eb9d558","name":"Convert byte array to SIGNED 32-bit integer","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Represent these bytes as 32-bit unsigned int\nconst value = buf.readInt32BE();\n\n// save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":650,"y":240,"wires":[["b999f538.df72b8"]]},{"id":"734fb295.9359fc","type":"modbus-read","z":"8fc1a5f.eb9d558","name":"Read GSM Signal strength","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"5","quantity":"2","rate":"10","rateUnit":"m","delayOnStart":false,"startDelayTime":"","server":"89cb9a7a.f6d138","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":330,"y":220,"wires":[["96c31649.de4538"],["b4339ef7.a41c5"]]},{"id":"96c31649.de4538","type":"modbus-response","z":"8fc1a5f.eb9d558","name":"","registerShowMax":20,"x":570,"y":180,"wires":[]},{"id":"3a725952.d250a6","type":"function","z":"8fc1a5f.eb9d558","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":600,"y":380,"wires":[["b999f538.df72b8"]]},{"id":"c833010c.d137b","type":"modbus-read","z":"8fc1a5f.eb9d558","name":"GSM Operator Name","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"7","quantity":"16","rate":"10","rateUnit":"m","delayOnStart":false,"startDelayTime":"","server":"89cb9a7a.f6d138","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":300,"y":340,"wires":[["d2ea1354.e44ef"],["3a725952.d250a6"]]},{"id":"d2ea1354.e44ef","type":"modbus-response","z":"8fc1a5f.eb9d558","name":"","registerShowMax":20,"x":570,"y":320,"wires":[]},{"id":"89cb9a7a.f6d138","type":"modbus-client","z":"","name":"","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":true,"tcpHost":"127.0.0.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectTimeout":"2000"}]

Hope this helps.

3 Likes

Hi iridiu, as far as I could understand each parameter will require a specific kind of manipulation for being correctly interpreted. For instance, system hostname will need a table lookup in an ascii table. Other parameters, like IP addresses, will need manipulation of data in binary form and this may be tricky in Javascript. At least system uptime and GSM signal strength are straightforward. Let's see the GSM signal strength for instance. The wiki says it is represented as two´s complement (since it is a negative number). So, in this case, all you need to is to subtract the second 16bit value (register 4) from 65536. Using the values from your picture: 65536 - 65457 = -79 dBm.

Trying a table lookup based on the picture you have provided and following the example on the wiki page. Does this string makes any sense for you , for the GSM operator name?

21071 = 524f = RO
8260 = 2044 = D
26983 = 6967 = iG
26926 = 692e = i.
19823 = 4d6f = Mo
25193 = 6269 = bi
27648 = 6c00 = l

1 Like

Hi @PKGeorgiev,

Neat solution ! Would it be possible to use the method buf.toString('ascii')to convert the byte array to string ,instead of the code below ?

// Convert byte array to string
// Works for arrays shorter than 65535
const value = String
    .fromCharCode
    .apply(null, msg.payload.buffer)
    .replace(/\0/gi, "")
    
msg.payload = value;

return msg;
1 Like

@Andrei yes buf.toString('ascii') works and is way better that the long version :slight_smile: For some reason it didn't work when I tried it. I've updated the code in my answer. Thanks!

2 Likes

Thanks a lot for your time and help, I have implemented your examples and, in the example code of PKGeorgiev, I have been able to read several values correctly, although most of them display the error that can be seen in the print screen.

In the case of Andrei's example, I get something like a blank payload, as can be seen in the print screen.
F%C4%83r%C4%83%20titlu1

Here is example received for "current SIM card":


Dashboard

And my flow:

[{"id":"44da94a1.1333dc","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to UNSIGNED 32-bit integer","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Represent these bytes as 32-bit unsigned int\nconst value = buf.readUInt32BE();\n\n// save the value\nmsg.payload = value;\nreturn msg;","outputs":1,"noerr":0,"x":553,"y":165,"wires":[[]]},{"id":"6e95813f.f4b8d","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Read System uptime","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"2","dataType":"HoldingRegister","adr":"1","quantity":"2","rate":"2","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":190,"y":140,"wires":[["9ce64dfd.4e3da"],["44da94a1.1333dc"]]},{"id":"dc79d090.15bf4","type":"modbus-response","z":"5c8a3e54.d2d01","name":"","registerShowMax":20,"x":450,"y":600,"wires":[]},{"id":"105ff479.001dbc","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to SIGNED 32-bit integer","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Represent these bytes as 32-bit unsigned int\nconst value = buf.readInt32BE();\n\n// save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":530,"y":260,"wires":[["bf98d6a1.54b178"]]},{"id":"efde23e1.72787","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Read GSM Signal strength","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"2","dataType":"HoldingRegister","adr":"3","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":210,"y":260,"wires":[[],["105ff479.001dbc"]]},{"id":"74a64c7d.94c594","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":320,"wires":[["895cd5be.866008"]]},{"id":"92a9e784.e46368","type":"modbus-read","z":"5c8a3e54.d2d01","name":"GSM Operator Name","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"2","dataType":"HoldingRegister","adr":"23","quantity":"16","rate":"1","rateUnit":"m","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":200,"y":320,"wires":[[],["74a64c7d.94c594"]]},{"id":"299d0882.bc32d8","type":"function","z":"5c8a3e54.d2d01","name":"Time conversion","func":"function timeConversion(millisec) {\n\n    var seconds = (millisec / 1000).toFixed(1);\n\n    var minutes = (millisec / (1000 * 60)).toFixed(1);\n\n    var hours = (millisec / (1000 * 60 * 60)).toFixed(1);\n\n    var days = (millisec / (1000 * 60 * 60 * 24)).toFixed(1);\n\n    if (seconds < 60) {\n        return seconds + \" Sec\";\n    } else if (minutes < 60) {\n        return minutes + \" Min\";\n    } else if (hours < 24) {\n        return hours + \" Hrs\";\n    } else {\n        return days + \" Days\"\n    }\n}\n\nmsg.payload = timeConversion(msg.payload.uptime * 1000);\nreturn msg;","outputs":1,"noerr":0,"x":1060,"y":162,"wires":[[]]},{"id":"bf98d6a1.54b178","type":"ui_gauge","z":"5c8a3e54.d2d01","name":"","group":"2fb2d7f7.a5e4d8","order":0,"width":0,"height":0,"gtype":"gage","title":"Signal strength","label":"dBm","format":"{{value}}","min":"-100","max":"0","colors":["#ff0000","#ffff00","#00ff00"],"seg1":"-90","seg2":"-70","x":920,"y":260,"wires":[]},{"id":"895cd5be.866008","type":"ui_text","z":"5c8a3e54.d2d01","group":"2fb2d7f7.a5e4d8","order":0,"width":0,"height":0,"name":"","label":"Operator GSM","format":"{{msg.payload}}","layout":"row-spread","x":920,"y":320,"wires":[]},{"id":"6f2ca98b.f6e858","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":380,"wires":[["ad1797d1.faf5a8"]]},{"id":"ad1797d1.faf5a8","type":"ui_text","z":"5c8a3e54.d2d01","group":"2fb2d7f7.a5e4d8","order":0,"width":0,"height":0,"name":"","label":"Current SIM card","format":"{{msg.payload}}","layout":"row-spread","x":930,"y":380,"wires":[]},{"id":"d7f3a082.79b4a","type":"modbus-response","z":"5c8a3e54.d2d01","name":"","registerShowMax":20,"x":450,"y":420,"wires":[]},{"id":"cc31d339.ad17c","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Current SIM card","topic":"","showStatusActivities":true,"showErrors":true,"unitid":"2","dataType":"HoldingRegister","adr":"87","quantity":"16","rate":"1","rateUnit":"m","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":180,"y":380,"wires":[[],["d7f3a082.79b4a"]]},{"id":"341b2329.21e34c","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Network registration","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"103","quantity":"16","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":190,"y":500,"wires":[[],["548a854b.422d7c"]]},{"id":"548a854b.422d7c","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":500,"wires":[["bbdfbc8f.0852e"]]},{"id":"bbdfbc8f.0852e","type":"ui_text","z":"5c8a3e54.d2d01","group":"2fb2d7f7.a5e4d8","order":0,"width":0,"height":0,"name":"","label":"Registration","format":"{{msg.payload}}","layout":"row-spread","x":910,"y":500,"wires":[]},{"id":"eff1252d.181758","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Network type","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"2","dataType":"HoldingRegister","adr":"119","quantity":"16","rate":"6","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":170,"y":560,"wires":[[],["dc79d090.15bf4"]]},{"id":"260f568.1e778aa","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Convert bytes to string\nconst value = String\n    .fromCharCode\n    .apply(null, msg.payload.buffer)\n    .replace(/\\0/gi, \"\")\n    \nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":560,"wires":[["4e18fd89.59f6c4"]]},{"id":"4e18fd89.59f6c4","type":"ui_text","z":"5c8a3e54.d2d01","group":"2fb2d7f7.a5e4d8","order":0,"width":0,"height":0,"name":"","label":"Network type","format":"{{msg.payload}}","layout":"row-spread","x":910,"y":560,"wires":[]},{"id":"9ce64dfd.4e3da","type":"modbus-response","z":"5c8a3e54.d2d01","name":"","registerShowMax":20,"x":470,"y":100,"wires":[]},{"id":"25b5d142.78ee9e","type":"modbus-read","z":"5c8a3e54.d2d01","name":"System temperature in 0.1 degrees","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"2","dataType":"HoldingRegister","adr":"5","quantity":"2","rate":"6","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":240,"y":700,"wires":[["a27038ad.d970d8"],["3d142b6e.a40814"]]},{"id":"a27038ad.d970d8","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to SIGNED 32-bit integer","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Represent these bytes as 32-bit unsigned int\nconst value = buf.readInt32BE();\n\n// save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":610,"y":700,"wires":[["ecd3140.fcb5fe8"]]},{"id":"ecd3140.fcb5fe8","type":"ui_gauge","z":"5c8a3e54.d2d01","name":"","group":"5e7d306.54b1cd","order":0,"width":0,"height":0,"gtype":"gage","title":"Temp","label":"units","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":890,"y":700,"wires":[]},{"id":"3d142b6e.a40814","type":"modbus-response","z":"5c8a3e54.d2d01","name":"","registerShowMax":20,"x":510,"y":740,"wires":[]},{"id":"d51dae9b.ccea5","type":"modbus-read","z":"5c8a3e54.d2d01","name":"System hostname","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"2","dataType":"HoldingRegister","adr":"7","quantity":"16","rate":"6","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":190,"y":820,"wires":[["20fb35cd.eb92fa"],["a361f781.c12dc8"]]},{"id":"20fb35cd.eb92fa","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Convert byte array to string\n// Works for arrays shorter than 65535\nconst value = String\n    .fromCharCode\n    .apply(null, msg.payload.buffer)\n    .replace(/\\0/gi, \"\")\n    \nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":820,"wires":[["2fde54e2.b1e5dc"]]},{"id":"a361f781.c12dc8","type":"modbus-response","z":"5c8a3e54.d2d01","name":"","registerShowMax":20,"x":430,"y":860,"wires":[]},{"id":"b0c387e2.b7bb28","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Router serial number","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"2","dataType":"HoldingRegister","adr":"39","quantity":"16","rate":"7","rateUnit":"s","delayOnStart":false,"startDelayTime":"1","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":200,"y":940,"wires":[["381cbf8d.91822"],["7b284af0.a74844"]]},{"id":"381cbf8d.91822","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":540,"y":940,"wires":[[]]},{"id":"7b284af0.a74844","type":"modbus-response","z":"5c8a3e54.d2d01","name":"","registerShowMax":20,"x":510,"y":980,"wires":[]},{"id":"d611ed67.ff8ec","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Router MAC address","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"55","quantity":"16","rate":"8","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":200,"y":1020,"wires":[["d3ec2ca4.4316e"],[]]},{"id":"d3ec2ca4.4316e","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":540,"y":1040,"wires":[[]]},{"id":"bf203ee7.6f0be","type":"debug","z":"5c8a3e54.d2d01","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":870,"y":60,"wires":[]},{"id":"70fad4d.536612c","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Router name","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"71","quantity":"16","rate":"9","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":170,"y":1120,"wires":[["b88718db.771c58"],[]]},{"id":"b88718db.771c58","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to string","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Convert bytes to string\nconst value = buf.toString('ascii');\n    \n// Save the value\nmsg.payload = value;\n\nreturn msg;","outputs":1,"noerr":0,"x":443,"y":1104,"wires":[[]]},{"id":"36150a1.28662f6","type":"modbus-read","z":"5c8a3e54.d2d01","name":"Current WAN IP address","topic":"","showStatusActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"139","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"58aee075.e3c67","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":200,"y":1200,"wires":[["44a1f8e9.cb4ac8"],[]]},{"id":"44a1f8e9.cb4ac8","type":"function","z":"5c8a3e54.d2d01","name":"Convert byte array to UNSIGNED 32-bit integer","func":"// Create new Buffer based on array bytes\nconst buf = Buffer.from(msg.payload.buffer);\n\n// Represent these bytes as 32-bit unsigned int\nconst value = buf.readUInt32BE();\n\n// save the value\nmsg.payload = value;\nreturn msg;","outputs":1,"noerr":0,"x":540,"y":1200,"wires":[[]]},{"id":"2fde54e2.b1e5dc","type":"debug","z":"5c8a3e54.d2d01","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":800,"y":840,"wires":[]},{"id":"58aee075.e3c67","type":"modbus-client","z":"","name":"Teltonika","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":true,"tcpHost":"192.168.1.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectTimeout":"2000"},{"id":"2fb2d7f7.a5e4d8","type":"ui_group","z":"","name":"GSM Network","tab":"315345d7.e57a6a","order":1,"disp":true,"width":"6","collapse":false},{"id":"5e7d306.54b1cd","type":"ui_group","z":"","name":"Router","tab":"315345d7.e57a6a","order":2,"disp":true,"width":"6","collapse":false},{"id":"315345d7.e57a6a","type":"ui_tab","z":"","name":"Router","icon":"settings","order":2}]

Hi Iridiu, a quick tip that can help a lot on troubleshooting. Give each node a meaningful name. By doing that it will be possible to associate the error message in the debug panel with the node that generated the message. Also adding a debug node (also named) will be helpful.

For instance:

I suggest you to troubleshoot each troubled modbus reading in separate. It will give you some work but at the end of the day it may be worthwhile. One possible way to do that is by breaking the wiring from the modbus nodes to their functions, leaving only one active (the one that you want to troubleshoot).

I am pretty sure that the readings are ok. It is just a matter of using the right bytes and doing the right manipulation and formatting. Let me give you an example. The temperature manipulation is straightforward (once you use the correct bytes). If the value read is 480 then you all you have to do is to display this value divided by 10 (can be done easily in the ui_gauge node).

1 Like

Hi Iridiu,

I see an issue. You have to connect the function nodes always to the second output of the modbus nodes. For instance, the function node below needs to be rewired to the other output of the modbus node.

2 Likes

Hi @Andrei, following your indications I've managed to make the nodes work correctly, thank you very much!

Hi Iridiu, thanks to @PKGeorgiev that provided the solution in fact.

it was a nice use case to practice using the modbus node. A final remark: see that it is still necessary some extra data manipulation to get the correct IP address.

1 Like

Yes, I'm looking for a solution to get correct IP data

Perhaps you could use below function as a starting point. You have a pair of numbers in the registers 139 and 140. Each one of them will convert to a pair of numbers that form the IP address.

For instance:
register 139 = 32322
register 140 = 35626

Will result in :
01111110 01000010 = 126.66
10001011 00101010 = 139.42

[{"id":"363fd71.fbd6f28","type":"tab","label":"Flow 16","disabled":false,"info":""},{"id":"24df2b6d.4b87e4","type":"inject","z":"363fd71.fbd6f28","name":"","topic":"","payload":"35626","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":270,"y":140,"wires":[["4d7bf.17df8842"]]},{"id":"4d7bf.17df8842","type":"function","z":"363fd71.fbd6f28","name":"Converttoip","func":"function converttoip(r){\nlet br = r.toString(2);\nlet a = parseInt(br.slice(0,-8),2);\nlet b = parseInt(br.slice(-8),2);\nreturn `${a}.${b}`\n}\n\nmsg.payload = converttoip(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"x":440,"y":140,"wires":[["c21be26f.88ae8"]]},{"id":"c21be26f.88ae8","type":"debug","z":"363fd71.fbd6f28","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":610,"y":140,"wires":[]}]

This is my network diagram:

Dashboard

So my current WAN IP address is 192.168.0.106, mobile network is a backup network, and this is data received fom modbus-read-node
F%C4%83r%C4%83%20titlu2

Good, in such case below (patched) code should work.

I did it based on your feedback and therefore this time the function node has to be connected in the first output of the modbus node.

[{"id":"9221b509.4f3348","type":"function","z":"363fd71.fbd6f28","name":"Read and convert to IP","func":"function converttoip(r){\nlet br = r.toString(2);\nlet padding = \"0\".repeat(16-br.length);\nbr = padding+br;\nlet a = parseInt(br.slice(0,-8),2);\nlet b = parseInt(br.slice(-8),2);\nreturn `${a}.${b}`\n}\n\n\n// Create new Buffer based on array bytes\nlet value1 = msg.payload.responseBuffer.data[0]\nlet value2 = msg.payload.responseBuffer.data[1]\n\n\nmsg.payload = converttoip(value1) + \".\"+converttoip(value2);\n\nreturn msg;","outputs":1,"noerr":0,"x":480,"y":320,"wires":[["3d1f5c79.3600a4"]]},{"id":"3d1f5c79.3600a4","type":"debug","z":"363fd71.fbd6f28","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":730,"y":320,"wires":[]}]

Hi @Andrei, I have tried the function, but with no succes, but with the knowledge I have accumulated so far, I have succeeded in displaying the IP address, so to get the WAN IP address from the received response, the values of both registers must be readed from buffer into 8-bit segments, so I translated each individual segment

// Create new Buffer based on array bytes
const buf = Buffer.from(msg.payload.buffer);
const value1 = buf.readUInt8(0);
const value2 = buf.readUInt8(1);
const value3 = buf.readUInt8(2);
const value4 = buf.readUInt8(3);
msg.payload = [value1, value2, value3, value4];

return msg;

1 Like

Hi @iridiu,

Well done! The solution you found is simple and effective. I really appreciate as now I could learn from you exactly how the buffer structure works for the Modbus node. Thank you very much.

2 Likes

I'm curious why the first output of modbus-read node returns an array of 16bit numbers given that most of the post operations (i.e. converting to numbers, IP addresses etc.) are byte oriented i.e. the raw byte buffer is used the most? What would be the use case for Output1?

1 Like

Hello guys, I was reading this topic and I saw that you were talking about converting a 16-bit variable to 32 .. I have a problem, I need to turn a 16-bit variable into 64-bit .. I need together the parts of a vector of 4 positions and contact this information for me to arrive at my actual information. Could you help me?

Can you explain in detail what you mean by that? Give an example of what you have and what you want to end up with. Remember this thread is about reading 32 bit modbus registers.

@eduardotodero I usually create a new Uint16Array with the 16-bit values and then create a Float64Array with the Uint16Array's buffer:

var ui16a = new Uint16Array([1,2,3,4]); // your 16-bit integers here
var fl64a = new Float64Array(ui16a.buffer);
console.log(fl64a[0]);

Or, if you need more flexibility, get familiar with DataView, specifically you would end up using: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView/getFloat64

Edit: missed if you were talking about 64-bit integers or floating-point numbers -- in any case, you can use typed arrays: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays to do what you want. You may want to create a Int64Array, for example. With these, you can convert an entire block of a certain type in one shot.

5 Likes