Parse PLC tag value from OMRON Fins node

Need help to parse string
Using OMRON fins node I'm reading tag values but I'm not able to parse them can any one help.
like the tag D2020 value 14384 should be 0800. I've tried to parse but not able to get results.
image

Thats what where the buffer-parser node comes to your rescue.

As documented in the node-red-contrib-omron-fins readme:

Data formats and conversion

As I use multiple PLCs and didn't want to write boolean / 32bit / float / double functionality into each node (it's best to keep things atomic and good at what they do) so I wrote a separate second node for handling data conversions.

This node "node-red-contrib-buffer-parser" node-red-contrib-buffer-parser (node) - Node-RED is capable of pretty much anything you will need for this or any PLC that returns 16bit data or a NodeJS Buffer.

In essence, you pull a bunch of data from the plc in one go & convert it all in the buffer-parser node to almost any format you could wish for (bits, floats, 32bit signed / unsigned, byteswapping etc etc). It can do 1 or many conversions all at once. It can send a grouped item (object) or individual items with a topic ready for pushing your data directly from the PLC to MQTT.

I got the values but instead of 0800 & 1630 I'm getting 8000 & 6103. How do I split & reverse with parse node?

Searched and found one of your solution

but did it differently using function node.
image

Code used in function node :point_down:

var a = parseInt(msg.payload.D2020).toString(16);
var b = parseInt(msg.payload.D2021).toString(16);
var c = parseInt(msg.payload.D2032).toString(16);
var d = parseInt(msg.payload.D2033).toString(16);
var ST_1 = Buffer.from(a, 'hex').toString().split("").reverse().join("");
var ST_2 = Buffer.from(b, 'hex').toString().split("").reverse().join("");
var SP_1 = Buffer.from(c, 'hex').toString().split("").reverse().join("");
var SP_2 = Buffer.from(d, 'hex').toString().split("").reverse().join("");

msg.ST = ST_1+ST_2;
msg.SP = SP_1+SP_2;

return msg;

Post a copy of the data coming out of PLC and I will show you what to do.

Then use the "copy value" button to grab valid JSON and post that in a reply
chrome_CTtKj0dqzH

msg 1

{"_msgid":"47d8c18d1c0a97f0","topic":"","payload":[56,48,48,48],"fins":{"name":"","request":{"command":{"name":"read","command":[1,1],"desc":"MEMORY AREA READ","descExtra":"Reads the contents of consecutive I/O memory area words","params":[{"name":"address","type":"string","required":true},{"name":"count","type":"number","required":true,"min":1}],"commandCode":"0101"},"options":{},"address":{"MemoryArea":"D","Address":2020,"Bit":"","isBitAddress":false,"memoryAreaCode":130,"bytes":[130,7,228,0],"elementLength":2},"count":2,"sid":18},"response":{"remoteHost":"192.168.21.168","sid":18,"command":{"name":"read","command":[1,1],"desc":"MEMORY AREA READ","descExtra":"Reads the contents of consecutive I/O memory area words","params":[{"name":"address","type":"string","required":true},{"name":"count","type":"number","required":true,"min":1}],"commandCode":"0101"},"commandDescription":"read","values":[14384,12336],"buffer":[56,48,48,48],"endCode":"0000","endCodeDescription":"Normal Completion.","MRES":0,"SRES":0,"NetworkRelayError":false,"NonFatalCPUUnitErr":true,"FatalCPUUnitErr":false},"stats":{"replyCount":18,"errorCount":0,"timeoutCount":0,"minReplyMS":41,"maxReplyMS":1530,"msgPerSec":0,"averageReplyMS":218.83333333333334,"runtimeMS":14542151},"createTime":1656498737536,"replyTime":1656498737593,"timeTaken":57}}

msg 2

