UNPKG

node-red-contrib-opcua-server-refresh

Version:

Fork of the original 'node-red-contrib-opcua-server' package that is no longer maintained. This has been refactored to support the latest version of node-opcua and fixes incomplete/non-working features.

42 lines 8.18 kB
[ { "id": "ae470607af71d684", "type": "opcua-compact-server-refresh", "z": "2e8c7f5c.ab73d", "port": 54840, "endpoint": "", "productUri": "", "acceptExternalCommands": true, "maxAllowedSessionNumber": 10, "maxConnectionsPerEndpoint": 10, "maxAllowedSubscriptionNumber": 100, "alternateHostname": "", "name": "", "showStatusActivities": false, "showErrors": false, "allowAnonymous": true, "individualCerts": false, "isAuditing": false, "serverDiscovery": true, "users": [], "xmlsetsOPCUA": [], "publicCertificateFile": "", "privateCertificateFile": "", "registerServerMethod": 1, "discoveryServerEndpointUrl": "", "capabilitiesForMDNS": "", "maxNodesPerRead": 1000, "maxNodesPerWrite": 1000, "maxNodesPerHistoryReadData": 100, "maxNodesPerBrowse": 3000, "maxBrowseContinuationPoints": 10, "maxHistoryContinuationPoints": 10, "delayToInit": 1000, "delayToClose": 200, "serverShutdownTimeout": 100, "addressSpaceScript": "function(server, addressSpace, opcua, eventObjects, done) {\n\n node.warn(\"Starting OPCUA Server\");\n\n // Debug Statements to verify eventObjects and sandboxFlowContext\n if (!opcua) {\n node.error(\"OPCUA module is not available.\");\n return done(new Error(\"OPCUA module is undefined.\"));\n }\n\n const namespace = addressSpace.getOwnNamespace();\n\n const Variant = opcua.Variant;\n const DataType = opcua.DataType;\n const VariantArrayType = opcua.VariantArrayType;\n const DataValue = opcua.DataValue;\n const standardUnits = opcua.standardUnits;\n\n //Define ISA-95 folder structure for UNS\n const rootFolder = addressSpace.findNode(\"RootFolder\");\n\n const enterprise = namespace.addFolder(rootFolder.objects, { browseName: \"sji\" });\n\n const site = namespace.addFolder(enterprise, { browseName: \"garfield\" });\n\n const area = namespace.addFolder(site, { browseName: \"bop\" });\n\n const subsystem = namespace.addFolder(area, { browseName: \"flare\" });\n /*\n * variation 0:\n * ------------\n *\n * Add a variable in folder using a raw Variant.\n * Use this variation when the variable has to be read or written by the OPCUA clients\n */\n const variable0 = namespace.addVariable({\n organizedBy: subsystem,\n browseName: \"FanSpeed\",\n nodeId: \"ns=1;s=FanSpeed\",\n dataType: \"Double\",\n value: new Variant({ dataType: DataType.Double, value: 1000.0 })\n });\n\n setInterval(function () {\n const fluctuation = Math.random() * 100 - 50;\n variable0.setValueFromSource(new Variant({ dataType: DataType.Double, value: 1000.0 + fluctuation }));\n }, 10);\n \n /*\n * variation 1:\n * ------------\n *\n * Add a variable in folder using a single get function which returns the up to date variable value in Variant.\n * The server will set the timestamps automatically for us.\n * Use this variation when the variable value is controlled by the getter function\n * Avoid using this variation if the variable has to be made writable, as the server will call the getter\n * function prior to returning its value upon client read requests.\n */\n namespace.addVariable({\n organizedBy: subsystem,\n browseName: \"PumpSpeed\",\n nodeId: \"ns=1;s=PumpSpeed\",\n dataType: \"Double\",\n value: {\n /**\n * returns the current value as a Variant\n * @method get\n * @return {Variant}\n */\n get: function () {\n const pump_speed = 200 + 100 * Math.sin(Date.now() / 10000);\n return new Variant({ dataType: DataType.Double, value: pump_speed });\n }\n }\n });\n\n namespace.addVariable({\n organizedBy: subsystem,\n browseName: \"SomeDate\",\n nodeId: \"ns=1;s=SomeDate\",\n dataType: \"DateTime\",\n value: {\n get: function () {\n return new Variant({ dataType: DataType.DateTime, value: new Date(Date.UTC(2016, 9, 13, 8, 40, 0)) });\n }\n }\n });\n\n /*\n * variation 2:\n * ------------\n *\n * Add a variable in folder. This variable gets its value and source timestamps from the provided function.\n * The value and source timestamps are held in a external object.\n * The value and source timestamps are updated on a regular basis using a timer function.\n */\n const external_value_with_sourceTimestamp = new DataValue({\n value: new Variant({ dataType: DataType.Double, value: 10.0 }),\n sourceTimestamp: null,\n sourcePicoseconds: 0\n });\n setInterval(function () {\n external_value_with_sourceTimestamp.value.value = Math.random();\n external_value_with_sourceTimestamp.sourceTimestamp = new Date();\n }, 1000);\n\n namespace.addVariable({\n organizedBy: subsystem,\n browseName: \"Pressure\",\n nodeId: \"ns=1;s=Pressure\",\n dataType: \"Double\",\n value: {\n timestamped_get: function () {\n return external_value_with_sourceTimestamp;\n }\n }\n });\n /*\n * variation 3:\n * ------------\n *\n * Add a variable in a folder. This variable gets its value and source timestamps from the provided\n * asynchronous function.\n * The asynchronous function is called only when needed by the opcua Server read services and monitored item services\n *\n */\n\n namespace.addVariable({\n organizedBy: subsystem,\n browseName: \"Temperature\",\n nodeId: \"s=Temperature\",\n dataType: \"Double\",\n\n value: {\n refreshFunc: function (callback) {\n const temperature = 20 + 10 * Math.sin(Date.now() / 10000);\n const value = new Variant({ dataType: DataType.Double, value: temperature });\n const sourceTimestamp = new Date();\n\n // simulate a asynchronous behaviour\n setTimeout(function () {\n callback(null, new DataValue({ value: value, sourceTimestamp: sourceTimestamp }));\n }, 100);\n }\n }\n });\n\n // UAAnalogItem\n // add a UAAnalogItem\n const analogNode = namespace.addAnalogDataItem({\n organizedBy: subsystem,\n\n nodeId: \"s=TemperatureAnalogItem\",\n browseName: \"TemperatureAnalogItem\",\n definition: \"(tempA -25) + tempB\",\n valuePrecision: 0.5,\n engineeringUnitsRange: { low: 100, high: 200 },\n instrumentRange: { low: -100, high: +200 },\n engineeringUnits: standardUnits.degree_celsius,\n dataType: \"Double\",\n value: {\n get: function () {\n return new Variant({ dataType: DataType.Double, value: Math.random() + 19.0 });\n }\n }\n });\n\n const m3x3 = namespace.addVariable({\n organizedBy: addressSpace.rootFolder.objects,\n nodeId: \"s=Matrix\",\n browseName: \"Matrix\",\n dataType: \"Double\",\n valueRank: 2,\n arrayDimensions: [3, 3],\n value: {\n get: function () {\n return new Variant({\n dataType: DataType.Double,\n arrayType: VariantArrayType.Matrix,\n dimensions: [3, 3],\n value: [1, 2, 3, 4, 5, 6, 7, 8, 9]\n });\n }\n }\n });\n\n const xyz = namespace.addVariable({\n organizedBy: addressSpace.rootFolder.objects,\n nodeId: \"s=Position\",\n browseName: \"Position\",\n dataType: \"Double\",\n valueRank: 1,\n arrayDimensions: null,\n value: {\n get: function () {\n return new Variant({\n dataType: DataType.Double,\n arrayType: VariantArrayType.Array,\n value: [1, 2, 3, 4]\n });\n }\n }\n });\n \n //------------------------------------------------------------------------------\n // Add a view\n //------------------------------------------------------------------------------\n const view = namespace.addView({\n organizedBy: rootFolder.views,\n browseName: \"MyView\"\n });\n\n view.addReference({\n referenceType: \"Organizes\",\n nodeId: analogNode.nodeId\n });\n node.warn(\"Construction of new address space for OPC UA done\");\n done();\n}", "x": 530, "y": 320, "wires": [] } ]