Select Page

OPC UA - PLC communication

 

Applies to

Sensoft Multiline
Sensoft Vision

 

Question

How can I communicate with a PLC if it is not OPC-UA capable?

 

Answer

Modern PLC are either OPC-UA capable either they have OPC-UA modules available. By defining the required OPC-UA variables, the PLC can directly operate the Sensoft and get the Alarm status, for example.

Older PLC's may not be OPC-UA capable, but support other communication protocols such as Modbus or OPC. In that situation the use of Node-RED may be helpful. Node-RED provides a browser-based flow editor that makes it easy to wire together flows using the wide range of nodes in the palette. Node-RED has an OPC-UA module and many others modules to communicate with PLC's (S7CP1E, PM3200,...) or databases (mysql, sqlite, influx, ... ). With the communication to databases, the integration could be improved by retrieving and sending to the Sensoft  information such as the nominal diameter, the order number or the type of product, that are not always available on the PLC. The Node-RED program can run on the same computer as the Sensoft  or on a low-cost hardware such as a Raspberry Pi.

Below there is a Node-RED example of communication with the Sensoft Multiline from a web browser through OPC-UA. This example requires that the OPC-UA license is enabled on the PC running the Sensoft Multiline. Node-RED requires the node-red-contrib-opcua and the node-red-dashboard palettes.

