Thank you for your replies.
I found another solution using the node.status() function, and it works as expected. However, I will share with you the test flow:
[{"id":"7aa9f6da.a3eeb8","type":"tab","label":"Test","disabled":false,"info":""},{"id":"b03d81d80d8da749","type":"function","z":"7aa9f6da.a3eeb8","name":"","func":"if (msg.status.text === \"done\") {\n msg.payload = \"hello\"\n return msg;\n}","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":600,"y":320,"wires":[["e85eeaa9aa4f5c7a"]]},{"id":"e85eeaa9aa4f5c7a","type":"debug","z":"7aa9f6da.a3eeb8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":810,"y":320,"wires":[]},{"id":"f727751fe91480a8","type":"opcua-compact-server","z":"7aa9f6da.a3eeb8","port":54845,"endpoint":"","productUri":"","acceptExternalCommands":true,"maxAllowedSessionNumber":"10","maxConnectionsPerEndpoint":"10","maxAllowedSubscriptionNumber":"100","alternateHostname":"","name":"","showStatusActivities":false,"showErrors":true,"allowAnonymous":true,"individualCerts":false,"isAuditing":false,"serverDiscovery":true,"users":[],"xmlsetsOPCUA":[],"publicCertificateFile":"","privateCertificateFile":"","registerServerMethod":"1","discoveryServerEndpointUrl":"opc.tcp://localhost:54845","capabilitiesForMDNS":"","maxNodesPerRead":1000,"maxNodesPerWrite":1000,"maxNodesPerHistoryReadData":100,"maxNodesPerBrowse":3000,"maxBrowseContinuationPoints":"10","maxHistoryContinuationPoints":"10","delayToInit":"1000","delayToClose":"200","serverShutdownTimeout":"100","addressSpaceScript":"function constructAlarmAddressSpace(server, addressSpace, eventObjects, done) {\n \n const opcua = coreServer.choreCompact.opcua;\n const LocalizedText = opcua.LocalizedText;\n const namespace = addressSpace.getOwnNamespace();\n\n const Variant = opcua.Variant;\n const DataType = opcua.DataType;\n const DataValue = opcua.DataValue;\n \n const isoInput2 = \"Boolean\"\n const nodeIdInput2 = \"Boolean\"\n const browserNameInput2 = \"I2\"\n \n const rootFolderName = \"Test\"\n const childFolderName = \"PLCs_IO\"\n const inputsFolderName = \"Inputs\"\n const outputsFolderName = \"Outputs\"\n const viewInputsName = \"Digital-Ins\"\n const viewOutputsName = \"Digital-Outs\"\n \n \n var flexServerInternals = this;\n \n this.sandboxFlowContext.set(isoInput2, false);\n \n coreServer.debugLog(\"init dynamic address space\");\n const rootFolder = addressSpace.findNode(\"RootFolder\");\n \n node.warn(\"construct new address space for OPC UA\");\n \n const myDevice = namespace.addFolder(rootFolder.objects, {\n \"browseName\": rootFolderName\n });\n const gpioFolder = namespace.addFolder(myDevice, { \"browseName\": childFolderName });\n const isoInputs = namespace.addFolder(gpioFolder, {\n \"browseName\": inputsFolderName\n });\n const isoOutputs = namespace.addFolder(gpioFolder, {\n \"browseName\": outputsFolderName\n });\n \n const gpioDI2 = namespace.addVariable({\n \"organizedBy\": isoInputs,\n \"browseName\": browserNameInput2,\n \"nodeId\": \"ns=1;s=\" + nodeIdInput2,\n \"dataType\": \"Boolean\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Boolean,\n \"value\": flexServerInternals.sandboxFlowContext.get(isoInput2)\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n isoInput2,\n variant.value\n );\n if (variant.value){\n node.status({fill:\"green\",shape:\"dot\",text:\"done\"});\n //node.error(\"done\", msg)\n \n }\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const viewDI = namespace.addView({\n \"organizedBy\": rootFolder.views,\n \"browseName\": viewInputsName\n });\n \n \n viewDI.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDI2.nodeId\n });\n \n\n coreServer.debugLog(\"create dynamic address space done\");\n node.warn(\"construction of new address space for OPC UA done\");\n \n done();\n }\n ","x":840,"y":200,"wires":[]},{"id":"f4c1c90167228418","type":"status","z":"7aa9f6da.a3eeb8","name":"","scope":["f727751fe91480a8"],"x":400,"y":320,"wires":[["b03d81d80d8da749"]]},{"id":"e37f4eb8d480274f","type":"OPCUA-IIoT-Write","z":"7aa9f6da.a3eeb8","connector":"77fdc29e.3c49ec","name":"","justValue":false,"showStatusActivities":false,"showErrors":true,"x":670,"y":440,"wires":[["c7646ab516181d31"]]},{"id":"c7646ab516181d31","type":"OPCUA-IIoT-Response","z":"7aa9f6da.a3eeb8","name":"","compressStructure":false,"showStatusActivities":false,"showErrors":true,"activateUnsetFilter":false,"activateFilters":false,"negateFilter":false,"filters":[],"x":820,"y":440,"wires":[[]]},{"id":"278abff106a2ad9a","type":"function","z":"7aa9f6da.a3eeb8","name":"toWriteMsg","func":"var value = msg.payload\n\nvar newMsg = { payload :{\n nodetype :'inject',\n injectType : 'write',\n valuesToWrite : [value],\n addressSpaceItems : [{\n name: \"Boolean\",\n nodeId: \"ns=1;s=Boolean\",\n datatypeName: \"Boolean\"\n }]\n }\n}\n\nreturn newMsg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":510,"y":440,"wires":[["e37f4eb8d480274f"]]},{"id":"c7952843f94092ab","type":"inject","z":"7aa9f6da.a3eeb8","name":"true","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":290,"y":440,"wires":[["278abff106a2ad9a"]]},{"id":"e1f99b96a6e25eab","type":"inject","z":"7aa9f6da.a3eeb8","name":"false","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"false","payloadType":"bool","x":290,"y":500,"wires":[["278abff106a2ad9a"]]},{"id":"77fdc29e.3c49ec","type":"OPCUA-IIoT-Connector","discoveryUrl":"","endpoint":"opc.tcp://localhost:54845","endpointMustExist":false,"keepSessionAlive":true,"loginEnabled":false,"name":"LOCAL FLEX 80","showErrors":true,"securityPolicy":"None","securityMode":"None","individualCerts":false,"publicCertificateFile":"","privateKeyFile":"","defaultSecureTokenLifetime":"","autoSelectRightEndpoint":false,"strategyMaxRetry":"","strategyInitialDelay":"","strategyMaxDelay":"","strategyRandomisationFactor":"","requestedSessionTimeout":"","connectionStartDelay":"","reconnectDelay":"","maxBadSessionRequests":""}]
In this case, if you look at the line number 61 in the address space script of the opcua-compact-server node, you will find the calling of the node.status() function.
I need a trigger when someone writes a certain variable value to the OPC UA server in order to monitor for value changes. I understand that this request violates the main principles of flow-based programming, but the alternative I thought of is to continuously poll the OPC UA server, get the variable's new value, compare it to the old value and act accordingly. I assume this solution, while not an anti-pattern, could be a waste of resources and may affect overall performances.
Any suggestion about how to make it more pattern-friendly, simpler and better (maybe using more appropriate node or a library that I may not be aware of yet...) will be appreciated.
Thank you in advance.