Node-red for millisecond Application

Hi,
In My Project, I am using a device which has Raspbian (a Debian variant) with the following specifications 1. a Broadcom BCM2837B0 quad-core ARM Cortex-A53,
2. Clock Speed : 1.2 GHz,
3. RAM 1 GB LPDDR2 and
4. Flash memory of 32GB.

I am using Node-Red, CoDeSys also, Interfacing with multiple systems through

  1. Ethernet / IP adapter and Ethernet /IP Scanner [ From CoDeSys ].
  2. Rest API [ From Node-Red]
  3. Data Logging into Data base [ From Node-Red]

Also, using OPC UA client and servers for interfacing between Node-red, Codesys and HMI.

Since the OPC UA data fetching/pushing at Node-red requires at least 200ms, it's been configured with the Inject node with 200ms trigger, due to this the CPU load on the Node-red has increased to 40% and CodeSys also increased to 45%.
Which intern triggers more CPU load.!!!

Is there any way of using to use the alternative method instead of using time interval with inject node? like based on the state change.

Does Node-Red is capable of handling the 200ms response application?

Note: With the 1sec, OPC UA configuration the Node-red CPU load was 8-10% and the CodeSys was about 25%.
Is there any fix to reduce the CPU Load?

Your Input would highly appreciated

Best Regards,
Mani

1 Like

Which opcua nodes are you in nodes are you using? (Provide a link from flows library)

Are you manually polling with an inject rather than subscribing to the OPC node ID? If so, why?

Hello Steve,

Thanks for your quick resposne,
I am using these nodes

  1. opcua-compact-server - node-red-contrib-opcua-server (node) - Node-RED
  2. OpcUa-Client - node-red-contrib-opcua (node) - Node-RED -- > Using in both Subscribe and Write option.

After getting these details form the OPC UA i made these variable into Global for using it my node-red logic to check the status of these variables, I am using Inject node with 200ms time interval.

Best Regards,
Mani

This node has built in examples - one of them being how to subscribe to 1 or multiple NodeIds.

Examples are accessed via hamburger menu -> import (or CTRL-I)

In case you are not aware, subscriptions are event based (you dont poll them)

Hi Steve,

I think, if not just only about the OPC UA, because after moving these OPC UA variable, I have made few logics to process the further steps. Like then the Start bit is True then making few requests in API and ack. to CoDeSys and then displaying in HMI.
To make all these, I am using Inject node with 200ms to check the status of the Start bit.
I think, it's increasing the CPU load. which intern crashing the application of Node-Red sometime and sometime Codesys.

Best Regards,
Mani

Why?

Node-red is built on nodejs which is event based.
If you chose to use repeat injects then it is very likely you are not using it correctly.

For example, if you have an OPC subscription to a tag named "start" then you can push that through a switch node & if it == true, then "do stuff" (call APIs etc). It will only happen when the "event occurs" - zero polling required!

Without more info and examples / screenshots it is difficult to direct your further (without guessing).

Hi Steve,

Sorry, I am Newbie to node-red.
In my project It has both OPC UA Server and Client.

It's not just only start, i do have few intermediate bits status to complete my cycle and during this intermediate cycle the start bit goes false. all these are designed to interface with another intelligent system in the control system to have a proper hand-shake signals.

Also, even for using the change node it requires an input node right, in my case I am using Inject Node at every 200ms.

Please do suggest me.

Best Regards,
Mani

Hi,
I found few in stuffs on the performance of the application.

Looks like, my CPU RAM is increasing over a Period of Time,
The RAM increases as below

  1. With 5sec Trigger using Inject node [ with nearly 250kb of data into the system as an Object.]
  • 36MB is getting consumed in 6Hrs time,
  1. With 200ms Trigger using Inject node
  • 96MB is getting consumed in 2Hrs time, [ Without any data]
  • Approx. 100MB of RAM getting consumed at every hour [ With Data of 250kb]

By this every 100MB getting consumed at every one hour, my system is reaching its max. RAM of 1GB in 6 to 8hrs.

