UNPKG

prisme-flow

Version:

prisme platform flow engine

482 lines (395 loc) 16.3 kB
/** * Created by prisme.io on 09/06/2017. */ module.exports = function (RED) { "use strict"; var opcua = require('node-opcua'); var path = require('path'); var os = require("os"); function OpcUaServerNode(n) { RED.nodes.createNode(this, n); this.name = n.name; this.port = n.port; this.endpoint = n.endpoint; var node = this; var variables = { Counter: 0, } var equipmentCounter = 0; var physicalAssetCounter = 0; var equipment; var physicalAssets; var vendorName; var equipmentNotFound = true; var initialized = false; var server = null; var folder = null; function verbose_warn(logMessage) { if (RED.settings.verbose) { node.warn((node.name) ? node.name + ': ' + logMessage : 'OpcUaServerNode: ' + logMessage); } } function verbose_log(logMessage) { if (RED.settings.verbose) { node.log(logMessage); } } node.status({fill: "red", shape: "ring", text: "Not running"}); var xmlFiles = [path.join(__dirname, 'public/vendor/opc-foundation/xml/Opc.Ua.NodeSet2.xml'), path.join(__dirname, 'public/vendor/opc-foundation/xml/Opc.ISA95.NodeSet2.xml')]; verbose_warn("node set:" + xmlFiles.toString()); function initNewServer() { initialized = false; verbose_warn("create Server from XML ..."); server = new opcua.OPCUAServer({ port: node.port, nodeset_filename: xmlFiles, resourcePath: node.endpoint || "UA/SimpleNodeRedServer" }); server.buildInfo.productName = node.name.concat("OPC UA server"); server.buildInfo.buildNumber = "112"; server.buildInfo.buildDate = new Date(2016, 3, 24); verbose_warn("init next..."); server.initialize(post_initialize); var hostname = os.hostname(); var discovery_server_endpointUrl = "opc.tcp://" + hostname + ":4840/UADiscovery"; verbose_log("\nregistering server to :".yellow + discovery_server_endpointUrl); server.registerServer(discovery_server_endpointUrl, function (err) { if (err) { // cannot register server in discovery verbose_warn(" warning : cannot register server into registry server"); } else { verbose_log(" registering server to the discovery server : done.".cyan); } }); } function construct_my_address_space(addressSpace) { verbose_warn('Server add VendorName ...'); vendorName = addressSpace.addObject({ organizedBy: addressSpace.rootFolder.objects, nodeId: "ns=4;s=VendorName", browseName: "VendorName" }); equipment = addressSpace.addObject({ organizedBy: vendorName, nodeId: "ns=4;s=Equipment", browseName: "Equipment" }); physicalAssets = addressSpace.addObject({ organizedBy: vendorName, nodeId: "ns=4;s=PhysicalAssets", browseName: "Physical Assets" }); verbose_warn('Server add MyVariable2 ...'); var variable2 = 10.0; addressSpace.addVariable({ componentOf: vendorName, nodeId: "ns=4;s=MyVariable2", browseName: "MyVariable2", dataType: opcua.DataType.Double, value: { get: function () { return new opcua.Variant({dataType: opcua.DataType.Double, value: variable2}); }, set: function (variant) { variable2 = parseFloat(variant.value); return opcua.StatusCodes.Good; } } }); verbose_warn('Server add FreeMemory ...'); addressSpace.addVariable({ componentOf: vendorName, nodeId: "ns=4;s=FreeMemory", browseName: "FreeMemory", dataType: opcua.DataType.Double, value: { get: function () { return new opcua.Variant({dataType: opcua.DataType.Double, value: available_memory()}); } } }); verbose_warn('Server add Counter ...'); addressSpace.addVariable({ componentOf: vendorName, nodeId: "ns=4;s=Counter", browseName: "Counter", dataType: opcua.DataType.UInt16, value: { get: function () { return new opcua.Variant({dataType: opcua.DataType.UInt16, value: variables.Counter}); } } }); var method = addressSpace.addMethod( vendorName, { browseName: "Bark", inputArguments: [ { name: "nbBarks", description: {text: "specifies the number of time I should bark"}, dataType: opcua.DataType.UInt32 }, { name: "volume", description: {text: "specifies the sound volume [0 = quiet ,100 = loud]"}, dataType: opcua.DataType.UInt32 } ], outputArguments: [{ name: "Barks", description: {text: "the generated barks"}, dataType: opcua.DataType.String, valueRank: 1 }] }); method.bindMethod(function (inputArguments, context, callback) { var nbBarks = inputArguments[0].value; var volume = inputArguments[1].value; verbose_log("Hello World ! I will bark ", nbBarks, " times"); verbose_log("the requested volume is ", volume, ""); var sound_volume = new Array(volume).join("!"); var barks = []; for (var i = 0; i < nbBarks; i++) { barks.push("Whaff" + sound_volume); } var callMethodResult = { statusCode: opcua.StatusCodes.Good, outputArguments: [{ dataType: opcua.DataType.String, arrayType: opcua.VariantArrayType.Array, value: barks }] }; callback(null, callMethodResult); }); } function post_initialize() { if (server) { var addressSpace = server.engine.addressSpace; construct_my_address_space(addressSpace); verbose_warn("Next server start..."); server.start(function () { verbose_warn("Server is now listening ... ( press CTRL+C to stop)"); server.endpoints[0].endpointDescriptions().forEach(function (endpoint) { verbose_warn("Server endpointUrl: " + endpoint.endpointUrl + ' securityMode: ' + endpoint.securityMode.toString() + ' securityPolicyUri: ' + endpoint.securityPolicyUri.toString()); }); var endpointUrl = server.endpoints[0].endpointDescriptions()[0].endpointUrl; verbose_log(" the primary server endpoint url is " + endpointUrl); }); node.status({fill: "green", shape: "dot", text: "running"}); initialized = true; verbose_warn("server initialized"); } else { node.status({fill: "gray", shape: "dot", text: "not running"}); node.error("server is not initialized") } } function available_memory() { return os.freemem() / os.totalmem() * 100.0; } initNewServer(); //###################################################################################### node.on("input", function (msg) { verbose_log(JSON.stringify(msg)); if (server == undefined || !initialized) { node.error("Server is not running"); return false; } var payload = msg.payload; if (contains_messageType(payload)) { read_message(payload); } if (contains_opcua_command(payload)) { execute_opcua_command(msg); } if (equipmentNotFound) { var addressSpace = server.engine.addressSpace; if (addressSpace === undefined) { node.error("addressSpace undefinded"); return false; } var rootFolder = addressSpace.findNode("ns=4;s=VendorName"); var references = rootFolder.findReferences("Organizes", true); if (findReference(references, equipment.nodeId)) { verbose_warn("Equipment Reference found in VendorName"); equipmentNotFound = false; } else { verbose_warn("Equipment Reference not found in VendorName"); } } node.send(msg); }); function findReference(references, nodeId) { return references.filter(function (r) { return r.nodeId.toString() === nodeId.toString(); }); } function contains_messageType(payload) { return payload.hasOwnProperty('messageType'); } function read_message(payload) { switch (payload.messageType) { case 'Variable': variables[payload.variableName] = payload.variableValue; break; default: break; } } function contains_opcua_command(payload) { return payload.hasOwnProperty('opcuaCommand'); } function execute_opcua_command(msg) { var payload = msg.payload; var addressSpace = server.engine.addressSpace; var name; switch (payload.opcuaCommand) { case "restartOPCUAServer": restart_server(); break; case "addEquipment": verbose_warn("adding Node".concat(payload.nodeName)); equipmentCounter++; name = payload.nodeName.concat(equipmentCounter); addressSpace.addObject({ organizedBy: addressSpace.findNode(equipment.nodeId), nodeId: "ns=4;s=".concat(name), browseName: name }); break; case "addPhysicalAsset": verbose_warn("adding Node".concat(payload.nodeName)); physicalAssetCounter++; name = payload.nodeName.concat(physicalAssetCounter); addressSpace.addObject({ organizedBy: addressSpace.findNode(physicalAssets.nodeId), nodeId: "ns=4;s=".concat(name), browseName: name }); break; case "setFolder": verbose_warn("set Folder".concat(msg.topic)); // Example topic format ns=4;s=FolderName folder = addressSpace.findNode(msg.topic); break; case "addFolder": verbose_warn("adding Folder".concat(msg.topic)); // Example topic format ns=4;s=FolderName var parentFolder = addressSpace.rootFolder.objects; if (folder!=null) { parentFolder = folder; // Use previous folder as parent or setFolder() can be use to set parent } folder = addressSpace.addObject({ organizedBy: addressSpace.findNode(parentFolder.nodeId), nodeId: msg.topic, browseName: msg.topic.substring(7) }); break; case "addVariable": verbose_warn("adding Node".concat(msg.topic)); // Example topic format ns=4;s=VariableName;datatype=Double var datatype = ""; var opcuaDataType = null; var e = msg.topic.indexOf("datatype="); var parentFolder = addressSpace.rootFolder.objects; if (folder!=null) { parentFolder = folder; // Use previous folder as parent or setFolder() can be use to set parent } if (e>0) { name = msg.topic.substring(0,e-1); datatype = msg.topic.substring(e+9); var browseName = name.substring(7); variables[browseName] = 0; if (datatype=="Int32") { opcuaDataType = opcua.DataType.Int32; } if (datatype=="Int16") { opcuaDataType = opcua.DataType.Int16; } if (datatype=="UInt32") { opcuaDataType = opcua.DataType.UInt32; } if (datatype=="UInt16") { opcuaDataType = opcua.DataType.UInt16; } if (datatype=="Double") { opcuaDataType = opcua.DataType.Double; } if (datatype=="Float") { opcuaDataType = opcua.DataType.Float; } if (datatype=="String") { opcuaDataType = opcua.DataType.String; variables[browseName] = ""; } if (datatype=="Boolean") { opcuaDataType = opcua.DataType.Boolean; variables[browseName] = true; } verbose_log(opcuaDataType.toString()); addressSpace.addVariable({ componentOf: addressSpace.findNode(parentFolder.nodeId), nodeId: name, browseName: browseName, // or displayName dataType: opcuaDataType, value: { get: function() { return new opcua.Variant({dataType: opcuaDataType, value: variables[browseName]}) } } }); } break; case "deleteNode": if (addressSpace === undefined) { node.error("addressSpace undefinded"); return false; } var searchedNode = addressSpace.findNode(payload.nodeId); if (searchedNode === undefined) { verbose_warn("can not find Node in addressSpace") } else { addressSpace.deleteNode(searchedNode); } break; default: node.error("unknown OPC UA Command"); } } function restart_server() { verbose_warn("Restart OPC UA Server"); if (server) { server.shutdown(0, function () { server = null; vendorName = null; initNewServer(); }); } else { server = null; vendorName = null; initNewServer(); } if (server) { verbose_warn("Restart OPC UA Server done"); } else { node.error("can not restart OPC UA Server"); } } node.on("close", function () { verbose_warn("closing..."); close_server(); }); function close_server() { if (server) { server.shutdown(0, function () { server = null; vendorName = null; }); } else { server = null; vendorName = null; } } } RED.nodes.registerType("OpcUa-Server", OpcUaServerNode); };