Read Registers From Modbus Not in Sequence

Hello,

I want to read multiple registers from modbus that are not in a sequence, what would be the best way? Is there any modbus node that I can use to do it, or shoud I use two modbus flex read and then join. I was trying the last solution without any luck joining the data array to after process in the buffer parser.
Thank you for any help provided.

Cheers

Hello ..

I think with the latest version of Modbus nodes v.5.14.1 there is a new node called Modbus-Flex-Sequencer that supposedly does just that .. do sequential reads .. but i havent tested it yet.

Whats wrong with the setup you have now ? .. what problem do you have joining the messages with the Join node ? You havent shared your flow to see how you setup your join node but if you add the Buffer parser nodes after each of your Modbus Flex getters and then wire those to a Join node with the following settings it should theoretically work.

image

It might be better to wire the modbus nodes in series. So after the first one save the data to a message property and then wire to the function node and second modbus node, then you will have a message with both results in it. The modbus node should not destroy the saved property. Then you won't have two modbus nodes trying to do things at (virtually) the same time, which is safer.

I'll give sequencer a try and then let you know. Cheers

Sorry Colin, I didn't understood your suggestion. I'm new to Node Red. But enjoying it more everyday. Cheers

@Colin is talking about wiring all nodes in series, like this: Modbus Serial - Whole bus disconnects when one device drops - #16 by Steve-Mcl

I haven't got the modbus nodes installed so can only mock up an image to show the flow.

I did a quick test with the Modbus-Flex-Sequencer and it doesnt work :wink: (i think its still under development)
Even if it did work, it would be a headache to route its results to individual buffer parsers to convert your values, so the best approach is what Colin and Steve recommended.

Also arrived to the same conclusion.

I parse a CSV with the registers i want to read, and their context, then loop each of the points into the flex getter node for a read and store all the register values into flow or global vars.

This sounds like a good approach. I wanted to ask whether you do a small delay when sending the messages this way or do you let the Flex getter node queue and delay the msgs with its settings.

I'm sorry to bother again. But I understood your idea, just can't seem to make it work. Having real problems joining at the end the two messages. I need an array (or buffer) to use buffer parser and get the variables, that is way I want to join them together.
Cheers

I think I found the best way to do it. This will be to read around 100 modbus equipments. I hope it won't brake down.