Looks like the, this 200ms eating-up all my RAM,
Herewith I have attaching my OPC UA Nodes for Codesys read and write nodes for your kind reference,
After moving these variables to Global, I am using these variables to start, process my operation. To check the status of these Global variables, I am using Inject node at every 200ms interval. I am starting my auto-cycle sequence using Inject Nodes.

  1. Is there any best to write this Nodes?
  2. Instead of Inject node, is there any other node I Can use instead of Inject as a starting Point of my Sequence ?
[{"id":"6009735745a81216","type":"group","z":"b09d706d370f621d","g":"dd93ce4ec751e275","name":"Subscribing To Codesys OPC UA Server","style":{"stroke":"#000000","fill":"#ffffbf","fill-opacity":"0.5","label":true,"color":"#000000"},"nodes":["3f97e8b62903c8ae","4892a65b297ee0c6","5b7d6d79112c89f0","59360722fd783fea","227a97f6e6c106f4","4ee0cbf5e46ebc32","e96247e573fb1509","54c54a7838312a98","c915a4f220618cd8","dea10b8c3c246880","daed9bc4e45112ca"],"x":74,"y":259,"w":1492,"h":322},{"id":"3f97e8b62903c8ae","type":"inject","z":"b09d706d370f621d","g":"6009735745a81216","name":"GO","props":[],"repeat":"0.2","crontab":"","once":true,"onceDelay":"","topic":"","x":170,"y":400,"wires":[["4892a65b297ee0c6"]]},{"id":"4892a65b297ee0c6","type":"template","z":"b09d706d370f621d","g":"6009735745a81216","name":"OPC Read Configuration","field":"payload","fieldType":"msg","format":"text","syntax":"plain","template":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Start_Scan,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.s_plc_FHS1_Scanned_BC,String\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_PROG_Running,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_Cask_AT_FHS1_Set,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.b_NR_FHS1_BC_Start_Scan,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_Cask_AT_FHS1_test,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Data_Ready,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_Read_InProgress,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.Line_PLC_Comm_Ok,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_result_read_Ack_to_NR,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_FHS1_Control_Mode,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Start_Scan_Set,Boolean","output":"str","x":350,"y":480,"wires":[["5b7d6d79112c89f0"]]},{"id":"5b7d6d79112c89f0","type":"csv","z":"b09d706d370f621d","g":"6009735745a81216","name":"Convert CSV Config To JSON","sep":",","hdrin":"","hdrout":"none","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":true,"include_empty_strings":"","include_null_values":"","x":590,"y":380,"wires":[["59360722fd783fea","c915a4f220618cd8"]]},{"id":"59360722fd783fea","type":"function","z":"b09d706d370f621d","g":"6009735745a81216","name":"Construct OPC msg Data","func":"// @ts-nocheck\n//Copy msg to Config, as msg is required for the OPC Client\nvar config = {};\nconfig = msg;\n\n//Perform a loop through the config data\n//For each iteration, set topic to column 1 & datatype to column 2\n\nfor (i=0;i<config.payload.length;i++) {\n    msg = {};\n    msg.topic = config.payload[i].col1;\n    msg.datatype = config.payload[i].col2;\n    msg.browseName = msg.topic.split(\".\").slice(-1).join(\".\");\n\n    //Send the message now, inside the loop\n    node.send(msg);\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":930,"y":340,"wires":[["4ee0cbf5e46ebc32","daed9bc4e45112ca"]]},{"id":"227a97f6e6c106f4","type":"debug","z":"b09d706d370f621d","g":"6009735745a81216","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":990,"y":540,"wires":[]},{"id":"4ee0cbf5e46ebc32","type":"debug","z":"b09d706d370f621d","g":"6009735745a81216","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1170,"y":340,"wires":[]},{"id":"e96247e573fb1509","type":"function","z":"b09d706d370f621d","g":"6009735745a81216","name":"PLC global variable assigment Function","func":"global.get(\"b_PLC_FHS1_BC_Start_Scan\") || false;\nglobal.get(\"s_plc_FHS1_Scanned_BC\") || null;\nglobal.get(\"b_PLC_PROG_Running\") || false;\nglobal.get(\"b_PLC_Cask_AT_FHS1_Set\") || false;\nglobal.get(\"b_NR_FHS1_BC_Start_Scan\") || false;\nglobal.get(\"b_PLC_Cask_AT_FHS1_test\") || false;\nglobal.get(\"b_PLC_FHS1_BC_Data_Ready\") || false;\nglobal.get(\"b_PLC_FHS1_Read_InProgress\") || false;\nglobal.get(\"Line_PLC_Comm_Ok\") || false;\nglobal.get(\"b_result_read_Ack_to_NR\") || false;\nglobal.get(\"b_FHS1_Control_Mode\") || false;\nglobal.get(\"b_PLC_FHS1_BC_Start_Scan_Set\") || false;\n\n\n//b_PLC_FHS1_BC_Start_Scan\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Start_Scan\") {\n    global.set(\"b_PLC_FHS1_BC_Start_Scan\", msg.payload)\n}\n// s_plc_FHS1_Scanned_BC <- s_plc_FHS1_Scanned_BC\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.s_plc_FHS1_Scanned_BC\") {\n    global.set(\"s_plc_FHS1_Scanned_BC\", msg.payload)\n}\n\n//b_PLC_PROG_Running\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_PROG_Running\") {\n    global.set(\"b_PLC_PROG_Running\", msg.payload)\n}\n\n//b_PLC_Cask_AT_FHS1\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_Cask_AT_FHS1_Set\") {\n    global.set(\"b_PLC_Cask_AT_FHS1_Set\", msg.payload)\n}\n\n//b_NR_FHS1_BC_Start_Scan\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.b_NR_FHS1_BC_Start_Scan\") {\n    global.set(\"b_NR_FHS1_BC_Start_Scan\", msg.payload)\n}\n\n//b_PLC_Cask_AT_FHS1 test\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_Cask_AT_FHS1_test\") {\n    global.set(\"b_PLC_Cask_AT_FHS1_test\", msg.payload)\n}\n\n//b_PLC_FHS1_BC_Data_Ready\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Data_Ready\") {\n    global.set(\"b_PLC_FHS1_BC_Data_Ready\", msg.payload)\n}\n\n//b_PLC_FHS1_Read_InProgress\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_Read_InProgress\") {\n    global.set(\"b_PLC_FHS1_Read_InProgress\", msg.payload)\n}\n\n//Line_PLC_Comm_Ok\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.Line_PLC_Comm_Ok\") {\n    global.set(\"Line_PLC_Comm_Ok\", msg.payload)\n}\n\n//b_result_read_Ack_to_NR\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_result_read_Ack_to_NR\") {\n    global.set(\"b_result_read_Ack_to_NR\", msg.payload)\n}\n\n//b_FHS1_Control_Mode\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_FHS1_Control_Mode\") {\n    global.set(\"b_FHS1_Control_Mode\", msg.payload)\n}\n\n//b_PLC_FHS1_BC_Start_Scan_Set\nif (msg.topic == \"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Start_Scan_Set\") {\n    global.set(\"b_PLC_FHS1_BC_Start_Scan_Set\", msg.payload)\n}\nreturn msg; ","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1200,"y":460,"wires":[["54c54a7838312a98"]]},{"id":"54c54a7838312a98","type":"debug","z":"b09d706d370f621d","g":"6009735745a81216","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1450,"y":540,"wires":[]},{"id":"c915a4f220618cd8","type":"debug","z":"b09d706d370f621d","g":"6009735745a81216","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":690,"y":300,"wires":[]},{"id":"dea10b8c3c246880","type":"template","z":"b09d706d370f621d","d":true,"g":"6009735745a81216","name":"OPC Read Configuration","field":"payload","fieldType":"msg","format":"text","syntax":"mustache","template":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_FHS1_PROG_Running,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_NR_FHS1_NOT_Valid_BC,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_NR_FHS1_Valid_BC,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_BC_Start_Scan,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_FHS1_Scanning_TimeOut,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_PLC_PROG_Running,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.POU_FHS1.s_plc_FHS1_Scanned_BC,String\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_WSI_EC_Complete,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_WSI_EC_Ready_To_Weight,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_WSI_FC_Complete,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_PLC.b_WSI_FC_Ready_To_Weight,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.POU_WS.float_EC_Net_Cal,Float\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.POU_WS.b_EC_Zeroing_Switch,Boolean\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.POU_WS.float_FC_Net_Cal,Float\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.POU_WS.b_FC_Zeroing_Switch,Boolean","output":"str","x":350,"y":320,"wires":[[]]},{"id":"daed9bc4e45112ca","type":"OpcUa-Client","z":"b09d706d370f621d","g":"6009735745a81216","endpoint":"a422c767cac035f8","action":"subscribe","deadbandtype":"a","deadbandvalue":1,"time":"1","timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"","x":820,"y":460,"wires":[["e96247e573fb1509","227a97f6e6c106f4"]]},{"id":"a422c767cac035f8","type":"OpcUa-Endpoint","endpoint":"opc.tcp://192.168.1.100:4840","secpol":"None","secmode":"None","login":false}]
[{"id":"5500d04e2011801f","type":"group","z":"b09d706d370f621d","g":"dd93ce4ec751e275","name":"Writing To Codesys OPC UA Server","style":{"stroke":"#000000","fill":"#e3f3d3","fill-opacity":"0.5","label":true,"color":"#000000"},"nodes":["ea7228ac928e5f67","7f891af9821bc208","1af59b05fdae9400","deed1989fed5bd90","65a9cbd31a0a792d","914a3533c88b3743","7ba3ec7987e11bad","c99d2e0301a3eef2","f4f7cd2175462ef6","4321dd9a661397d1","a6cab4af8eede9ac"],"x":74,"y":619,"w":1292,"h":262},{"id":"ea7228ac928e5f67","type":"inject","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"GO","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"0.2","crontab":"","once":true,"onceDelay":"","topic":"","payload":"","payloadType":"date","x":170,"y":700,"wires":[["7f891af9821bc208"]]},{"id":"7f891af9821bc208","type":"template","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"OPC Write Configuration","field":"payload","fieldType":"msg","format":"text","syntax":"mustache","template":"ns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.b_NR_FHS1_NOT_Valid_BC,Boolean,b_NR_FHS1_NOT_Valid_BC\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.b_NR_FHS1_Valid_BC,Boolean,b_NR_FHS1_Valid_BC\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.int_FHS1_EM01_State,Float,int_FHS1_EM01_State\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.int_FHS1_EM02_State,Float,int_FHS1_EM02_State\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.int_counter_SCANNED_CASKS,Float,counter_SCANNED_CASKS\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.int_counter_VALID,Float,counter_VALID\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.int_counter_NOT_VALID,Float,counter_NOT_VALID\nns=4;s=|var|CODESYS Control for Raspberry Pi MC SL.Application.GVL_FHS.b_NR_HeartBeat,Boolean,b_NR_HeartBeat","output":"str","x":390,"y":660,"wires":[["1af59b05fdae9400"]]},{"id":"1af59b05fdae9400","type":"csv","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"Convert CSV Config To JSON","sep":",","hdrin":"","hdrout":"none","multi":"mult","ret":"\\n","temp":"","skip":"0","strings":false,"include_empty_strings":"","include_null_values":"","x":650,"y":660,"wires":[["914a3533c88b3743"]]},{"id":"deed1989fed5bd90","type":"function","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"Initialise Value Data","func":"for (i=0;i<msg.payload.length;i++){\n    global.set(msg.payload[i].col3,null)\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1250,"y":660,"wires":[[]]},{"id":"65a9cbd31a0a792d","type":"inject","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"INIT","props":[{"p":"init","v":"true","vt":"bool"}],"repeat":"","crontab":"","once":true,"onceDelay":"","topic":"","x":170,"y":660,"wires":[["7f891af9821bc208"]]},{"id":"914a3533c88b3743","type":"switch","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"Initialising?","property":"init","propertyType":"msg","rules":[{"t":"nnull"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":950,"y":660,"wires":[["deed1989fed5bd90"],["7ba3ec7987e11bad"]]},{"id":"7ba3ec7987e11bad","type":"function","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"Construct OPC msg Data","func":"//Copy msg to Config, as msg is required for the OPC Client\nvar config = {};\nconfig = msg;\n\n//Perform a loop through the config data\n//For each iteration, set topic to column 1 & datatype to column 2\nfor (i=0;i<config.payload.length;i++){\n    msg = {};\n    msg.topic       = config.payload[i].col1;\n    msg.datatype    = config.payload[i].col2;\n    msg.payload     = global.get(config.payload[i].col3)\n    msg.browseName  = msg.topic.split(\".\").slice(-1).join(\".\");\n\n    //Send the message now, inside the loop\n    node.send(msg);\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":670,"y":740,"wires":[["c99d2e0301a3eef2"]]},{"id":"c99d2e0301a3eef2","type":"switch","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"Block Null Values","property":"payload","propertyType":"msg","rules":[{"t":"nnull"}],"checkall":"true","repair":false,"outputs":1,"x":970,"y":740,"wires":[["f4f7cd2175462ef6","4321dd9a661397d1"]]},{"id":"f4f7cd2175462ef6","type":"debug","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"opc ua client","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1230,"y":740,"wires":[]},{"id":"4321dd9a661397d1","type":"OpcUa-Client","z":"b09d706d370f621d","g":"5500d04e2011801f","endpoint":"a422c767cac035f8","action":"write","deadbandtype":"a","deadbandvalue":1,"time":10,"timeUnit":"s","certificate":"n","localfile":"","localkeyfile":"","securitymode":"None","securitypolicy":"None","folderName4PKI":"","name":"","x":1000,"y":840,"wires":[["a6cab4af8eede9ac"]]},{"id":"a6cab4af8eede9ac","type":"debug","z":"b09d706d370f621d","g":"5500d04e2011801f","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1230,"y":840,"wires":[]},{"id":"a422c767cac035f8","type":"OpcUa-Endpoint","endpoint":"opc.tcp://192.168.1.100:4840","secpol":"None","secmode":"None","login":false}]

My hardware has four Core,

  1. What could be the permissible Limt of the Average CPU load for the 4 core Raspberry PI? now it's varying between 3.65 to 8 and sometime up to 15.
  2. How can I bring this Average CPU Load under the permissible value?

Best Regards,
Mani

Two questions:

  1. If you leave it running a long time does node-red eventually crash due to out of memory, or does the memory stop increasing?

  2. If you run top is anything consuming a lot of CPU time?

[Edit] Sorry, I see you have answered question 2 already. Up to 15% CPU means that the processor is only lightly loaded, so that is not related to the problem.

hi ,

Thanks for your kind response,

For your first question, please refer the attached two images, each image taken at a 1hr interval.
the Available RAM has been reduced to nearly 100MB.


It's bit confusing while reading the multiple blogs for multi-core Avg. CPU load.
Can you also, please clarify on the Avg. CPU Load on the ''Top' Command is fine for 4-core processor?

Best Regards,
Mani

Yes, as I said before - DONT POLL

Instead, use the subscribe method.

There is NO need to poll every 200ms.

See also: OPC UA multiple subscription - #2 by Steve-Mcl

But what happens if you leave it another few hours?

hi Colin,

Today, Morning, the system was running up to 7hrs, just before I executed the reboot, I managed to take few info's, please refer the below observations.

Observations:

  1. Codesys has been crashed.
  2. IP address was pining
  3. H/w was not reachable through putty for the initial few mins [ tried for nearly 10mins]
  4. Node-red was not responding
  5. luckily after few tryouts then could be able to connect though putty. [ Node-red too started responding after few 'F5' on the browser.
  6. Refer the attached image for the more info form 'top' command.

a) the Available memory was just about 77MB.
Mem % of Nod-red went up to 78.8%
b) CodeSys Application not running

then after taking a snapshot, executed the 'sudo reboot'

Not sure what's killing my application?
Any inputs on stopping the RAM utilization?

Best Regards,
Mani

hello Steve,

Yes, I did use the same approach which has been given in the provided link for taking the OPC variable to global variables. [ Please refer my previous shared nodes]

But for my project auto sequence, these global variables to be checked at min. 200ms to take a further action,

the attached code is one logic for my auto sequence, similar to this I do have another 5-7 set of branches and all of them running similar to this,

flows (19).json (11.8 KB)

I am newbie here,

  1. Is there is any better way of designing the code?
  2. I am not sure, whether the nodes and flow can be started only with the inject node or Interval or Link in and Link Out?
  3. If any other nodes similar to filter would be a nice to have, but again filter node requires a inject node or interval to function.
  4. For my testing purpose, I am changing the interval between 200ms to 2sec.it's pure manual effort like I am opening each Inject node and changing the intervals [ nearly 8 to 10 inject node],
    Is there any extended version of Inject node, where I can set the Interval from a Global variable.

Best Regards,
Mani

No they dont, not if you do things event based - i.e. on change of value

You just have to approach things with a different mindset

hi Steve,

Thanks for helping me out, you mean to say, I need to create a function to subscribe and check if any of these values are getting changed?

  1. In your example, I Could see the OPC name, do I need to create this function for my OPC variable or the Global variables?
  2. If possible, can you share any function which can do the subscription? also for detecting the change in values for the group of variables?
  3. Subscription takes care of writing back few variables to the server too?

Best Regards,
Mani

Do you understand the difference between polling the OPC Server - vs - Subscribing to NodeIds?



Not sure what you mean.



I already did

Not until you can grab & show me sample data (I have no idea what you are polling and what the values might be)



No, thats a different part of the OPC spec.

I'm with Steve on this one. I'm not sure you're understanding the difference between polling and subscribing.

  • Polling: Manually asking the source at a given time for specific data, waiting for the data and the responding to it when it arrives.
  • Subscribing: Setting up a listener (also called mailbox, interrupt, etc.) where the source sends a triggering message saying an event happened (sometimes includes data, depending on how the source is configured). The listener than responds to the triggering message.

Polling takes significant resources to do one thing: wait. While you're waiting for your source, the program has difficulty continuing to the next steps. Subscribing is different because it doesn't have to wait. It does what it's programmed to do until something tells the program something happened. At that point it responds to something that's ready and then continues doing what it was doing before. Resource use is significantly less with subscribing than with polling and as a byproduct, significantly more reactive. Look at Steve's posts about how to subscribe and follow those.

That's a serious concern to me. It sounds like you're storing your results in memory with nothing to dump them to storage. If you're continuously building a history of results, you really need to put them into a file, database or something that stores them for you for later retrieval. Storing something in memory is a horribly bad idea if you know it's just going to be building and building. Better design is store your history and only keep stuff in memory that you need.

Aside from that, you need to understand one thing. Javascript (and as a result, Node-Red also) is a single-threaded programming language. Everything you do runs on one thread. Which also means everything you do runs on one core. It doesn't scale well to multiple cores. If you have computationally intensive tasks (which it doesn't appear that you do), there is a concept introduced over a decade ago called the Web Worker that Javascript supports. It allows you to add a task to another thread to spread out the load. If you need that capacity, you can use it. But if you don't (and I don't think you do), you should concentrate on keeping your system resource use down and work that way.

In the end, follow Steve's advice. Subscribe-n-save.

hi Steve,

Yes, I understood the Subscribe method.
I started implementing it in my logic, Since I am new to Js and Node-red it's taking bit of time for me to create.

Thank you so much for your input.

Best Regards,
Mani

Hi Mani,

I thought you might be interested in testing some other parameters while subscribing. There is a subscribing request interval for the opc ua client and a publishing interval for the opc ua server.

I just came accross a Nodered profiler, it might be useful to confirm where the process overload issue is.