[{"id":"5ab0396f.e9977","type":"tab","label":"Multiline-Dashboard","disabled":false,"info":""},{"id":"3e9c6215.2b9e16","type":"OpcUa-Client","z":"5ab0396f.e9977","endpoint":"288b951c.a28c2a","action":"write","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"Write","x":690,"y":580,"wires":[["f30d8815.080888"]]},{"id":"f32d80b.ea1ff","type":"inject","z":"5ab0396f.e9977","name":"Start","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.1","topic":"","payload":"","payloadType":"str","x":130,"y":100,"wires":[["a828434a.ee8438"]]},{"id":"a828434a.ee8438","type":"OpcUa-Item","z":"5ab0396f.e9977","item":"ns=2;s=Device.From Sensoft.Line names","datatype":"String Array","value":"","name":"","x":300,"y":100,"wires":[["e7175a95.867438"]]},{"id":"f30d8815.080888","type":"debug","z":"5ab0396f.e9977","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":850,"y":580,"wires":[]},{"id":"e262d9d.46eeba8","type":"comment","z":"5ab0396f.e9977","name":"Read the Lines Names","info":"","x":140,"y":60,"wires":[]},{"id":"195d310f.abcf1f","type":"comment","z":"5ab0396f.e9977","name":"Lines names are stored on the 'Lines' flow variable","info":"","x":670,"y":60,"wires":[]},{"id":"4eae2468.c1df8c","type":"comment","z":"5ab0396f.e9977","name":"Line 1: Start/Stop switch","info":"","x":150,"y":540,"wires":[]},{"id":"e45b0b23.df991","type":"ui_switch","z":"5ab0396f.e9977","name":"","label":"Start/Stop","tooltip":"","group":"d4e9ee6a.f6764","order":2,"width":6,"height":1,"passthru":true,"decouple":"false","topic":"topic","topicType":"msg","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","animate":false,"className":"","x":140,"y":580,"wires":[["6acde77a.a9393"]]},{"id":"6acde77a.a9393","type":"function","z":"5ab0396f.e9977","name":"Line 1 Start/Stop","func":"msg.datatype=\"Boolean\";\nif (msg.payload){\n    msg.topic=\"ns=2;s=Device.To Sensoft.\" + flow.get('Lines')[0] + \".Start\";\n    return msg;\n} else {\n    msg.payload=!msg.payload; // when swhitched off send True to the Stop variable\n    msg.topic=\"ns=2;s=Device.To Sensoft.\" + flow.get('Lines')[0] + \".Stop\";\n    return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":410,"y":580,"wires":[["3e9c6215.2b9e16"]]},{"id":"b9375e4f.e0df3","type":"ui_numeric","z":"5ab0396f.e9977","name":"","label":"Nominal diameter","tooltip":"","group":"d4e9ee6a.f6764","order":7,"width":6,"height":1,"wrap":false,"passthru":true,"topic":"topic","topicType":"msg","format":"{{msg.payload}}","min":"1","max":"5000","step":1,"className":"","x":170,"y":640,"wires":[["ccec70a.be1381"]]},{"id":"ccec70a.be1381","type":"function","z":"5ab0396f.e9977","name":"Line 1 Nominal diameter","func":"msg.topic=\"ns=2;s=Device.To Sensoft.\" + flow.get('Lines')[0] + \".Next.Diameter [um]\";\nmsg.datatype=\"Double\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":430,"y":640,"wires":[["3e9c6215.2b9e16"]]},{"id":"4bec7155.43089","type":"OpcUa-Client","z":"5ab0396f.e9977","endpoint":"288b951c.a28c2a","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"0","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"Subscribe","x":460,"y":280,"wires":[["bdc64003.ffb44"]]},{"id":"4832517e.d8ab5","type":"function","z":"5ab0396f.e9977","name":"Last Fault","func":"outmsg=[];\noutmsg[0]={};\noutmsg[0].topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Last fault.Nr\";\noutmsg[0].datatype=\"Int32\";\noutmsg[1]={};\noutmsg[1].topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Last fault.Time\";\noutmsg[1].datatype=\"DateTime\";\noutmsg[2]={};\noutmsg[2].topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Last fault.Position [m]\";\noutmsg[2].datatype=\"Double\";\noutmsg[3]={};\noutmsg[3].topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Last fault.Size [um]\";\noutmsg[3].datatype=\"Double\";\nreturn [outmsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":240,"y":280,"wires":[["4bec7155.43089"]]},{"id":"e75006ea.1f9e","type":"function","z":"5ab0396f.e9977","name":"Warnings/Alarms","func":"outmsg=[];\noutmsg[0]={};\noutmsg[0].topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Alerts.Nr of alarms\";\noutmsg[0].datatype=\"Int32\";\noutmsg[1]={};\noutmsg[1].topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Alerts.Nr of warnings\";\noutmsg[1].datatype=\"Int32\";\nreturn [outmsg];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":270,"y":360,"wires":[["6aa421a4.e14eb8"]]},{"id":"de7675ee.f3b018","type":"function","z":"5ab0396f.e9977","name":"Set Lines names","func":"flow.set('Lines',msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":100,"wires":[["d021adac.47f63"]]},{"id":"bdc64003.ffb44","type":"function","z":"5ab0396f.e9977","name":"Last Fault","func":"outmsg= Array.from({length: 4});\nvarname=msg.topic.split(\".\");\nswitch (varname[varname.length-1]){\ncase \"Nr\":\n outmsg[0]=msg;\nbreak;\n \ncase \"Time\":\n outmsg[1]=msg;\nbreak;\n\ncase \"Position [m]\":\n outmsg[2]=msg;\nbreak;\n\ncase \"Size [um]\":\n outmsg[3]=msg;\nbreak;\n} \n\nreturn outmsg;","outputs":4,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":280,"wires":[["4ae5b5ee.8cb7c4"],["f34b7f9a.336ef"],["9ce44a8c.bcf9b"],["562350d3.288408"]]},{"id":"6aa421a4.e14eb8","type":"OpcUa-Client","z":"5ab0396f.e9977","endpoint":"288b951c.a28c2a","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"0","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"Subscribe","x":460,"y":360,"wires":[["a994f09f.ca2c6"]]},{"id":"a994f09f.ca2c6","type":"function","z":"5ab0396f.e9977","name":"# Alerts","func":"outmsg= Array.from({length: 2});\nvarname=msg.topic.split(\".\");\nswitch (varname[varname.length-1]){\ncase \"Nr of alarms\":\n outmsg[0]=msg;\nbreak;\n \ncase \"Nr of warnings\":\n outmsg[1]=msg;\nbreak;\n} \nreturn outmsg;","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":640,"y":360,"wires":[["809287bd.4da87"],["bcfee97f.7a2ce"]]},{"id":"4ae5b5ee.8cb7c4","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":28,"width":6,"height":1,"name":"","label":"Nr","format":"{{msg.payload}}","layout":"row-spread","className":"","x":850,"y":220,"wires":[]},{"id":"f34b7f9a.336ef","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":32,"width":6,"height":1,"name":"","label":"Time","format":"{{msg.payload | date:'HH:mm:ss'}}","layout":"row-spread","className":"","x":850,"y":260,"wires":[]},{"id":"9ce44a8c.bcf9b","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":36,"width":6,"height":1,"name":"","label":"Position","format":"{{value | number:3}} m","layout":"row-spread","className":"","x":860,"y":300,"wires":[]},{"id":"562350d3.288408","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":40,"width":6,"height":1,"name":"","label":"Size","format":"{{value | number:1}} µm","layout":"row-spread","className":"","x":850,"y":340,"wires":[]},{"id":"809287bd.4da87","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":17,"width":6,"height":1,"name":"","label":"Nr of alarms","format":"{{msg.payload}}","layout":"row-spread","className":"","x":870,"y":380,"wires":[]},{"id":"bcfee97f.7a2ce","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":13,"width":6,"height":1,"name":"","label":"Nr of warnings","format":"{{msg.payload}}","layout":"row-spread","className":"","x":880,"y":420,"wires":[]},{"id":"dfb35c2b.1b9fb","type":"ui_text","z":"5ab0396f.e9977","group":"d4e9ee6a.f6764","order":23,"width":6,"height":1,"name":"","label":"Last fault","format":"{{msg.payload}}","layout":"row-spread","className":"","x":860,"y":180,"wires":[]},{"id":"607f5c68.15833c","type":"inject","z":"5ab0396f.e9977","name":"","props":[{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"Last Fault","x":670,"y":180,"wires":[["dfb35c2b.1b9fb"]]},{"id":"6bd53226.b46dac","type":"function","z":"5ab0396f.e9977","name":"Mean data","func":"msg.topic=\"ns=2;s=Device.From Sensoft.\" + flow.get('Lines')[0] + \".Mean data\";\nmsg.datatype=\"Double Array\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":250,"y":460,"wires":[["fd288229.8d315"]]},{"id":"fd288229.8d315","type":"OpcUa-Client","z":"5ab0396f.e9977","endpoint":"288b951c.a28c2a","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"0","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"Subscribe","x":460,"y":460,"wires":[["813f6ee2.ea9fd8"]]},{"id":"813f6ee2.ea9fd8","type":"function","z":"5ab0396f.e9977","name":"Mean data","func":"outmsg=[];\noutmsg[0]={};\noutmsg[0].payload=msg.payload[2] + msg.payload[3]; //relative diameter + ovality\noutmsg[0].topic=\"Relative Ø X [um]\";\noutmsg[1]={};\noutmsg[1].payload=msg.payload[2] - msg.payload[3]; //relative diameter - ovality\noutmsg[1].topic=\"Relative Ø Y [um]\";\noutmsg[2]={};\noutmsg[2].payload=msg.payload[4]; //max LU\noutmsg[2].topic=\"Max LU [um]\";\noutmsg[3]={};\noutmsg[3].payload=-msg.payload[5]; //max NE\noutmsg[3].topic=\"Max NE [um]\";\nreturn outmsg;","outputs":4,"noerr":0,"initialize":"","finalize":"","libs":[],"x":650,"y":460,"wires":[["7114ad4e.96b3c4"],["7114ad4e.96b3c4"],["a0b19457.072658"],["a0b19457.072658"]]},{"id":"7114ad4e.96b3c4","type":"ui_chart","z":"5ab0396f.e9977","name":"","group":"d4e9ee6a.f6764","order":4,"width":7,"height":6,"label":"Relative Ø","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#ec1818","#ff7f0e","#2ca02c","#98df8a","#28abd7","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":870,"y":460,"wires":[[]]},{"id":"a0b19457.072658","type":"ui_chart","z":"5ab0396f.e9977","name":"","group":"d4e9ee6a.f6764","order":25,"width":7,"height":6,"label":"Max Lump & Neck-down","chartType":"line","legend":"true","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#fa67f7","#ff7f0e","#2ca02c","#98df8a","#11c6ec","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"className":"","x":910,"y":500,"wires":[[]]},{"id":"cba3319d.8b8628","type":"comment","z":"5ab0396f.e9977","name":"Line 1: Subscribe to variables","info":"","x":160,"y":220,"wires":[]},{"id":"e7175a95.867438","type":"OpcUa-Client","z":"5ab0396f.e9977","endpoint":"288b951c.a28c2a","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"0","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"Subscribe","x":480,"y":100,"wires":[["de7675ee.f3b018"]]},{"id":"d021adac.47f63","type":"link out","z":"5ab0396f.e9977","name":"Got lines names","links":["a324010a.1ea9f"],"x":815,"y":100,"wires":[]},{"id":"a324010a.1ea9f","type":"link in","z":"5ab0396f.e9977","name":"Update subscriptions","links":["d021adac.47f63"],"x":75,"y":280,"wires":[["4832517e.d8ab5","e75006ea.1f9e","6bd53226.b46dac"]]},{"id":"288b951c.a28c2a","type":"OpcUa-Endpoint","endpoint":"opc.tcp://192.168.1.120:4840","secpol":"None","secmode":"None","login":false},{"id":"d4e9ee6a.f6764","type":"ui_group","z":"5ab0396f.e9977","name":"Multiline (Dashboard)","tab":"c2e39485.e5f0f8","order":2,"disp":true,"width":"16","collapse":false,"className":""},{"id":"c2e39485.e5f0f8","type":"ui_tab","name":"Sensoft Multiline","icon":"dashboard","order":2,"disabled":false,"hidden":false}]

Node-RED flow communication with the Sensoft Multiline from a web browser through OPC-UA example

Below there is a Node-RED example of communication with the Sensoft Vision. The diameter and winder status of a MAG machine is retrieved from a MySQL database. The OPC-UA corresponding variables are updated according to the data read from the database. This example requires that the OPC-UA license is enabled on the PC running the Sensoft Vision. Node-RED requires the an node-red-contrib-opcua and the node-red-node-mysql palettes.

[{"id":"672cd33f.a77de4","type":"tab","label":"mysql","disabled":false,"info":""},{"id":"dafc6729.00c6d","type":"mysql","z":"672cd33f.a77de4","mydb":"e57c48ef.20c928","name":"mySQL","x":500,"y":80,"wires":[["7f2ef14d.0db148"]]},{"id":"dbeb13b4.28214","type":"function","z":"672cd33f.a77de4","name":"Query","func":"msg.topic=\"select timestamp,A176BWI_NX_SETDI2_VAL0,A117DRI_NW_SETSPE_VAL0,A151DRI_NR_ACTREV_VAL0,A152DRI_NR_ACTREV_VAL0 from dbo_GROUP_LOG_1 where timestamp = (select max(timestamp) from dbo_GROUP_LOG_1);\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":350,"y":80,"wires":[["dafc6729.00c6d"]]},{"id":"decd4807.a57c98","type":"inject","z":"672cd33f.a77de4","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"5","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":190,"y":80,"wires":[["dbeb13b4.28214"]]},{"id":"3785a0aa.b174f8","type":"debug","z":"672cd33f.a77de4","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":950,"y":140,"wires":[]},{"id":"7f2ef14d.0db148","type":"function","z":"672cd33f.a77de4","name":"mySQL data -> OPC-UA","func":"var LastQuery=flow.get('LastQuery');\nvar CurrentQuery=msg.payload[0];\nvar i=0;\noutmsg=[];\nif (new Date(CurrentQuery.timestamp) > new Date(flow.get('LastQuery').timestamp)) {\n if (CurrentQuery.A176BWI_NX_SETDI2_VAL0 != LastQuery.A176BWI_NX_SETDI2_VAL0) {\n let diameter=CurrentQuery.A176BWI_NX_SETDI2_VAL0;\n outmsg[i]={\n topic: \"ns=2;s=Device.To Sensoft.Nominal diameter [um]\", //OPC-UA Nominal Diameter variable\n datatype: \"Double\",\n payload: diameter,\n// number: [0, 0, 0 ,0 ,0]\n };\n i=i+1;\n }\n let W1O=(LastQuery.A151DRI_NR_ACTREV_VAL0 > 0) === true ? 1 : 0 // W1 running? last query\n let W1N=(CurrentQuery.A151DRI_NR_ACTREV_VAL0 > 0) === true ? 1 : 0; // W1 running? current query\n let W2O=(LastQuery.A152DRI_NR_ACTREV_VAL0 > 0 ) === true ? 1 : 0 // W2 running? last query\n let W2N=(CurrentQuery.A152DRI_NR_ACTREV_VAL0 > 0 ) === true ? 1 : 0;// W2 running? current query\n let number=8*W1O + 4*W1N + 2*W2O + W2N;\n // we build a number containging the status of the winders W1 & W2:\n // based on the number a Start, Stop or Stop and Start are sent to Vision through OPC-UA\n if (number==1 || number==4 || number==5) { // W1 or W2 or both passed from 0 to 1 state\n outmsg[i]={};\n outmsg[i].topic=\"ns=2;s=Device.To Sensoft.Start\"; //OPC-UA Start variable\n outmsg[i].datatype=\"Boolean\";\n outmsg[i].payload=\"false\";\n// outmsg[i].number=[W1O, W1N, W2O, W2N, number];\n i=i+1; \n }\n if (number==2 || number==8 || number==10) { // W1 or W2 or both passed from 1 to 0 state\n outmsg[i]={};\n outmsg[i].topic=\"ns=2;s=Device.To Sensoft.Stop\"; //OPC-UA Stop variable\n outmsg[i].datatype=\"Boolean\";\n outmsg[i].payload=\"false\";\n// outmsg[i].number=[W1O, W1N, W2O, W2N, number];\n i=i+1; \n } \n if (number==6 || number==7 || number==9 || number==13) { // Changed active winder -> Spool change\n outmsg[i]={};\n outmsg[i].topic=\"ns=2;s=Device.To Sensoft.Stop\"; //OPC-UA Stop variable\n outmsg[i].datatype=\"Boolean\";\n outmsg[i].payload=\"false\";\n// outmsg[i].number=[W1O, W1N, W2O, W2N, number];\n i=i+1; \n outmsg[i]={};\n outmsg[i].topic=\"ns=2;s=Device.To Sensoft.Start\"; //OPC-UA Start variable\n outmsg[i].datatype=\"Boolean\";\n outmsg[i].payload=\"false\";\n// outmsg[i].number=[W1O, W1N, W2O, W2N, number];\n i=i+1; \n } \n // evaluate spooler change and eventually add Stop, Start or Stop/Start outmsg\n flow.set('LastQuery',CurrentQuery);\n return [outmsg];\n}\n// if no new record with new timestamp: do nothing","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nflow.set('LastQuery', {\n timestamp: new Date(\"1970-01-01T01:00:00.000\"),\n A176BWI_NX_SETDI2_VAL0: 0,\n A151DRI_NR_ACTREV_VAL0: 0, \n A152DRI_NR_ACTREV_VAL0: 0 });","finalize":"","libs":[],"x":710,"y":80,"wires":[["d6f1b855.b2b31","3785a0aa.b174f8"]]},{"id":"d6f1b855.b2b31","type":"OpcUa-Client","z":"672cd33f.a77de4","endpoint":"994122e8aae3c147","action":"write","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"Write","x":950,"y":80,"wires":[[]]},{"id":"e57c48ef.20c928","type":"MySQLdatabase","name":"","host":"192.168.1.101","port":"3306","db":"sensoft_ml","tz":"","charset":"UTF8"},{"id":"994122e8aae3c147","type":"OpcUa-Endpoint","endpoint":"opc.tcp://192.168.1.120:4840","secpol":"None","secmode":"None","login":false}]

Node-RED flow Sensoft Vision control from a mySQL database through OPC-UA example