Slight update: Added header checks - works quite nicely reading 350 registers...
[{"id":"f77e01bf.42f16","type":"inject","z":"5e6c8b.7f38b374","name":"FC4: Read 50 from address 100","props":[{"p":"topic","vt":"str"},{"p":"sid","v":"1","vt":"num"},{"p":"pid","v":"0","vt":"num"},{"p":"len","v":"6","vt":"num"},{"p":"uid","v":"1","vt":"num"},{"p":"fc","v":"4","vt":"num"},{"p":"address","v":"100","vt":"num"},{"p":"registerCount","v":"50","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1602,"y":64,"wires":[["4e227fe.b16e08"]]},{"id":"f662fe41.9f3f3","type":"debug","z":"5e6c8b.7f38b374","name":"modbus response","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2282,"y":240,"wires":[]},{"id":"cef58d63.4cb6","type":"debug","z":"5e6c8b.7f38b374","name":"modbus request","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2272,"y":112,"wires":[]},{"id":"edb7a472.6eebc8","type":"buffer-parser","z":"5e6c8b.7f38b374","name":"Parse Response","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"int16be","name":"header=>sid","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int16be","name":"header=>pid","offset":2,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int16be","name":"header=>len","offset":4,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"header=>uid","offset":6,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"header=>fc","offset":7,"length":1,"offsetbit":0,"scale":"1","mask":"0x7F"},{"type":"uint8","name":"header=>byteCount","offset":8,"length":1,"offsetbit":0,"scale":"1","mask":"0x7F"},{"type":"uint16be","name":"data","offset":9,"length":-1,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"buffer","offset":9,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":2048,"y":176,"wires":[["79e4497c.3006e8"]]},{"id":"4e227fe.b16e08","type":"function","z":"5e6c8b.7f38b374","name":"inc SID","func":"var sid = context.get(\"sid\") || 0;\nsid++;\nif(sid > 250) sid = 0;\ncontext.set(\"sid\", sid) \nmsg.sid = sid;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1852,"y":112,"wires":[["a85ac5f2.9be538"]]},{"id":"a85ac5f2.9be538","type":"buffer-maker","z":"5e6c8b.7f38b374","name":"build MB Request","specification":"spec","specificationType":"ui","items":[{"name":"sid","type":"uint16be","length":1,"dataType":"msg","data":"sid"},{"name":"pid","type":"uint16be","length":1,"dataType":"msg","data":"pid"},{"name":"len","type":"uint16be","length":1,"dataType":"msg","data":"len"},{"name":"uid","type":"byte","length":1,"dataType":"msg","data":"uid"},{"name":"fc","type":"byte","length":1,"dataType":"msg","data":"fc"},{"name":"address","type":"uint16be","length":1,"dataType":"msg","data":"address"},{"name":"registerCount","type":"uint16be","length":1,"dataType":"msg","data":"registerCount"}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","x":2058,"y":112,"wires":[["cef58d63.4cb6","81661067.26948"]]},{"id":"79e4497c.3006e8","type":"function","z":"5e6c8b.7f38b374","name":"check response","func":"var header = msg.payload.header || {};\nvar sidOK = msg.sid == header.sid;\nvar pidOK = msg.pid == header.pid;\nvar uidOK = msg.uid == header.uid;\nvar fcOK = msg.fc == header.fc;\nvar countOK = msg.registerCount == (header.byteCount/2);\nif(!countOK && msg.registerCount > 127) {\n countOK = msg.registerCount == msg.payload.data.length;\n}\n\nvar statText = \"\";\nif(!sidOK) {\n statText = \"SID does not match. Sent: ${msg.sid}, Received: ${header.sid}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!pidOK) {\n statText = \"PID does not match. Sent: ${msg.pid}, Received: ${header.pid}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!uidOK) {\n statText = \"Unit ID does not match. Sent: ${msg.uid}, Received: ${header.uid}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!fcOK) {\n statText = \"FC does not match. Sent: ${msg.fc}, Received: ${header.fc}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!countOK) {\n statText = \"Response register count does not match requested count\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nstatText = `OK. FC: ${msg.fc}, Addr: ${msg.address}[${msg.registerCount}], SID: (${msg.sid}) : Got ${msg.payload.data.length} register(s)` ;\nnode.status({text:statText});\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":2048,"y":240,"wires":[["f662fe41.9f3f3"]]},{"id":"d821be47.eb35a","type":"inject","z":"5e6c8b.7f38b374","name":"FC3: Read 350 from address 0","props":[{"p":"topic","vt":"str"},{"p":"sid","v":"1","vt":"num"},{"p":"pid","v":"0","vt":"num"},{"p":"len","v":"6","vt":"num"},{"p":"uid","v":"1","vt":"num"},{"p":"fc","v":"3","vt":"num"},{"p":"address","v":"0","vt":"num"},{"p":"registerCount","v":"350","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1602,"y":112,"wires":[["4e227fe.b16e08"]]},{"id":"81661067.26948","type":"tcp request","z":"5e6c8b.7f38b374","server":"192.168.1.59","port":"502","out":"sit","splitc":" ","name":"","x":1812,"y":176,"wires":[["edb7a472.6eebc8"]]}]
And you can now set the fc
, address
and registerCount
in the inject.
LIMITATIONS: only fc3 and fc4 are handled (more work required to read coils or write to modbus - but it is possible - feel free to make a modbus (kinda) contrib out of it)