{"_msgid":"e64ec00d89086324","topic":"","payload":[54,49,48,51],"fins":{"name":"","request":{"command":{"name":"read","command":[1,1],"desc":"MEMORY AREA READ","descExtra":"Reads the contents of consecutive I/O memory area words","params":[{"name":"address","type":"string","required":true},{"name":"count","type":"number","required":true,"min":1}],"commandCode":"0101"},"options":{},"address":{"MemoryArea":"D","Address":2032,"Bit":"","isBitAddress":false,"memoryAreaCode":130,"bytes":[130,7,240,0],"elementLength":2},"count":2,"sid":19},"response":{"remoteHost":"192.168.21.168","sid":19,"command":{"name":"read","command":[1,1],"desc":"MEMORY AREA READ","descExtra":"Reads the contents of consecutive I/O memory area words","params":[{"name":"address","type":"string","required":true},{"name":"count","type":"number","required":true,"min":1}],"commandCode":"0101"},"commandDescription":"read","values":[13873,12339],"buffer":[54,49,48,51],"endCode":"0000","endCodeDescription":"Normal Completion.","MRES":0,"SRES":0,"NetworkRelayError":false,"NonFatalCPUUnitErr":true,"FatalCPUUnitErr":false},"stats":{"replyCount":19,"errorCount":0,"timeoutCount":0,"minReplyMS":41,"maxReplyMS":1530,"msgPerSec":1,"averageReplyMS":209.78947368421052,"runtimeMS":14543370},"createTime":1656498738765,"replyTime":1656498738812,"timeTaken":47}}

I am sure Steve will show you how to use the buffer parser to do this, but you can also use a function node.
e.g.

[{"id":"50f1db63.c306fc","type":"inject","z":"bf9e1e33.030598","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":170,"y":100,"wires":[["a5548432.25b45"]]},{"id":"a5548432.25b45","type":"function","z":"bf9e1e33.030598","name":"","func":"msg = {\"_msgid\":\"47d8c18d1c0a97f0\",\"topic\":\"\",\"payload\":[56,48,48,48],\"fins\":{\"name\":\"\",\"request\":{\"command\":{\"name\":\"read\",\"command\":[1,1],\"desc\":\"MEMORY AREA READ\",\"descExtra\":\"Reads the contents of consecutive I/O memory area words\",\"params\":[{\"name\":\"address\",\"type\":\"string\",\"required\":true},{\"name\":\"count\",\"type\":\"number\",\"required\":true,\"min\":1}],\"commandCode\":\"0101\"},\"options\":{},\"address\":{\"MemoryArea\":\"D\",\"Address\":2020,\"Bit\":\"\",\"isBitAddress\":false,\"memoryAreaCode\":130,\"bytes\":[130,7,228,0],\"elementLength\":2},\"count\":2,\"sid\":18},\"response\":{\"remoteHost\":\"192.168.21.168\",\"sid\":18,\"command\":{\"name\":\"read\",\"command\":[1,1],\"desc\":\"MEMORY AREA READ\",\"descExtra\":\"Reads the contents of consecutive I/O memory area words\",\"params\":[{\"name\":\"address\",\"type\":\"string\",\"required\":true},{\"name\":\"count\",\"type\":\"number\",\"required\":true,\"min\":1}],\"commandCode\":\"0101\"},\"commandDescription\":\"read\",\"values\":[14384,12336],\"buffer\":[56,48,48,48],\"endCode\":\"0000\",\"endCodeDescription\":\"Normal Completion.\",\"MRES\":0,\"SRES\":0,\"NetworkRelayError\":false,\"NonFatalCPUUnitErr\":true,\"FatalCPUUnitErr\":false},\"stats\":{\"replyCount\":18,\"errorCount\":0,\"timeoutCount\":0,\"minReplyMS\":41,\"maxReplyMS\":1530,\"msgPerSec\":0,\"averageReplyMS\":218.83333333333334,\"runtimeMS\":14542151},\"createTime\":1656498737536,\"replyTime\":1656498737593,\"timeTaken\":57}}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":280,"y":40,"wires":[["a5c616f2.65744"]]},{"id":"a5c616f2.65744","type":"function","z":"bf9e1e33.030598","name":"","func":"msg.payload = Number(Buffer.from(msg.payload).toString())\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":440,"y":100,"wires":[["d81fd4ee.9943e8"]]},{"id":"d81fd4ee.9943e8","type":"debug","z":"bf9e1e33.030598","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":640,"y":100,"wires":[]}]
msg.payload = Number(Buffer.from(msg.payload).toString())
return msg;
1 Like

