ModBus TCP Read 32-bit registers

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