Modbus Serial - Best way to request data

Hi, I'm using NodeRed v3.0.2 and node-red-contrib-modbus (last version). My modbus hardware uses a RS485 RTU.

After some reading, I noticed that best practice to request data is to make a single request with a higher number of variables. For instance, use address 1 and quantity 10. However, my device lacks of the 8 address, which gives me no alternative, other than make two requests.

Address = 1 Quantity = 7
Address = 9 Quantity = 3

My question is if I'm doing it correctly, or if there is a more elegant way to perform it.

[{"id":"69e5ce6599848b17","type":"group","z":"f05b1eedc84ed2ab","name":"Read speed","style":{"stroke":"#92d04f","fill":"#92d04f","fill-opacity":"0.05","label":true,"color":"#000000"},"nodes":["d7f639752a0116f8","5b010bc59484b149","01857754ce2ca002","b9da5067a567800f","fb0258379895e808","1918563a10c9fc5e","7b7c9f6b820d8ddb","02d4b7847a018e4b","f147f48315c36dd2"],"x":74,"y":1239,"w":852,"h":262},{"id":"d7f639752a0116f8","type":"inject","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"Check speed","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":440,"y":1280,"wires":[["01857754ce2ca002"]]},{"id":"5b010bc59484b149","type":"function","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"Build Modbus msg","func":"// Get driver info\nlet _driverName = msg.payload[0];\nvar _driver = flow.get(\"_varsDrivers\")[_driverName];\n// driver.timeout = 10;\n// msg.payload = {};\n// msg.payload[driverName] = driver;\n\nvar msg1 = {};\nvar msg2 = {};\n\n// Request from inverter\n// 10 first parameters\nvar _fc = 3;\n\nvar _PXXXX = 1;\nvar _qty = 7;\nmsg1.payload = { \n    value: 0, \n    'fc': _fc, \n    'unitid': _driver.id, \n    'address': _PXXXX,\n    'quantity': _qty,\n    };\n\nvar _PXXXX = 9;\nvar _qty = 3;\nmsg2.payload = {\n    value: 0,\n    'fc': _fc,\n    'unitid': _driver.id,\n    'address': _PXXXX,\n    'quantity': _qty,\n};\n\nreturn [msg1, msg2];\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":190,"y":1360,"wires":[["7b7c9f6b820d8ddb"],["7b7c9f6b820d8ddb"]]},{"id":"01857754ce2ca002","type":"function","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"Queue Messages Modbus","func":"// Only process if inject true\nif (msg.payload === true){\n    // Get drivers from flow\n    var _drivers = flow.get(\"_varsDrivers\");\n    var _driversKeys = Object.keys(_drivers);\n\n    // Pass messages without timeout\n    msg.payload =\n        _driversKeys.filter((el) => {\n            if (_drivers[el].timeout > 0){\n                _drivers[el].timeout--;\n            }\n            return _drivers[el].timeout === 0;\n        });\n\n    // If there is no driver available, drop\n    if (msg.payload.length != 0){\n        context.set(\"_varsDrivers\", msg.payload);\n        return msg;\n    }\n    \n}else{\n    // After modbus reply, send next drive\n    msg.payload = context.get(\"_varsDrivers\")\n    \n    // Remove first element - Already processed\n    msg.payload.shift();\n\n    // If empty elements, exit\n    if (msg.payload.length != 0) {\n        return msg;\n    }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":770,"y":1280,"wires":[["5b010bc59484b149"]]},{"id":"b9da5067a567800f","type":"comment","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"90ms por driver","info":"","x":180,"y":1420,"wires":[]},{"id":"fb0258379895e808","type":"function","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"Update values / MQTT","func":"if (msg.payload[0]){\n    // Recover flow var\n    var _drivers = flow.get(\"_varsDrivers\");\n    var _driversKey = Object.keys(_drivers);\n    // Find element and edit it's actual speed\n    var driverName =\n        _driversKey.find(\n            el => _drivers[el].id == msg.modbusRequest.unitid\n            // el => _drivers[el].id == 4\n        );\n    \n    // Update variables\n    _drivers[driverName].speed._set = msg.payload[0][0];\n    _drivers[driverName].speed._get = msg.payload[0][1];\n    _drivers[driverName].info.current = msg.payload[0][2];\n    _drivers[driverName].info.Vdc = msg.payload[0][3];\n    _drivers[driverName].info.state = msg.payload[0][5];\n    _drivers[driverName].info.Vout = msg.payload[0][6];\n    _drivers[driverName].info.torque = msg.payload[1][0];\n    _drivers[driverName].info.Pout = msg.payload[1][1];\n    _drivers[driverName].info.pf = msg.payload[1][2];\n\n   msg.topic = \"driver/\" + driverName + \"/speed/get\";\n   msg.payload = _drivers[driverName].speed._get;\n\n   return msg;\n\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":780,"y":1340,"wires":[["1918563a10c9fc5e"]]},{"id":"1918563a10c9fc5e","type":"mqtt out","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"Publish Modbus","topic":"","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"b317b5e94474dac6","x":820,"y":1400,"wires":[]},{"id":"7b7c9f6b820d8ddb","type":"modbus-flex-getter","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"Request Modbus","showStatusActivities":false,"showErrors":true,"showWarnings":true,"logIOActivities":false,"server":"4bb49bd08ce7548f","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":true,"keepMsgProperties":true,"delayOnStart":false,"startDelayTime":"","x":410,"y":1360,"wires":[["f147f48315c36dd2"],["02d4b7847a018e4b"]]},{"id":"02d4b7847a018e4b","type":"modbus-response","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"","registerShowMax":20,"x":430,"y":1460,"wires":[]},{"id":"f147f48315c36dd2","type":"join","z":"f05b1eedc84ed2ab","g":"69e5ce6599848b17","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"","count":"2","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"num","reduceFixup":"","x":590,"y":1340,"wires":[["fb0258379895e808","01857754ce2ca002"]]},{"id":"b317b5e94474dac6","type":"mqtt-broker","name":"","broker":"10.254.0.253","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"4bb49bd08ce7548f","type":"modbus-client","z":"f05b1eedc84ed2ab","name":"WaveshareRS485","clienttype":"serial","bufferCommands":true,"stateLogEnabled":true,"queueLogEnabled":true,"failureLogEnabled":true,"tcpHost":"127.0.0.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyAMA0","serialType":"RTU-BUFFERD","serialBaudrate":"19200","serialDatabits":"8","serialStopbits":"1","serialParity":"even","serialConnectionDelay":"5","serialAsciiResponseStartDelimiter":"0x3A","unit_id":0,"commandDelay":10,"clientTimeout":100,"reconnectOnTimeout":false,"reconnectTimeout":1000,"parallelUnitIdsAllowed":true,"showWarnings":true,"showLogs":true}]

The function Build Modbus msg has two outputs, in which I create the descontinuity. After that, I use join node. I confess that I'm not happy with the join configuration.

What happens if you make one request over the full range?

A better solution is.

  1. For stability, dont send parallel MB requests
  2. Avoid loops (they can get out of control)
  3. Dont use join in Array mode (since delays can cause array order issue)
  4. Store all values in message and "pass them on"

Example...

The flow (untested)

[{"id":"69e5ce6599848b17","type":"group","z":"83556a18e3c2c577","name":"Read speed","style":{"stroke":"#92d04f","fill":"#92d04f","fill-opacity":"0.05","label":true,"color":"#000000"},"nodes":["d7f639752a0116f8","5b010bc59484b149","01857754ce2ca002","b9da5067a567800f","fb0258379895e808","1918563a10c9fc5e","6969c1e05fc1c993","7463e14c42bf93ce","2f52a88051dd1e30"],"x":574,"y":2359,"w":832,"h":202},{"id":"d7f639752a0116f8","type":"inject","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"Check speed","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":740,"y":2400,"wires":[["01857754ce2ca002"]]},{"id":"5b010bc59484b149","type":"function","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"Build Modbus msg","func":"// Get driver info\nlet _driverName = msg.payload[0];\nlet _driver = flow.get(\"_varsDrivers\")[_driverName];\n// driver.timeout = 10;\n// msg.payload = {};\n// msg.payload[driverName] = driver;\n\n\n// Request from inverter\n// 10 first parameters\nlet _fc = 3;\nlet _PXXXX = 1;\nlet _qty = 7;\nmsg.payload = { \n    value: 0, \n    'fc': _fc, \n    'unitid': _driver.id, \n    'address': _PXXXX,\n    'quantity': _qty,\n    };\n\n_PXXXX = 9;\n_qty = 3;\nmsg.next = {\n    value: 0,\n    'fc': _fc,\n    'unitid': _driver.id,\n    'address': _PXXXX,\n    'quantity': _qty,\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":2400,"wires":[["7463e14c42bf93ce"]]},{"id":"01857754ce2ca002","type":"function","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"Queue Messages Modbus","func":"// Only process if inject true\nif (msg.payload === true){\n    // Get drivers from flow\n    var _drivers = flow.get(\"_varsDrivers\");\n    var _driversKeys = Object.keys(_drivers);\n\n    // Pass messages without timeout\n    msg.payload =\n        _driversKeys.filter((el) => {\n            if (_drivers[el].timeout > 0){\n                _drivers[el].timeout--;\n            }\n            return _drivers[el].timeout === 0;\n        });\n\n    // If there is no driver available, drop\n    if (msg.payload.length != 0){\n        context.set(\"_varsDrivers\", msg.payload);\n        return msg;\n    }\n    \n}else{\n    // After modbus reply, send next drive\n    msg.payload = context.get(\"_varsDrivers\")\n    \n    // Remove first element - Already processed\n    msg.payload.shift();\n\n    // If empty elements, exit\n    if (msg.payload.length != 0) {\n        return msg;\n    }\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1010,"y":2400,"wires":[["5b010bc59484b149"]]},{"id":"b9da5067a567800f","type":"comment","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"90ms por driver","info":"","x":680,"y":2520,"wires":[]},{"id":"fb0258379895e808","type":"function","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"Update values / MQTT","func":"const data1 = msg.data1\nconst data2 = msg.payload\n\nif (data1){\n    // Recover flow var\n    var _drivers = flow.get(\"_varsDrivers\");\n    var _driversKey = Object.keys(_drivers);\n    // Find element and edit it's actual speed\n    var driverName =\n        _driversKey.find(\n            el => _drivers[el].id == msg.modbusRequest.unitid\n            // el => _drivers[el].id == 4\n        );\n    \n    // Update variables\n    _drivers[driverName].speed._set = data1[0];\n    _drivers[driverName].speed._get = data1[1];\n    _drivers[driverName].info.current = data1[2];\n    _drivers[driverName].info.Vdc = data1[3];\n    _drivers[driverName].info.state = data1[5];\n    _drivers[driverName].info.Vout = data1[6];\n    _drivers[driverName].info.torque = data2[0];\n    _drivers[driverName].info.Pout = data2[1];\n    _drivers[driverName].info.pf = data2[2];\n\n   msg.topic = \"driver/\" + driverName + \"/speed/get\";\n   msg.payload = _drivers[driverName].speed._get;\n\n   return msg;\n\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1080,"y":2520,"wires":[["1918563a10c9fc5e"]]},{"id":"1918563a10c9fc5e","type":"mqtt out","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"Publish Modbus","topic":"","qos":"1","retain":"false","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"b317b5e94474dac6","x":1300,"y":2520,"wires":[]},{"id":"6969c1e05fc1c993","type":"change","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"","rules":[{"t":"set","p":"data1","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"next","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1020,"y":2460,"wires":[["2f52a88051dd1e30"]]},{"id":"7463e14c42bf93ce","type":"link call","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"","links":["bd899996cdf424ae"],"linkType":"static","timeout":"30","x":790,"y":2460,"wires":[["6969c1e05fc1c993"]]},{"id":"2f52a88051dd1e30","type":"link call","z":"83556a18e3c2c577","g":"69e5ce6599848b17","name":"","links":["bd899996cdf424ae"],"linkType":"static","timeout":"30","x":870,"y":2520,"wires":[["fb0258379895e808"]]},{"id":"b317b5e94474dac6","type":"mqtt-broker","name":"","broker":"10.254.0.253","port":"1883","clientid":"","autoConnect":true,"usetls":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""},{"id":"983df0f6705793ac","type":"group","z":"83556a18e3c2c577","name":"Get Modbus Data (subroutine)","style":{"label":true,"stroke":"#ffC000","fill":"#ffefbf","color":"#000000"},"nodes":["bd899996cdf424ae","4a578c80ba761dd1","dd1246486ff745ef","f55e31d42a9aaba6"],"x":574,"y":2199,"w":432,"h":142},{"id":"bd899996cdf424ae","type":"link in","z":"83556a18e3c2c577","g":"983df0f6705793ac","name":"get MB data","links":[],"x":615,"y":2240,"wires":[["4a578c80ba761dd1"]]},{"id":"4a578c80ba761dd1","type":"modbus-flex-getter","z":"83556a18e3c2c577","g":"983df0f6705793ac","name":"Request Modbus","showStatusActivities":false,"showErrors":true,"logIOActivities":false,"server":"4bb49bd08ce7548f","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":true,"keepMsgProperties":true,"x":760,"y":2240,"wires":[["f55e31d42a9aaba6"],["dd1246486ff745ef"]]},{"id":"dd1246486ff745ef","type":"modbus-response","z":"83556a18e3c2c577","g":"983df0f6705793ac","name":"","registerShowMax":20,"x":860,"y":2300,"wires":[]},{"id":"f55e31d42a9aaba6","type":"link out","z":"83556a18e3c2c577","g":"983df0f6705793ac","name":"link out 3","mode":"link","links":[],"x":965,"y":2240,"wires":[]},{"id":"4bb49bd08ce7548f","type":"modbus-client","z":"83556a18e3c2c577","name":"WaveshareRS485","clienttype":"serial","bufferCommands":true,"stateLogEnabled":true,"queueLogEnabled":true,"failureLogEnabled":true,"tcpHost":"127.0.0.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyAMA0","serialType":"RTU-BUFFERD","serialBaudrate":"19200","serialDatabits":"8","serialStopbits":"1","serialParity":"even","serialConnectionDelay":"5","serialAsciiResponseStartDelimiter":"0x3A","unit_id":0,"commandDelay":10,"clientTimeout":100,"reconnectOnTimeout":false,"reconnectTimeout":1000,"parallelUnitIdsAllowed":true}]

Hi @Colin , I receive illegal address.

Hi @Steve-Mcl ,

  1. Ok, I replaced it with
return [[msg1, msg2]]
  1. Your suggestion it really good. Thanks. However, I get a problem. I need to get data as fast as I can. In order to do so, I must start a new request, as soon the reading finishes. This is way I loop it. After looking into your suggested flow, I wasn't able to find the back trigger. It only relies on injection node.
  2. About the join array, I will remove it. My only concern was to trigger the flow after the last message. But from your suggestion, it seems a good alternative.
  3. Not sure if I understood it.

Unfortunately, I wasn't able to make your flow work. I'm getting timeout.

Just to add a problem in Link call node get MB data. When it timeout, it simply erase _linkSource. The node timeout.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.