Passa al contenuto principale

OPC UA client con Node-RED

Node-RED è uno strumento di programmazione per collegare insieme dispositivi hardware, API e servizi online in modi nuovi e interessanti. Tramite un editor basato su browser è possibile collegare tra di loro oggetti (Flows) utilizzando l'ampia gamma oggetti disponibili.

Ho già spiegato in questo articolo come installare Node-RED sui nostri sistemi basati su Raspberry, ora vedremo come utilizzare Node-RED per dialogare con altri sistemi utilizzando il protocollo (OPC UA)  Open Platform Communications Unified Architecture un protocollo unificato di comunicazione per l'automazione industriale.

Installazione nodo OPC UA​

Nella installazione standard di Node-RED viene installata una base di nodi, quelli più comunemente utilizzati, ma esiste una libreria enorme di nodi utilizzabili. Per utilizzare il protocollo OPC UA occorre installare i nodi forniti con node-red-contrib-opcua. L'installazione può essere fatta da riga di comando con (npm) Node Package Manager, oppure più semplicemente da browser.

Dal menù scegliere Manage palette, poi cercare il modulo node-red-contrib-opcua e procedere con l'installazione, per testare l'esempio occorre anche installare il modulo node-red-dashboard.

Node-RED_contrib_opcua

Ecco il programma​

Sotto si può vedere il programma in Node-RED con la relativa dashboard che si connette al programma SimpleOPCUA sviluppato con CODESYS, entrambi i programmi sono eseguiti dallo stesso modulo CPU SlimLine Raspberry.

Node-RED_SimpleOPCUA

La comunicazione con il server OPC UA di CODESYS è svolta dal nodo OpcUa Client in cui viene definito come Endpoint l'indirizzo e porta del server OPC UA (Nell'esempio è opc.tcp://192.168.0.180:4840). Naturalmente girando entrambi i programmi sullo stesso processore avrei potuto definire opc.tcp://localhost:4840. Nelle operazioni di lettura (Variabili DIStatus e Counter) verrà definita Action READ, nelle operazioni di scrittura (Variabile DOCommand) verrà definita Action WRITE.

In entrata all'OpcUa Client si trova l'oggetto OpcUa Item che specifica il NodeId della variabile cui accedere da riportare nel campo Item, per individuare il valore da scrivere utilizzare il programma UaExpert come indicato qui. Nell'esempio avremo:

DIStatus: ns=4;s=|var|CODESYS Control for Raspberry Pi SL.Application.PLC_PRG.DIStatus DOCommand: ns=4;s=|var|CODESYS Control for Raspberry Pi SL.Application.PLC_PRG.DOCommand Counter: ns=4;s=|var|CODESYS Control for Raspberry Pi SL.Application.PLC_PRG.Counter

Nel campo Type andrà definito il tipo della variabile:

DIStatus: Boolean DOCommand: Boolean Counter: UInt32

Tuti gli altri nodi servono ad attivare a tempo l'esecuzione dei nodi OPC UA ed a visualizzare i dati sulla dashboard.

Codice sorgente Node-RED

Per testare l'esempio è possibile copiare il codice seguente ed incollarlo in un progetto vuoto, naturalmente dovrà essere in esecuzione il programma CODESYS SimpleUPCUA. Ricordarsi di modificare l'indirizzo IP del Server OPCUA.