So yes, you can but it is a cludge due to the format of the source data in the PLC.

Your data is using 16 bits to store 8 bit ascii characters.

e.g. a byte view of your data for the string 1630 is
DEC : [0,54,0,49,0,48,0,51] ==>
HEX : [00,36,00,31,00,30,00,33] ==>
ASCII: [null,'6',null,'1',null,'0',null,'3']

When swapped by 32 that becomes...
DEC : [49,0,54,0,51,0,48,0] ==>
HEX : [31,00,36,00,33,00,30,00] ==>
ASCII: ['1', null, '6', null, '3', null, '0', null]

Anyhow, doing a swap32 then (ab)using the UFT16 formatter, you can read the text ...

demo flow...

[{"id":"95ae180e0279963e","type":"inject","z":"d8bcc25e815f0bc3","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1125,"y":840,"wires":[["971e05a4f5397cda"]],"l":false},{"id":"971e05a4f5397cda","type":"function","z":"d8bcc25e815f0bc3","name":"FINS Response for D2020","func":"msg = { \"_msgid\": \"47d8c18d1c0a97f0\", \"topic\": \"\", \"payload\": [56, 48, 48, 48], \"fins\": { \"name\": \"\", \"request\": { \"command\": { \"name\": \"read\", \"command\": [1, 1], \"desc\": \"MEMORY AREA READ\", \"descExtra\": \"Reads the contents of consecutive I/O memory area words\", \"params\": [{ \"name\": \"address\", \"type\": \"string\", \"required\": true }, { \"name\": \"count\", \"type\": \"number\", \"required\": true, \"min\": 1 }], \"commandCode\": \"0101\" }, \"options\": {}, \"address\": { \"MemoryArea\": \"D\", \"Address\": 2020, \"Bit\": \"\", \"isBitAddress\": false, \"memoryAreaCode\": 130, \"bytes\": [130, 7, 228, 0], \"elementLength\": 2 }, \"count\": 2, \"sid\": 18 }, \"response\": { \"remoteHost\": \"192.168.21.168\", \"sid\": 18, \"command\": { \"name\": \"read\", \"command\": [1, 1], \"desc\": \"MEMORY AREA READ\", \"descExtra\": \"Reads the contents of consecutive I/O memory area words\", \"params\": [{ \"name\": \"address\", \"type\": \"string\", \"required\": true }, { \"name\": \"count\", \"type\": \"number\", \"required\": true, \"min\": 1 }], \"commandCode\": \"0101\" }, \"commandDescription\": \"read\", \"values\": [14384, 12336], \"buffer\": [56, 48, 48, 48], \"endCode\": \"0000\", \"endCodeDescription\": \"Normal Completion.\", \"MRES\": 0, \"SRES\": 0, \"NetworkRelayError\": false, \"NonFatalCPUUnitErr\": true, \"FatalCPUUnitErr\": false }, \"stats\": { \"replyCount\": 18, \"errorCount\": 0, \"timeoutCount\": 0, \"minReplyMS\": 41, \"maxReplyMS\": 1530, \"msgPerSec\": 0, \"averageReplyMS\": 218.83333333333334, \"runtimeMS\": 14542151 }, \"createTime\": 1656498737536, \"replyTime\": 1656498737593, \"timeTaken\": 57 } }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1290,"y":840,"wires":[["38bc220a3d211942"]]},{"id":"2627f3d9713d40f1","type":"function","z":"d8bcc25e815f0bc3","name":"FINS Response for D2032","func":"msg = { \"_msgid\": \"e64ec00d89086324\", \"topic\": \"\", \"payload\": [54, 49, 48, 51], \"fins\": { \"name\": \"\", \"request\": { \"command\": { \"name\": \"read\", \"command\": [1, 1], \"desc\": \"MEMORY AREA READ\", \"descExtra\": \"Reads the contents of consecutive I/O memory area words\", \"params\": [{ \"name\": \"address\", \"type\": \"string\", \"required\": true }, { \"name\": \"count\", \"type\": \"number\", \"required\": true, \"min\": 1 }], \"commandCode\": \"0101\" }, \"options\": {}, \"address\": { \"MemoryArea\": \"D\", \"Address\": 2032, \"Bit\": \"\", \"isBitAddress\": false, \"memoryAreaCode\": 130, \"bytes\": [130, 7, 240, 0], \"elementLength\": 2 }, \"count\": 2, \"sid\": 19 }, \"response\": { \"remoteHost\": \"192.168.21.168\", \"sid\": 19, \"command\": { \"name\": \"read\", \"command\": [1, 1], \"desc\": \"MEMORY AREA READ\", \"descExtra\": \"Reads the contents of consecutive I/O memory area words\", \"params\": [{ \"name\": \"address\", \"type\": \"string\", \"required\": true }, { \"name\": \"count\", \"type\": \"number\", \"required\": true, \"min\": 1 }], \"commandCode\": \"0101\" }, \"commandDescription\": \"read\", \"values\": [13873, 12339], \"buffer\": [54, 49, 48, 51], \"endCode\": \"0000\", \"endCodeDescription\": \"Normal Completion.\", \"MRES\": 0, \"SRES\": 0, \"NetworkRelayError\": false, \"NonFatalCPUUnitErr\": true, \"FatalCPUUnitErr\": false }, \"stats\": { \"replyCount\": 19, \"errorCount\": 0, \"timeoutCount\": 0, \"minReplyMS\": 41, \"maxReplyMS\": 1530, \"msgPerSec\": 1, \"averageReplyMS\": 209.78947368421052, \"runtimeMS\": 14543370 }, \"createTime\": 1656498738765, \"replyTime\": 1656498738812, \"timeTaken\": 47 } }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1290,"y":880,"wires":[["38bc220a3d211942"]]},{"id":"16f9e4c856d7c845","type":"inject","z":"d8bcc25e815f0bc3","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1125,"y":880,"wires":[["2627f3d9713d40f1"]],"l":false},{"id":"38bc220a3d211942","type":"buffer-parser","z":"d8bcc25e815f0bc3","name":"","data":"fins.response.buffer","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"utf16le","name":"hour","offset":0,"length":4,"offsetbit":0,"scale":"-0x30","mask":""},{"type":"utf16le","name":"min","offset":4,"length":4,"offsetbit":0,"scale":"-0x30","mask":""},{"type":"utf16le","name":"time","offset":0,"length":8,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"databytes","offset":0,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"swap32","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"return","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":1560,"y":860,"wires":[["e74172d25a40e617","16a1f1aca78f25a7"]]},{"id":"65e715cf886adbed","type":"debug","z":"d8bcc25e815f0bc3","name":"post-processed","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1760,"y":920,"wires":[]},{"id":"e74172d25a40e617","type":"function","z":"d8bcc25e815f0bc3","name":"post processing","func":"msg.payload.time = msg.payload.hour.padStart(2, \"0\") + \":\" + msg.payload.min.padStart(2,\"0\")\nmsg.payload.hour = parseInt(msg.payload.hour)\nmsg.payload.min = parseInt(msg.payload.min)\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1570,"y":920,"wires":[["65e715cf886adbed"]]},{"id":"16a1f1aca78f25a7","type":"debug","z":"d8bcc25e815f0bc3","name":"buffer-parser","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1750,"y":860,"wires":[]}]

Better solutions (from best to worst)...

Store the values in the PLC as actual numbers e.g.
DM2020: 16
DM2021: 30

Or store the "text" as ASCII chars
DM2020: 0x3631
DM2021: 0x3033

Or store the time as BCD
DM2020: 0x1630

1 Like

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