Dear Friends,
I am trying to create opc ua server using from "node-red-contrib-iiot-opcua".
I am able to get it working with data type as double. definition as shown below is working perfect:
const gpioDI1 = namespace.addVariable({
"organizedBy": isoInputs,
"browseName": "I1",
"nodeId": "ns=1;s=Isolated_Input1",
"dataType": "Double",
"value": {
"get": function() {
return new Variant({
"dataType": DataType.Double,
"value": flexServerInternals.sandboxFlowContext.get("data1")
});
},
"set": function(variant) {
flexServerInternals.sandboxFlowContext.set(
"isoInput1",
parseFloat(variant.value)
);
return opcua.StatusCodes.Good;
}
}
});
But when I try data type string as shown below, then it does not work, node status is always "waiting"
const gpioDI1 = namespace.addVariable({
"organizedBy": isoInputs,
"browseName": "I1",
"nodeId": "ns=1;s=String",
"dataType": "String",
"value": {
"get": function() {
return new Variant({
"dataType": DataType.String,
"value": flexServerInternals.sandboxFlowContext.get("data1")
});
},
"set": function(variant) {
flexServerInternals.sandboxFlowContext.set(
"isoInput1",
parseFloat(variant.value)
);
return opcua.StatusCodes.Good;
}
}
});
the flow which is running perfectly is as below:
[
{
"id": "89c9e23040c05321",
"type": "OPCUA-IIoT-Flex-Server",
"z": "96df9d1b.b1b87",
"port": "55480",
"endpoint": "UA/user1",
"acceptExternalCommands": true,
"maxAllowedSessionNumber": "",
"maxConnectionsPerEndpoint": "",
"maxAllowedSubscriptionNumber": "",
"alternateHostname": "",
"name": "user1",
"showStatusActivities": false,
"showErrors": false,
"allowAnonymous": true,
"individualCerts": false,
"isAuditing": false,
"serverDiscovery": true,
"users": [],
"xmlsets": [],
"publicCertificateFile": "",
"privateCertificateFile": "",
"registerServerMethod": "1",
"discoveryServerEndpointUrl": "",
"capabilitiesForMDNS": "",
"maxNodesPerRead": 1000,
"maxNodesPerBrowse": 2000,
"delayToClose": 1000,
"addressSpaceScript": "function constructAlarmAddressSpace(server, addressSpace, eventObjects, done) {\n // server = the created node-opcua server\n // addressSpace = script placeholder\n // eventObjects = to hold event variables in memory from this script\n \n // internal global sandbox objects are \n // node = node of the flex server, \n // coreServer = core iiot server object for debug and access to nodeOPCUA,\n // and scriptObjects to hold variables and functions\n const LocalizedText = opcua.LocalizedText;\n const namespace = addressSpace.getOwnNamespace();\n \n coreServer.internalDebugLog('init dynamic address space')\n node.warn('construct new address space for OPC UA')\n \n const Variant = opcua.Variant;\n const DataType = opcua.DataType;\n const DataValue = opcua.DataValue;\n \n var flexServerInternals = this;\n \n this.sandboxFlowContext.set(\"data1\", 0);\n this.sandboxFlowContext.set(\"data2\", 0);\n \n \n this.sandboxFlowContext.set(\"data3\", 0);\n this.sandboxFlowContext.set(\"data4\", 0);\n \n \n coreServer.internalDebugLog(\"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\": \"GNA_Scanner\"\n });\n const gpioFolder = namespace.addFolder(myDevice, { \"browseName\": \"GPIO\" });\n const isoInputs = namespace.addFolder(gpioFolder, {\n \"browseName\": \"Inputs\"\n });\n const isoOutputs = namespace.addFolder(gpioFolder, {\n \"browseName\": \"Outputs\"\n });\n \n const gpioDI1 = namespace.addVariable({\n \"organizedBy\": isoInputs,\n \"browseName\": \"I1\",\n \"nodeId\": \"ns=1;s=Isolated_Input1\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data1\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoInput1\",\n variant.value\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const gpioDI2 = namespace.addVariable({\n \"organizedBy\": isoInputs,\n \"browseName\": \"I2\",\n \"nodeId\": \"ns=1;s=Isolated_Input2\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data2\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoInput2\",\n parseFloat(variant.value)\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const gpioDO1 = namespace.addVariable({\n \"organizedBy\": isoOutputs,\n \"browseName\": \"O1\",\n \"nodeId\": \"ns=1;s=Isolated_Output1\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data3\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoOutput1\",\n parseFloat(variant.value)\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const gpioDO2 = namespace.addVariable({\n \"organizedBy\": isoOutputs,\n \"browseName\": \"O2\",\n \"nodeId\": \"ns=1;s=Isolated_Output2\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data4\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoOutput2\",\n parseFloat(variant.value)\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n \n //------------------------------------------------------------------------------\n // Add a view\n //------------------------------------------------------------------------------\n const viewDI = namespace.addView({\n \"organizedBy\": rootFolder.views,\n \"browseName\": \"RPIW0-Digital-Ins\"\n });\n \n const viewDO = namespace.addView({\n \"organizedBy\": rootFolder.views,\n \"browseName\": \"RPIW0-Digital-Outs\"\n });\n \n viewDI.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDI1.nodeId\n });\n \n viewDI.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDI2.nodeId\n });\n \n \n viewDO.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDO1.nodeId\n });\n \n viewDO.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDO2.nodeId\n });\n \n \n coreServer.internalDebugLog(\"create dynamic address space done\");\n node.warn(\"construction of new address space for OPC UA done\");\n \n done();\n}\n",
"x": 670,
"y": 440,
"wires": [
[]
]
},
{
"id": "d322f02a5173c846",
"type": "function",
"z": "96df9d1b.b1b87",
"name": "set flow context Inputs",
"func": "flow.set('data1', 999)\nflow.set('data2', Math.random() + 13.0)\nflow.set('data3', Math.random() + 14.0)\nflow.set('data4', Math.random() + 15.0)\n\nmsg.payload = [\n flow.get('data1'),\n flow.get('data2'),\n flow.get('data3'),\n flow.get('data4'),\n]\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 460,
"y": 380,
"wires": [
[
"be3de210a03c018d"
]
]
},
{
"id": "cc009cd686d0639d",
"type": "inject",
"z": "96df9d1b.b1b87",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "3",
"crontab": "",
"once": true,
"onceDelay": "0.5",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 250,
"y": 380,
"wires": [
[
"d322f02a5173c846"
]
]
},
{
"id": "be3de210a03c018d",
"type": "debug",
"z": "96df9d1b.b1b87",
"name": "debug 1",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 680,
"y": 380,
"wires": []
}
]
and the flow which is not working is as below:
[
{
"id": "89c9e23040c05321",
"type": "OPCUA-IIoT-Flex-Server",
"z": "96df9d1b.b1b87",
"port": "55480",
"endpoint": "UA/user1",
"acceptExternalCommands": true,
"maxAllowedSessionNumber": "",
"maxConnectionsPerEndpoint": "",
"maxAllowedSubscriptionNumber": "",
"alternateHostname": "",
"name": "user1",
"showStatusActivities": false,
"showErrors": false,
"allowAnonymous": true,
"individualCerts": false,
"isAuditing": false,
"serverDiscovery": true,
"users": [],
"xmlsets": [],
"publicCertificateFile": "",
"privateCertificateFile": "",
"registerServerMethod": "1",
"discoveryServerEndpointUrl": "",
"capabilitiesForMDNS": "",
"maxNodesPerRead": 1000,
"maxNodesPerBrowse": 2000,
"delayToClose": 1000,
"addressSpaceScript": "function constructAlarmAddressSpace(server, addressSpace, eventObjects, done) {\n // server = the created node-opcua server\n // addressSpace = script placeholder\n // eventObjects = to hold event variables in memory from this script\n \n // internal global sandbox objects are \n // node = node of the flex server, \n // coreServer = core iiot server object for debug and access to nodeOPCUA,\n // and scriptObjects to hold variables and functions\n const LocalizedText = opcua.LocalizedText;\n const namespace = addressSpace.getOwnNamespace();\n \n coreServer.internalDebugLog('init dynamic address space')\n node.warn('construct new address space for OPC UA')\n \n const Variant = opcua.Variant;\n const DataType = opcua.DataType;\n const DataValue = opcua.DataValue;\n \n var flexServerInternals = this;\n \n this.sandboxFlowContext.set(\"data1\", 0);\n this.sandboxFlowContext.set(\"data2\", 0);\n \n \n this.sandboxFlowContext.set(\"data3\", 0);\n this.sandboxFlowContext.set(\"data4\", 0);\n \n \n coreServer.internalDebugLog(\"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\": \"GNA_Scanner\"\n });\n const gpioFolder = namespace.addFolder(myDevice, { \"browseName\": \"GPIO\" });\n const isoInputs = namespace.addFolder(gpioFolder, {\n \"browseName\": \"Inputs\"\n });\n const isoOutputs = namespace.addFolder(gpioFolder, {\n \"browseName\": \"Outputs\"\n });\n \n const gpioDI1 = namespace.addVariable({\n \"organizedBy\": isoInputs,\n \"browseName\": \"I1\",\n \"nodeId\": \"ns=1;s=Isolated_Input1\",\n \"dataType\": \"String\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.String,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data1\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoInput1\",\n variant.value\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const gpioDI2 = namespace.addVariable({\n \"organizedBy\": isoInputs,\n \"browseName\": \"I2\",\n \"nodeId\": \"ns=1;s=Isolated_Input2\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data2\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoInput2\",\n parseFloat(variant.value)\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const gpioDO1 = namespace.addVariable({\n \"organizedBy\": isoOutputs,\n \"browseName\": \"O1\",\n \"nodeId\": \"ns=1;s=Isolated_Output1\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data3\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoOutput1\",\n parseFloat(variant.value)\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n const gpioDO2 = namespace.addVariable({\n \"organizedBy\": isoOutputs,\n \"browseName\": \"O2\",\n \"nodeId\": \"ns=1;s=Isolated_Output2\",\n \"dataType\": \"Double\",\n \"value\": {\n \"get\": function() {\n return new Variant({\n \"dataType\": DataType.Double,\n \"value\": flexServerInternals.sandboxFlowContext.get(\"data4\")\n });\n },\n \"set\": function(variant) {\n flexServerInternals.sandboxFlowContext.set(\n \"isoOutput2\",\n parseFloat(variant.value)\n );\n return opcua.StatusCodes.Good;\n }\n }\n });\n \n \n //------------------------------------------------------------------------------\n // Add a view\n //------------------------------------------------------------------------------\n const viewDI = namespace.addView({\n \"organizedBy\": rootFolder.views,\n \"browseName\": \"RPIW0-Digital-Ins\"\n });\n \n const viewDO = namespace.addView({\n \"organizedBy\": rootFolder.views,\n \"browseName\": \"RPIW0-Digital-Outs\"\n });\n \n viewDI.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDI1.nodeId\n });\n \n viewDI.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDI2.nodeId\n });\n \n \n viewDO.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDO1.nodeId\n });\n \n viewDO.addReference({\n \"referenceType\": \"Organizes\",\n \"nodeId\": gpioDO2.nodeId\n });\n \n \n coreServer.internalDebugLog(\"create dynamic address space done\");\n node.warn(\"construction of new address space for OPC UA done\");\n \n done();\n}\n",
"x": 670,
"y": 440,
"wires": [
[]
]
},
{
"id": "d322f02a5173c846",
"type": "function",
"z": "96df9d1b.b1b87",
"name": "set flow context Inputs",
"func": "flow.set('data1', \"ABC1234\")\nflow.set('data2', Math.random() + 13.0)\nflow.set('data3', Math.random() + 14.0)\nflow.set('data4', Math.random() + 15.0)\n\nmsg.payload = [\n flow.get('data1'),\n flow.get('data2'),\n flow.get('data3'),\n flow.get('data4'),\n]\nreturn msg;",
"outputs": 1,
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 460,
"y": 380,
"wires": [
[
"be3de210a03c018d"
]
]
},
{
"id": "cc009cd686d0639d",
"type": "inject",
"z": "96df9d1b.b1b87",
"name": "",
"props": [
{
"p": "payload"
},
{
"p": "topic",
"vt": "str"
}
],
"repeat": "3",
"crontab": "",
"once": true,
"onceDelay": "0.5",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 250,
"y": 380,
"wires": [
[
"d322f02a5173c846"
]
]
},
{
"id": "be3de210a03c018d",
"type": "debug",
"z": "96df9d1b.b1b87",
"name": "debug 1",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 680,
"y": 380,
"wires": []
}
]
Please suggest the solution to make second flow with string input working. thanks.