[{"id":"78a821d6.71cc3","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"a5fa9e01.cfaf6","type":"OpcUa-Endpoint","z":"","endpoint":"opc.tcp://192.168.0.180:4840","secpol":"None","secmode":"NONE","login":false},{"id":"888fe058.d1598","type":"ui_base","theme":{"name":"theme-light","lightTheme":{"default":"#0094CE","baseColor":"#0094CE","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":true,"reset":false},"darkTheme":{"default":"#097479","baseColor":"#097479","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif","edited":false},"customTheme":{"name":"Untitled Theme 1","default":"#4B7930","baseColor":"#4B7930","baseFont":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"},"themeState":{"base-color":{"default":"#0094CE","value":"#0094CE","edited":false},"page-titlebar-backgroundColor":{"value":"#0094CE","edited":false},"page-backgroundColor":{"value":"#fafafa","edited":false},"page-sidebar-backgroundColor":{"value":"#ffffff","edited":false},"group-textColor":{"value":"#1bbfff","edited":false},"group-borderColor":{"value":"#ffffff","edited":false},"group-backgroundColor":{"value":"#ffffff","edited":false},"widget-textColor":{"value":"#111111","edited":false},"widget-backgroundColor":{"value":"#0094ce","edited":false},"widget-borderColor":{"value":"#ffffff","edited":false},"base-font":{"value":"-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif"}},"angularTheme":{"primary":"indigo","accents":"blue","warn":"red","background":"grey"}},"site":{"name":"Node-RED Dashboard","hideToolbar":"false","allowSwipe":"false","lockMenu":"false","allowTempTheme":"true","dateFormat":"DD/MM/YYYY","sizes":{"sx":48,"sy":48,"gx":6,"gy":6,"cx":6,"cy":6,"px":0,"py":0}}},{"id":"fefa668f.751fc8","type":"ui_tab","z":"","name":"Main","icon":"dashboard","order":1,"disabled":false,"hidden":false},{"id":"1c67e3b2.585c7c","type":"ui_group","z":"","name":"My Dashboard","tab":"fefa668f.751fc8","order":1,"disp":true,"width":"6","collapse":false},{"id":"a9407375.ad7b","type":"inject","z":"78a821d6.71cc3","name":"","topic":"","payload":"1","payloadType":"num","repeat":"1","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":300,"wires":[["a9cc134f.3c259"]]},{"id":"a9cc134f.3c259","type":"OpcUa-Item","z":"78a821d6.71cc3","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi SL.Application.PLC_PRG.Counter","datatype":"UInt32","value":"","name":"","x":320,"y":300,"wires":[["3b553ad1.95c7e6"]]},{"id":"3b553ad1.95c7e6","type":"OpcUa-Client","z":"78a821d6.71cc3","endpoint":"a5fa9e01.cfaf6","action":"read","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","name":"","x":520,"y":300,"wires":[["954e9722.cdd3a8","a5077176.e41b4"]]},{"id":"954e9722.cdd3a8","type":"ui_text","z":"78a821d6.71cc3","group":"1c67e3b2.585c7c","order":0,"width":0,"height":0,"name":"","label":"Counter","format":"{{msg.payload}}","layout":"row-spread","x":700,"y":300,"wires":[]},{"id":"a978aa03.2e7fd8","type":"ui_switch","z":"78a821d6.71cc3","name":"","label":"DOCommand","tooltip":"","group":"1c67e3b2.585c7c","order":1,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":120,"y":180,"wires":[["2df7e872.48a7d8"]]},{"id":"2df7e872.48a7d8","type":"OpcUa-Item","z":"78a821d6.71cc3","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi SL.Application.PLC_PRG.DOCommand","datatype":"Boolean","value":"","name":"","x":320,"y":180,"wires":[["69afc737.ac9a18"]]},{"id":"69afc737.ac9a18","type":"OpcUa-Client","z":"78a821d6.71cc3","endpoint":"a5fa9e01.cfaf6","action":"write","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","name":"","x":520,"y":180,"wires":[["8dd2298c.0a7b98"]]},{"id":"8dd2298c.0a7b98","type":"debug","z":"78a821d6.71cc3","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":710,"y":180,"wires":[]},{"id":"a5077176.e41b4","type":"debug","z":"78a821d6.71cc3","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":710,"y":240,"wires":[]},{"id":"f030e24.9615b2","type":"OpcUa-Item","z":"78a821d6.71cc3","item":"ns=4;s=|var|CODESYS Control for Raspberry Pi SL.Application.PLC_PRG.DIStatus","datatype":"Boolean","value":"","name":"","x":320,"y":100,"wires":[["5fc5f389.f3337c"]]},{"id":"5fc5f389.f3337c","type":"OpcUa-Client","z":"78a821d6.71cc3","endpoint":"a5fa9e01.cfaf6","action":"read","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","name":"","x":520,"y":100,"wires":[["135032e8.ef2d5d"]]},{"id":"a10173b4.131ff","type":"inject","z":"78a821d6.71cc3","name":"","topic":"","payload":"1","payloadType":"num","repeat":"1","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":100,"wires":[["f030e24.9615b2"]]},{"id":"135032e8.ef2d5d","type":"ui_text","z":"78a821d6.71cc3","group":"1c67e3b2.585c7c","order":3,"width":"1","height":"1","name":"Di00","label":"","format":"<font color={{(msg.payload?"green":"lightgrey")}}><i class="fa fa-lightbulb-o fa-2x"></i></font><br/><font size="-2">Di00</font>","layout":"col-center","x":710,"y":100,"wires":[]}]