[{"id":"7b5ce34010b47634","type":"tab","label":"Modbus Sequence","disabled":false,"info":""},{"id":"1a61223919d36fa1","type":"inject","z":"7b5ce34010b47634","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":120,"y":160,"wires":[["a3b64b9f1004af66"]]},{"id":"a3b64b9f1004af66","type":"function","z":"7b5ce34010b47634","name":"DirisA10#5 Common","func":"msg.payload = { value: msg.payload,\n'fc': 3,\n'unitid': 22, \n'address': 2 , \n'quantity': 6 }; \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":160,"wires":[["775615de01c50f58"]]},{"id":"775615de01c50f58","type":"modbus-flex-getter","z":"7b5ce34010b47634","name":"Modbus Read #22","showStatusActivities":true,"showErrors":true,"logIOActivities":false,"server":"8643327cb6aae6be","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":true,"x":570,"y":160,"wires":[[],["465426bf347e7399"]]},{"id":"465426bf347e7399","type":"change","z":"7b5ce34010b47634","name":"","rules":[{"t":"move","p":"payload.data","pt":"msg","to":"data01","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":950,"y":160,"wires":[["c571b7a2a8b6bb89"]]},{"id":"c571b7a2a8b6bb89","type":"function","z":"7b5ce34010b47634","name":"DirisA10#5 Energies","func":"msg.payload = { value: msg.payload,\n'fc': 3,\n'unitid': 22, \n'address': 6687 , \n'quantity': 2 }; \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":340,"y":260,"wires":[["9596fd4115a8992c"]]},{"id":"9596fd4115a8992c","type":"modbus-flex-getter","z":"7b5ce34010b47634","name":"Modbus Read #22","showStatusActivities":true,"showErrors":true,"logIOActivities":false,"server":"8643327cb6aae6be","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":true,"x":570,"y":260,"wires":[[],["e9fc5b56c604f2bd"]]},{"id":"342d9d605b8f0897","type":"function","z":"7b5ce34010b47634","name":"","func":"msg.counter = 'Counter#22'\nmsg.ts = msg.timestamp\nmsg.V1 = ((msg.data01[0] << 16) + msg.data01[1])*0.01\nmsg.V2 = ((msg.data01[2] << 16) + msg.data01[3])*0.01\nmsg.V3 = ((msg.data01[4] << 16) + msg.data01[5])*0.01\n\nmsg.Energy = ((msg.payload.data[0] << 16) + msg.payload.data[1])*0.01\n\nmsg.payload = {\n            ts:msg.ts, \n            V1:msg.V1,\n            V2:msg.V2,\n            V3:msg.V3,\n            Energy:msg.Energy\n            }       \nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1040,"y":260,"wires":[["afedee5c5e9ff47f"]]},{"id":"e9fc5b56c604f2bd","type":"moment","z":"7b5ce34010b47634","name":"'yyyy-MM-DD hh:mm:ss'","topic":"","input":"","inputType":"date","inTz":"Europe/Lisbon","adjAmount":0,"adjType":"days","adjDir":"add","format":"'yyyy-MM-DD HH:mm:ss'","locale":"en-US","output":"timestamp","outputType":"msg","outTz":"Europe/Lisbon","x":790,"y":280,"wires":[["342d9d605b8f0897"]]},{"id":"afedee5c5e9ff47f","type":"debug","z":"7b5ce34010b47634","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1240,"y":280,"wires":[]},{"id":"8643327cb6aae6be","type":"modbus-client","name":"Modbus TCP","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"192.168.1.51","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":"2000","reconnectOnTimeout":true,"reconnectTimeout":"4000","parallelUnitIdsAllowed":true}]

I'm posting a part of my flow also, that i use to read in sequence a bunch of Energy Meters using Modbus serial. Hope you find something useful in it.

The steps used.

  1. use Cron-plus node to trigger the sequence of reads.
  2. use an "error" function to fill with null values for any device that may be offline
  3. join the results after passing them from buffer-parser.
  4. save them in Context

ModbusFlow.json (54.1 KB)

I think I would probably have parsed each buffer before moving on the next modbus node, then it would be trivial to combine them .

@UnborN, I just let throw them at the flex getter and it handles them.. Its not a massive amount of tags, 70 - 90 for the main PLC status and alarms. most have 1, 2 or 3, VFDs I also read 10 or 12 tags each the same way.. relevant snippets are below...

[{"id":"73599554.0351dc","type":"function","z":"64187f31.4b904","name":"cacheConfig","func":"//varpts=msg.payloadvarpoints_lookup={}pts.forEach(function(p){if(points_lookup[p.reg_name]){points_lookup[p.reg_name].points.push({'bit':parseInt(p.bit),'name':p.point_name,'alias_on':p.alias_on,'alias_off':p.alias_off,'parse':p.parse})}else{points_lookup[p.reg_name]={}points_lookup[p.reg_name].name=p.reg_namepoints_lookup[p.reg_name].parse=p.parsepoints_lookup[p.reg_name].group=p.grouppoints_lookup[p.reg_name].quantity=p.quantitypoints_lookup[p.reg_name].address=parseInt(p.reg_address)points_lookup[p.reg_name].points=[]points_lookup[p.reg_name].points.push({'bit':parseInt(p.bit),'name':p.point_name,'alias_on':p.alias_on,'alias_off':p.alias_off})}});flow.set('points',points_lookup)\nvar pts = msg.payload\nvar points_lookup = {}\npts.forEach(function(p){\n    \n    if (points_lookup[p.reg_name]) {\n      points_lookup[p.reg_name].points.push({'bit': parseInt(p.bit), 'name': p.point_name, 'alias_on': p.alias_on, 'alias_off': p.alias_off, 'parse': p.parse})\n    } else {\n      points_lookup[p.reg_name] = {}\n      points_lookup[p.reg_name].name = p.reg_name\n      points_lookup[p.reg_name].parse = p.parse\n      points_lookup[p.reg_name].group = p.group\n      points_lookup[p.reg_name].quantity = p.quantity\n      points_lookup[p.reg_name].address = parseInt(p.reg_address)\n      points_lookup[p.reg_name].points = []\n      points_lookup[p.reg_name].points.push({'bit': parseInt(p.bit), 'name': p.point_name, 'alias_on': p.alias_on, 'alias_off': p.alias_off})\n    } \n});\n\nflow.set('points', points_lookup)        ","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":220,"wires":[[]]},{"id":"2aa1c606.326e2a","type":"file in","z":"64187f31.4b904","name":"","filename":"/data/modbus_points.csv","format":"utf8","chunk":false,"sendError":false,"encoding":"none","x":270,"y":220,"wires":[["3d104107.371ece"]]},{"id":"3d104107.371ece","type":"fastcsv","z":"64187f31.4b904","name":"fastcsv","headers":true,"headerstr":"","ignoreEmpty":true,"discardUnmappedColumns":true,"strictColumnHandling":false,"delimiter":",","quote":"\"","escape":"\"","comment":"#","ltrim":false,"rtrim":false,"rowDelimiter":"\\n","includeEndRowDelimiter":false,"quoteHeaders":false,"quoteColumns":false,"x":480,"y":220,"wires":[["73599554.0351dc"]]},{"id":"7e742181.e1e8b","type":"function","z":"64187f31.4b904","name":"LoopThroughPoints","func":"var points = flow.get('points')\nvar modbusStatus = flow.get('modbusStatus')\nif(points && (modbusStatus.indexOf('active') != -1 || modbusStatus.indexOf('timeout') != -1 )) {\nvar numPoints = Object.keys(points).length\nvar idx = flow.get('idx')\nif (idx == undefined || idx >= numPoints) {\n    idx = 0\n}\n\nvar names = Object.keys(points)\nmsg.points = points[names[idx]].points\nmsg.name = names[idx]\nmsg.parse = points[names[idx]].parse\nmsg.group = points[names[idx]].group\n//node.error(msg.name)\nmsg.payload = { value: msg.payload, 'fc': 3, 'unitid': 1, 'address': points[names[idx]].address, 'quantity': points[names[idx]].quantity }\n\nif(idx <= numPoints-1) {\n    idx += 1\n    flow.set('idx', idx)\n      \n} else {\nflow.set('idx', 0)  \n}\nreturn msg;  \n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":690,"y":320,"wires":[["acc10367.8945c"]]},{"id":"ba625744.8c9338","type":"function","z":"64187f31.4b904","name":"ParseResult","func":"//if(msg.name==\"Status\"){returnmsg}elseif(msg.name.indexOf(\"Alarms\")!=-1){return[null,msg]}else{return[null,null,msg]}\n\nif (msg.name == \"Status\") {\n  return msg\n} else if(msg.name == \"Alarms\") {\nreturn [null,msg]    \n} else {\nreturn [null,null,msg]\n}\n\n","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1160,"y":320,"wires":[[],[],[]]},{"id":"1244d16a.3f7adf","type":"inject","z":"64187f31.4b904","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"3","crontab":"","once":false,"onceDelay":0.1,"topic":"","payloadType":"date","x":240,"y":320,"wires":[["6db508f3.149ba8"]]},{"id":"6db508f3.149ba8","type":"moment","z":"64187f31.4b904","name":"InjecttimeStamp","topic":"","input":"","inputType":"date","inTz":"America/Chicago","adjAmount":0,"adjType":"days","adjDir":"add","format":"MM/DD/YYhh:mmA","locale":"POSIX","output":"timeStamp","outputType":"msg","outTz":"America/Chicago","x":450,"y":320,"wires":[["7e742181.e1e8b"]]},{"id":"acc10367.8945c","type":"modbus-flex-getter","z":"64187f31.4b904","name":"","showStatusActivities":false,"showErrors":false,"logIOActivities":false,"server":"","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":true,"x":930,"y":320,"wires":[["ba625744.8c9338"],[]]}]
1 Like

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