UNPKG

node-red-contrib-iiot-opcua

Version:

An Industrial IoT OPC UA toolbox contribution package for Node-RED based on node-opcua.

1,141 lines (1,135 loc) 47 kB
/** The BSD 3-Clause License Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com) Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/) Copyright 2015,2016 - Mika Karaila, Valmet Automation Inc. (node-red-contrib-opcua) All rights reserved. node-red-contrib-iiot-opcua */ 'use strict'; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.setNodeOPCUAConnected = exports.checkConnectorState = exports.isNodeId = exports.setNodeInitalState = exports.isSessionBad = exports.availableMemory = exports.buildNodeListFromClient = exports.buildNodesFromCrawler = exports.buildNodesFromBrowser = exports.buildNodesToListen = exports.buildNodesToRead = exports.buildNodesToWrite = exports.normalizeMessage = exports.createItemForWriteList = exports.newOPCUANodeIdFromMsgTopic = exports.newOPCUANodeIdFromItemNodeId = exports.parseIdentifierFromItemNodeId = exports.parseIdentifierFromMsgTopic = exports.parseForNodeIdentifier = exports.parseNamespaceFromItemNodeId = exports.parseNamespaceFromMsgTopic = exports.convertDataValueByDataType = exports.convertDataValue = exports.valueIsString = exports.getBasicDataTypes = exports.getVariantValue = exports.buildNewVariant = exports.getNodeStatus = exports.calcMillisecondsByTimeAndUnit = exports.getTimeUnitName = exports.getNodeOPCUAServerPath = exports.getNodeOPCUAClientPath = exports.getNodeOPCUAPath = exports.getPathFromRequireResolve = exports.regex_ns_g = exports.regex_ns_b = exports.regex_ns_s = exports.regex_ns_i = exports.DEFAULT_TIMEOUT = exports.FAKTOR_SEC_TO_MSEC = exports.isWindows = exports.RUNNING_STATE = exports.TEN_SECONDS_TIMEOUT = exports.OBJECTS_ROOT = exports.FsmListenerStates = exports.FsmConnectorStates = exports.nodeOPCUAId = exports.underscore = exports.os = exports.Debug = void 0; exports.isInitializedIIoTNode = exports.isNodeTypeToFilterResponse = exports.filterListByNodeId = exports.filterListEntryByNodeId = exports.resetIiotNode = exports.checkItemForUnsetState = exports.checkResponseItemIsNotToFilter = exports.checkCrawlerItemIsNotToFilter = exports.handleErrorInsideNode = exports.getItemFilterValueWithElement = exports.initCoreServerNode = exports.initCoreNode = exports.setNodeStatusTo = exports.checkSessionNotValid = exports.deregisterToConnector = exports.registerToConnector = exports.setNodeOPCUARestart = exports.setNodeOPCUASessionError = exports.setNodeOPCUASessionRestart = exports.setNodeOPCUASessionClosed = exports.setNodeOPCUASessionStarted = exports.setNodeOPCUALost = exports.setNodeOPCUAClosed = void 0; // SOURCE-MAP-REQUIRED const debug_1 = require("debug"); Object.defineProperty(exports, "Debug", { enumerable: true, get: function () { return debug_1.debug; } }); const os = __importStar(require("os")); exports.os = os; const underscore = __importStar(require("underscore")); exports.underscore = underscore; const underscore_1 = __importStar(require("underscore")); const nodeOPCUAId = __importStar(require("node-opcua-nodeid")); exports.nodeOPCUAId = nodeOPCUAId; const assertion_1 = require("../types/assertion"); const node_opcua_1 = require("node-opcua"); var FsmConnectorStates; (function (FsmConnectorStates) { FsmConnectorStates["StateIdle"] = "idle"; FsmConnectorStates["StateInit"] = "init"; FsmConnectorStates["StateOpened"] = "opened"; FsmConnectorStates["StateSessionRequested"] = "sessionRequested"; FsmConnectorStates["StateSessionActive"] = "sessionActive"; FsmConnectorStates["StateSessionClosed"] = "sessionClosed"; FsmConnectorStates["StateSessionRestart"] = "sessionRestart"; FsmConnectorStates["StateClosed"] = "closed"; FsmConnectorStates["StateLocked"] = "locked"; FsmConnectorStates["StateUnlocked"] = "unlocked"; FsmConnectorStates["StateStopped"] = "stopped"; FsmConnectorStates["StateEnd"] = "end"; FsmConnectorStates["StateReconfigured"] = "reconfigured"; FsmConnectorStates["StateRenewed"] = "renewed"; })(FsmConnectorStates = exports.FsmConnectorStates || (exports.FsmConnectorStates = {})); var FsmListenerStates; (function (FsmListenerStates) { FsmListenerStates["StateIdle"] = "idle"; FsmListenerStates["StateInit"] = "init"; FsmListenerStates["StateEnd"] = "end"; FsmListenerStates["StateRequested"] = "requested"; FsmListenerStates["StateStarted"] = "started"; FsmListenerStates["StateError"] = "error"; FsmListenerStates["StateTerminated"] = "terminated"; })(FsmListenerStates = exports.FsmListenerStates || (exports.FsmListenerStates = {})); exports.OBJECTS_ROOT = 'ns=0;i=84'; exports.TEN_SECONDS_TIMEOUT = 10; exports.RUNNING_STATE = FsmConnectorStates.StateSessionActive; exports.isWindows = /^win/.test(os.platform()); exports.FAKTOR_SEC_TO_MSEC = 1000; exports.DEFAULT_TIMEOUT = 1000; exports.regex_ns_i = /ns=([0-9]+);i=([0-9]+)/; exports.regex_ns_s = /ns=([0-9]+);s=(.*)/; exports.regex_ns_b = /ns=([0-9]+);b=(.*)/; exports.regex_ns_g = /ns=([0-9]+);g=(.*)/; var logger; (function (logger) { logger.internalDebugLog = (0, debug_1.debug)('opcuaIIoT:core'); logger.detailDebugLog = (0, debug_1.debug)('opcuaIIoT:core:details'); logger.specialDebugLog = (0, debug_1.debug)('opcuaIIoT:core:special'); })(logger || (logger = {})); logger.internalDebugLog(os.endianness()); logger.internalDebugLog(os.hostname()); logger.internalDebugLog(os.platform()); logger.internalDebugLog(os.type()); logger.internalDebugLog(os.arch()); const getPathFromRequireResolve = (requireResolve) => { let pathToNodeOPCUA = ''; if (exports.isWindows) { pathToNodeOPCUA = requireResolve.replace('\\index.js', ''); } else { pathToNodeOPCUA = requireResolve.replace('/index.js', ''); } logger.internalDebugLog('path to node-opcua: ' + pathToNodeOPCUA); return pathToNodeOPCUA; }; exports.getPathFromRequireResolve = getPathFromRequireResolve; function getNodeOPCUAPath() { return (0, exports.getPathFromRequireResolve)(require.resolve('node-opcua')); } exports.getNodeOPCUAPath = getNodeOPCUAPath; function getNodeOPCUAClientPath() { return (0, exports.getPathFromRequireResolve)(require.resolve('node-opcua-client')); } exports.getNodeOPCUAClientPath = getNodeOPCUAClientPath; function getNodeOPCUAServerPath() { return (0, exports.getPathFromRequireResolve)(require.resolve('node-opcua-server')); } exports.getNodeOPCUAServerPath = getNodeOPCUAServerPath; function getTimeUnitName(unit) { switch (unit) { case 'ms': return 'msec.'; case 's': return 'sec.'; case 'm': return 'min.'; case 'h': return 'h.'; default: return ''; } } exports.getTimeUnitName = getTimeUnitName; function calcMillisecondsByTimeAndUnit(time, unit) { switch (unit) { case 'ms': return time; case 's': return time * 1000; // seconds case 'm': return time * 60000; // minutes case 'h': return time * 3600000; // hours default: return 10000; // 10 sec. } } exports.calcMillisecondsByTimeAndUnit = calcMillisecondsByTimeAndUnit; function getNodeStatus(statusValue, statusLog) { let fillValue = 'yellow'; let shapeValue = 'ring'; switch (statusValue) { case 'initialize': case 'connecting': fillValue = 'yellow'; break; case 'connected': case 'keepalive': case 'subscribe': case 'started': if (!statusLog) { statusValue = 'active'; shapeValue = 'dot'; } fillValue = 'green'; break; case 'active': case 'subscribed': case 'listening': fillValue = 'green'; shapeValue = 'dot'; break; case 'disconnected': case 'terminated': fillValue = 'red'; break; case 'waiting': fillValue = 'blue'; shapeValue = 'dot'; statusValue = 'waiting ...'; break; case 'error': fillValue = 'red'; shapeValue = 'dot'; break; default: if (!statusValue) { fillValue = 'blue'; statusValue = 'waiting ...'; } } return { fill: fillValue, shape: shapeValue, text: statusValue }; } exports.getNodeStatus = getNodeStatus; function extractValue(value) { logger.detailDebugLog('extractValue value:' + value); if (underscore_1.default.isUndefined(value.value) === false) { return value.value; // value could be null, 0, and any other, but not undefined } return value; } function buildNewVariant(datatype, value) { let variantValue = { dataType: node_opcua_1.DataType.Null, value: null }; let originValue = Object.assign({}, value); value = extractValue(value); logger.detailDebugLog('buildNewVariant datatype: ' + datatype + ' originValue:' + originValue + ' value:' + value); switch (datatype) { case 'Float': case node_opcua_1.DataType.Float: variantValue = { dataType: node_opcua_1.DataType.Float, value: parseFloat(value) }; break; case 'Double': case node_opcua_1.DataType.Double: variantValue = { dataType: node_opcua_1.DataType.Double, value: parseFloat(value) }; break; case 'UInt16': case node_opcua_1.DataType.UInt16: let uint16 = new Uint16Array([value]); variantValue = { dataType: node_opcua_1.DataType.UInt16, value: uint16[0] }; break; case 'UInt32': case node_opcua_1.DataType.UInt32: let uint32 = new Uint32Array([value]); variantValue = { dataType: node_opcua_1.DataType.UInt32, value: uint32[0] }; break; case 'Int32': case node_opcua_1.DataType.Int32: variantValue = { dataType: node_opcua_1.DataType.Int32, value: parseInt(value) }; break; case 'Int16': case node_opcua_1.DataType.Int16: variantValue = { dataType: node_opcua_1.DataType.Int16, value: parseInt(value) }; break; case 'Int64': case node_opcua_1.DataType.Int64: variantValue = { dataType: node_opcua_1.DataType.Int64, value: parseInt(value) }; break; case 'Boolean': case node_opcua_1.DataType.Boolean: if (value && value !== 'false') { variantValue = { dataType: node_opcua_1.DataType.Boolean, value: true }; } else { variantValue = { dataType: node_opcua_1.DataType.Boolean, value: false }; } break; case 'LocalizedText': case node_opcua_1.DataType.LocalizedText: variantValue = { dataType: node_opcua_1.DataType.LocalizedText, value: JSON.parse(value) /* [{text:'Hello', locale:'en'}, {text:'Hallo', locale:'de'} ... ] */ }; break; case 'DateTime': case node_opcua_1.DataType.DateTime: variantValue = { dataType: node_opcua_1.DataType.DateTime, value: new Date(value) }; break; default: if (datatype !== '') { const datatypeList = getBasicDataTypes(); datatypeList.forEach((item) => { if (item.name === datatype || item.dataType === datatype) { variantValue = { dataType: item.dataType, value: value }; } }); } else { variantValue = { dataType: node_opcua_1.DataType.String, value: value }; } break; } logger.detailDebugLog('buildNewVariant variantValue: ' + JSON.stringify(variantValue)); return { value: variantValue }; } exports.buildNewVariant = buildNewVariant; function getVariantValue(datatype, value) { switch (datatype) { case 'Float': case 'Double': case node_opcua_1.DataType.Double: return parseFloat(value); case 'UInt16': case node_opcua_1.DataType.UInt16: let uint16 = new Uint16Array([value]); return uint16[0]; case 'UInt32': case node_opcua_1.DataType.UInt32: let uint32 = new Uint32Array([value]); return uint32[0]; case 'UInt64': case node_opcua_1.DataType.UInt64: return parseInt(value); case 'Int16': case node_opcua_1.DataType.Int16: case 'Int32': case 'Integer': case node_opcua_1.DataType.Int32: case 'Int64': case node_opcua_1.DataType.Int64: return parseInt(value); case 'Boolean': case node_opcua_1.DataType.Boolean: return (value && value !== 'false'); case 'DateTime': case node_opcua_1.DataType.DateTime: return new Date(value); case 'String': case node_opcua_1.DataType.String: return (typeof value !== 'string') ? value.toString() : value; default: return value; } } exports.getVariantValue = getVariantValue; function getBasicDataTypes() { return [ { name: 'Null', dataType: node_opcua_1.DataType.Null }, { name: 'Boolean', dataType: node_opcua_1.DataType.Boolean }, { name: 'SByte', dataType: node_opcua_1.DataType.SByte }, { name: 'Byte', dataType: node_opcua_1.DataType.Byte }, { name: 'Int16', dataType: node_opcua_1.DataType.Int16 }, { name: 'UInt16', dataType: node_opcua_1.DataType.UInt16 }, { name: 'Int32', dataType: node_opcua_1.DataType.Int32 }, { name: 'UInt32', dataType: node_opcua_1.DataType.UInt32 }, { name: 'Int64', dataType: node_opcua_1.DataType.Int64 }, { name: 'UInt64', dataType: node_opcua_1.DataType.UInt64 }, { name: 'Float', dataType: node_opcua_1.DataType.Float }, { name: 'Double', dataType: node_opcua_1.DataType.Double }, { name: 'DateTime', dataType: node_opcua_1.DataType.DateTime }, { name: 'String', dataType: node_opcua_1.DataType.String }, { name: 'Guid', dataType: node_opcua_1.DataType.Guid }, { name: 'ByteString', dataType: node_opcua_1.DataType.ByteString }, { name: 'XmlElement', dataType: node_opcua_1.DataType.XmlElement }, { name: 'NodeId', dataType: node_opcua_1.DataType.NodeId }, { name: 'ExpandedNodeId', dataType: node_opcua_1.DataType.ExpandedNodeId }, { name: 'StatusCode', dataType: node_opcua_1.DataType.StatusCode }, { name: 'LocalizedText', dataType: node_opcua_1.DataType.LocalizedText }, { name: 'ExtensionObject', dataType: node_opcua_1.DataType.ExtensionObject }, { name: 'DataValue', dataType: node_opcua_1.DataType.DataValue }, { name: 'Variant', dataType: node_opcua_1.DataType.Variant }, { name: 'DiagnosticInfo', dataType: node_opcua_1.DataType.DiagnosticInfo } ]; } exports.getBasicDataTypes = getBasicDataTypes; function valueIsString(value) { return typeof value === 'string'; } exports.valueIsString = valueIsString; function convertDataValue(value) { if (valueIsString(value)) { return value; } else return convertDataValueByDataType(value.value.value, value.value.dataType); } exports.convertDataValue = convertDataValue; function convertDataValueByDataType(value, dataType) { let convertedValue = null; const valueType = typeof value; logger.detailDebugLog('convertDataValue: ' + JSON.stringify(value) + ' value origin type ' + valueType + ' convert to' + ' ' + dataType); // TODO: we have to check if that is needed or to improve since v2.x - here was a problem, that the node-opcua sent strings or types try { switch (dataType) { case 'NodeId': case node_opcua_1.DataType.NodeId: convertedValue = value.toString(); break; case 'ExpandedNodeId': case node_opcua_1.DataType.ExpandedNodeId: if (value.value instanceof Buffer) { convertedValue = value.toString(); } else { convertedValue = value; } break; case 'ByteString': case node_opcua_1.DataType.ByteString: convertedValue = value; break; case 'Byte': case node_opcua_1.DataType.Byte: if (valueType === 'boolean') { convertedValue = value ? 1 : 0; } else { convertedValue = parseInt(value); } break; case 'QualifiedName': case node_opcua_1.DataType.QualifiedName: convertedValue = value.toString(); break; case 'LocalizedText': case node_opcua_1.DataType.LocalizedText: convertedValue = value; break; case 'Float': case node_opcua_1.DataType.Float: if (isNaN(value)) { convertedValue = value; } else { convertedValue = parseFloat(value); } break; case 'Double': case node_opcua_1.DataType.Double: if (isNaN(value)) { convertedValue = value; } else { convertedValue = parseFloat(value); } break; case 'UInt16': case node_opcua_1.DataType.UInt16: let uint16 = new Uint16Array([value]); convertedValue = uint16[0]; break; case 'UInt32': case node_opcua_1.DataType.UInt32: let uint32 = new Uint32Array([value]); convertedValue = uint32[0]; break; case 'Int16': case node_opcua_1.DataType.Int16: case 'Int32': case node_opcua_1.DataType.Int32: case 'Int64': case node_opcua_1.DataType.Int64: if (valueType === 'boolean') { convertedValue = value ? 1 : 0; } else { if (isNaN(value)) { convertedValue = value; } else { convertedValue = parseInt(value); } } break; case 'Boolean': case node_opcua_1.DataType.Boolean: convertedValue = value; break; case 'String': case node_opcua_1.DataType.String: if (valueType !== 'string') { convertedValue = value.toString(); } else { convertedValue = value; } break; case 'Null': case node_opcua_1.DataType.Null: convertedValue = null; break; case "DateTime": case node_opcua_1.DataType.DateTime: if (valueType !== 'string') { convertedValue = value.toString(); } else { convertedValue = value; } break; default: logger.internalDebugLog('convertDataValue unused DataType: ' + dataType); if (underscore_1.default.isUndefined(value)) { convertedValue = null; } else { convertedValue = value; } break; } } catch (err) { logger.detailDebugLog('convertDataValue ' + err); } logger.detailDebugLog('convertDataValue is: ' + convertedValue); return convertedValue; } exports.convertDataValueByDataType = convertDataValueByDataType; function parseNamespaceFromMsgTopic(msg) { let nodeNamespace = ''; if (msg === null || msg === void 0 ? void 0 : msg.topic) { // TODO: real parsing instead of string operations // TODO: which type are relevant here? (String, Integer ...) nodeNamespace = msg.topic.substring(3, msg.topic.indexOf(';')); } return Number.parseInt(nodeNamespace); } exports.parseNamespaceFromMsgTopic = parseNamespaceFromMsgTopic; function parseNamespaceFromItemNodeId(item) { if (typeof item === 'number') { return 0; } if ((0, underscore_1.isObject)(item) && item.namespace) { return item.namespace; } // TODO: real parsing instead of string operations const nodeObject = JSON.parse(JSON.stringify(item)); return Number.parseInt(nodeObject.nodeId.substring(3, nodeObject.nodeId.indexOf(';'))); } exports.parseNamespaceFromItemNodeId = parseNamespaceFromItemNodeId; function parseForNodeIdentifier(nodeItem) { if (nodeItem) { // TODO: real parsing instead of string operations if (nodeItem.includes(';i=')) { return { identifier: parseInt(nodeItem.substring(nodeItem.indexOf(';i=') + 3)), type: node_opcua_1.NodeIdType.NUMERIC }; } else if (nodeItem.includes(';g=')) { return { identifier: nodeItem.substring(nodeItem.indexOf(';g=') + 3), type: node_opcua_1.NodeIdType.GUID }; } else { if (nodeItem.includes(';b=')) { return { identifier: nodeItem.substring(nodeItem.indexOf(';b=') + 3), type: node_opcua_1.NodeIdType.BYTESTRING }; } else { return { identifier: nodeItem.substring(nodeItem.indexOf(';s=') + 3), type: node_opcua_1.NodeIdType.STRING }; } } } return { identifier: 'null', type: 0x00 }; } exports.parseForNodeIdentifier = parseForNodeIdentifier; function parseIdentifierFromMsgTopic(msg) { return parseForNodeIdentifier(msg.topic); } exports.parseIdentifierFromMsgTopic = parseIdentifierFromMsgTopic; function parseIdentifierFromItemNodeId(item) { return parseForNodeIdentifier(item.nodeId || item); } exports.parseIdentifierFromItemNodeId = parseIdentifierFromItemNodeId; function newOPCUANodeIdFromItemNodeId(item) { let namespace = parseNamespaceFromItemNodeId(item); let nodeIdentifier = parseIdentifierFromItemNodeId(item); logger.internalDebugLog('newOPCUANodeIdFromItemNodeId: ' + JSON.stringify(item) + ' -> ' + JSON.stringify(nodeIdentifier) + ' namespace:' + namespace); return new node_opcua_1.NodeId(nodeIdentifier.type, nodeIdentifier.identifier, namespace); } exports.newOPCUANodeIdFromItemNodeId = newOPCUANodeIdFromItemNodeId; function newOPCUANodeIdFromMsgTopic(msg) { let namespace = parseNamespaceFromMsgTopic(msg); let nodeIdentifier = parseIdentifierFromMsgTopic(msg); logger.internalDebugLog('newOPCUANodeIdFromMsgTopic: ' + JSON.stringify(nodeIdentifier)); return new node_opcua_1.NodeId(nodeIdentifier.type, nodeIdentifier.identifier, namespace); } exports.newOPCUANodeIdFromMsgTopic = newOPCUANodeIdFromMsgTopic; function createItemForWriteList(item, value) { return { nodeId: newOPCUANodeIdFromItemNodeId(item), attributeId: node_opcua_1.AttributeIds.Value, indexRange: undefined, value }; } exports.createItemForWriteList = createItemForWriteList; function normalizeMessage(msg) { const payload = msg.payload; const addressSpaceValues = payload.nodesToWrite || payload.addressSpaceItems; if (!addressSpaceValues) return []; const writeValues = payload.valuesToWrite; if (!(0, assertion_1.isNotDefined)(writeValues)) { return addressSpaceValues.map((item, index) => { return Object.assign(Object.assign({}, item), { value: underscore_1.default.isUndefined(writeValues[index]) ? null : writeValues[index] }); }); } else return addressSpaceValues.map((item, index) => { if (item.value) return item; else return Object.assign(Object.assign({}, item), { value: (Array.isArray(msg.payload) && msg.payload.length && msg.payload.length === msg.addressSpaceItems.length) ? msg.payload[index] : msg.payload }); }); } exports.normalizeMessage = normalizeMessage; function buildNodesToWrite(msg) { logger.detailDebugLog('buildNodesToWrite input: ' + JSON.stringify(msg)); const writeInputs = normalizeMessage(msg); const nodesToWrite = writeInputs.map((item) => createItemForWriteList(item, buildNewVariant(item.datatypeName, item.value))); logger.internalDebugLog('buildNodesToWrite output: ' + JSON.stringify(nodesToWrite)); return nodesToWrite; } exports.buildNodesToWrite = buildNodesToWrite; function buildNodesToRead(payload) { var _a; logger.detailDebugLog('buildNodesToRead input: ' + JSON.stringify(payload)); let injectArrayOfNodeIds = (((_a = payload.value) === null || _a === void 0 ? void 0 : _a.length) && payload.value.type === Array) ? payload.value : payload.addressSpaceItems; /* there are some possible ways to receive the Array<any> from Browser or Inject TODO: payload.injectType and/or payload.nodetype should be used to make a clear decision here read : nodesToRead write : nodesToWrite browse : browserResults crawl : crawlerResults value : inject with Array<any> addressSpaceItems : inject fall back for all types */ let nodePayloadList = payload.nodesToRead || payload.nodesToWrite || payload.crawlerResults || payload.browserResults || injectArrayOfNodeIds; if (nodePayloadList && nodePayloadList.length) { return nodePayloadList.map((item) => { return item; }); } else { let nodeList = payload.nodesToRead || payload.nodesToWrite; if (nodeList && nodeList.length) { // legacy return nodeList.map((item) => { return item; }); } else if (payload.addressSpaceItems && payload.addressSpaceItems.length) { return payload.addressSpaceItems.map((item) => item); } } return []; } exports.buildNodesToRead = buildNodesToRead; function buildNodesToListen(payload) { var _a, _b; if ((_a = payload.addressItemsToRead) === null || _a === void 0 ? void 0 : _a.length) return payload.addressItemsToRead; else if ((_b = payload.addressSpaceItems) === null || _b === void 0 ? void 0 : _b.length) return payload.addressSpaceItems; else return payload.addressSpaceItemList; } exports.buildNodesToListen = buildNodesToListen; function buildNodesFromBrowser(payload) { return payload.browserResults || payload.addressSpaceItems; } exports.buildNodesFromBrowser = buildNodesFromBrowser; function buildNodesFromCrawler(payload) { return payload.crawlerResults || payload.addressSpaceItems; } exports.buildNodesFromCrawler = buildNodesFromCrawler; function buildNodeListFromClient(payload) { /* The node type should help users to be aware of wiring mistakes. We want to support the user with messages if the wiring and inputs are wrong. That brings the needs of a nodeType (where does it come from) and injectType (where should it be for). This was the real last feature and needs some more refactoring and work to be done well. */ switch (payload.nodetype) { case 'read': case 'write': return buildNodesToRead(payload); case 'node': case 'listen': case 'inject': case 'events': return buildNodesToListen(payload); case 'browse': return buildNodesFromBrowser(payload); case 'crawl': return buildNodesFromCrawler(payload); default: logger.internalDebugLog('unknown node type injected to filter for ' + payload.nodetype); return []; } } exports.buildNodeListFromClient = buildNodeListFromClient; function availableMemory() { return os.freemem() / os.totalmem() * 100.0; } exports.availableMemory = availableMemory; function isSessionBad(err) { return (err.toString().includes('Session') || err.toString().includes('Channel') || err.toString().includes('Transaction') || err.toString().includes('timeout') || err.toString().includes('Connection')); } exports.isSessionBad = isSessionBad; function setNodeInitalState(nodeState, node, statusCall) { switch (nodeState) { case 'INITOPCUA': case 'SESSIONREQUESTED': node.oldStatusParameter = setNodeStatusTo(node, 'connecting', node.oldStatusParameter, node.showStatusActivities, statusCall); break; case 'OPEN': case 'SESSIONCLOSED': node.iiot.opcuaClient = node.connector.iiot.opcuaClient; node.oldStatusParameter = setNodeStatusTo(node, 'connected', node.oldStatusParameter, node.showStatusActivities, statusCall); break; case 'SESSIONACTIVE': node.iiot.opcuaSession = node.connector.iiot.opcuaSession; node.oldStatusParameter = setNodeStatusTo(node, 'active', node.oldStatusParameter, node.showStatusActivities, statusCall); break; case 'LOCKED': node.oldStatusParameter = setNodeStatusTo(node, 'locked', node.oldStatusParameter, node.showStatusActivities, statusCall); break; case 'UNLOCKED': node.oldStatusParameter = setNodeStatusTo(node, 'unlocked', node.oldStatusParameter, node.showStatusActivities, statusCall); break; case 'STOPPED': node.oldStatusParameter = setNodeStatusTo(node, 'stopped', node.oldStatusParameter, node.showStatusActivities, statusCall); break; case 'END': node.oldStatusParameter = setNodeStatusTo(node, 'end', node.oldStatusParameter, node.showStatusActivities, statusCall); break; default: node.oldStatusParameter = setNodeStatusTo(node, 'waiting', node.oldStatusParameter, node.showStatusActivities, statusCall); } } exports.setNodeInitalState = setNodeInitalState; function isNodeId(nodeId) { if (!nodeId || !nodeId.identifierType) { return false; } switch (nodeId.identifierType) { case node_opcua_1.NodeIdType.NUMERIC: case node_opcua_1.NodeIdType.STRING: case node_opcua_1.NodeIdType.GUID: return true; default: return false; } } exports.isNodeId = isNodeId; function checkConnectorState(node, msg, callerType, errorHandler, emitHandler, statusHandler) { var _a, _b; const state = (_b = (_a = node.connector) === null || _a === void 0 ? void 0 : _a.iiot.stateService) === null || _b === void 0 ? void 0 : _b.state.value; logger.internalDebugLog('Check Connector State ' + state + ' By ' + callerType); if (state !== exports.RUNNING_STATE) { logger.internalDebugLog('Wrong Client State ' + state + ' By ' + callerType); if (node.showErrors) { errorHandler(new Error('Client Not ' + exports.RUNNING_STATE + ' On ' + callerType), msg); } node.oldStatusParameter = setNodeStatusTo(node, 'not running', node.oldStatusParameter, node.showStatusActivities, statusHandler); emitHandler('opcua_client_not_ready'); return false; } else { return true; } } exports.checkConnectorState = checkConnectorState; function setNodeOPCUAConnected(node, opcuaClient, statusHandler) { if (isInitializedIIoTNode(node)) { node.iiot.opcuaClient = opcuaClient; } node.oldStatusParameter = setNodeStatusTo(node, 'connecting', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUAConnected = setNodeOPCUAConnected; function setNodeOPCUAClosed(node, statusHandler) { if (isInitializedIIoTNode(node)) { // @ts-ignore node.iiot.opcuaClient = null; } node.oldStatusParameter = setNodeStatusTo(node, 'disconnected', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUAClosed = setNodeOPCUAClosed; function setNodeOPCUALost(node, statusHandler) { node.oldStatusParameter = setNodeStatusTo(node, 'lost', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUALost = setNodeOPCUALost; function setNodeOPCUASessionStarted(node, opcuaSession, statusHandler) { if (isInitializedIIoTNode(node)) { node.iiot.opcuaSession = opcuaSession; } node.oldStatusParameter = setNodeStatusTo(node, 'active', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUASessionStarted = setNodeOPCUASessionStarted; function setNodeOPCUASessionClosed(node, statusHandler) { if (isInitializedIIoTNode(node)) { node.iiot.opcuaSession = null; } node.oldStatusParameter = setNodeStatusTo(node, 'connecting', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUASessionClosed = setNodeOPCUASessionClosed; function setNodeOPCUASessionRestart(node, statusHandler) { node.oldStatusParameter = setNodeStatusTo(node, 'restart', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUASessionRestart = setNodeOPCUASessionRestart; function setNodeOPCUASessionError(node, statusHandler) { if (isInitializedIIoTNode(node)) { node.iiot.opcuaSession = null; } node.oldStatusParameter = setNodeStatusTo(node, 'connecting', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUASessionError = setNodeOPCUASessionError; function setNodeOPCUARestart(node, opcuaClient, statusHandler) { logger.internalDebugLog('Connector Restart'); if (opcuaClient && isInitializedIIoTNode(node)) { node.iiot.opcuaClient = opcuaClient; } node.oldStatusParameter = setNodeStatusTo(node, 'connecting', node.oldStatusParameter, node.showStatusActivities, statusHandler); } exports.setNodeOPCUARestart = setNodeOPCUARestart; function registerToConnector(node, statusCallback, onAlias, errorHandler) { var _a, _b, _c; if (!node) { logger.internalDebugLog('Node Not Valid On Register To Connector'); return; } if ((0, assertion_1.isNotDefined)(node.connector)) { errorHandler(new Error('Connector Config Node Not Valid On Registering Client Node ' + node.id), { payload: 'No Connector Configured' }); return; } if (!node.connector.statusCallbacks) { node.connector.statusCallbacks = []; } node.connector.statusCallbacks.push(statusCallback); (_a = node.connector.functions) === null || _a === void 0 ? void 0 : _a.registerForOPCUA(node, onAlias); const statusCall = (status) => { node.connector.statusCallbacks.forEach((callback) => callback(status)); }; node.connector.on('connector_init', (node) => { var _a, _b; if ((_a = node.iiot) === null || _a === void 0 ? void 0 : _a.opcuaClient) { // @ts-ignore node.iiot.opcuaClient = null; } if ((_b = node.iiot) === null || _b === void 0 ? void 0 : _b.opcuaSession) { node.iiot.opcuaSession = null; } }); node.connector.on('connection_started', (opcuaClient) => { setNodeOPCUAConnected(node.connector, opcuaClient, statusCall); }); node.connector.on('server_connection_close', () => { setNodeOPCUAClosed(node.connector, statusCall); }); node.connector.on('server_connection_abort', () => { setNodeOPCUAClosed(node.connector, statusCall); }); node.connector.on('connection_closed', () => { setNodeOPCUAClosed(node.connector, statusCall); }); node.connector.on('server_connection_lost', () => { setNodeOPCUALost(node.connector, statusCall); }); node.connector.on('reset_opcua_connection', () => { setNodeOPCUASessionClosed(node.connector, statusCall); }); node.connector.on('session_started', (opcuaSession) => { setNodeOPCUASessionStarted(node.connector, opcuaSession, statusCall); }); node.connector.on('session_closed', () => { setNodeOPCUASessionClosed(node.connector, statusCall); }); node.connector.on('session_restart', () => { setNodeOPCUAClosed(node.connector, statusCall); }); node.connector.on('session_error', () => { setNodeOPCUASessionError(node.connector, statusCall); }); node.connector.on('after_reconnection', () => { setNodeOPCUARestart(node.connector, node_opcua_1.OPCUAClient.create(node.connector.iiot.opcuaClient), statusCall); // TODO: investigate one args v two }); setNodeInitalState((_c = (_b = node.connector) === null || _b === void 0 ? void 0 : _b.iiot) === null || _c === void 0 ? void 0 : _c.stateService.state.value, node, statusCall); } exports.registerToConnector = registerToConnector; function deregisterToConnector(node, done) { var _a, _b; if (!node) { logger.internalDebugLog('Node Not Valid On Register To Connector'); done(); return; } if (!node.connector) { node.error(new Error('Connector Not Valid On Register To Connector'), { payload: 'No Connector Configured' }); done(); return; } if (isInitializedIIoTNode(node.connector)) { (_b = (_a = node.connector) === null || _a === void 0 ? void 0 : _a.functions) === null || _b === void 0 ? void 0 : _b.deregisterForOPCUA(node, done); } else { done(); } } exports.deregisterToConnector = deregisterToConnector; function checkSessionNotValid(session, callerType) { if (!session) { logger.internalDebugLog('Session Not Valid On Check For ' + callerType); return true; } if (session.sessionId === 'terminated') { logger.internalDebugLog('Session Is Valid But Terminated On Check For ' + callerType); return true; } return false; } exports.checkSessionNotValid = checkSessionNotValid; function setNodeStatusTo(node, statusValue, oldStatus, showStatusActivities, status) { let statusParameter = getNodeStatus(statusValue, showStatusActivities); if (!underscore.isEqual(oldStatus, statusParameter) && statusParameter) { logger.detailDebugLog('Node ' + node.id + ' Status To ' + statusValue); if (typeof status === "function") status(statusParameter); else logger.internalDebugLog("Status is not a function " + typeof status); } return statusParameter; } exports.setNodeStatusTo = setNodeStatusTo; // sets some values within node.iiot function initCoreNode() { return { reconnectTimeout: exports.DEFAULT_TIMEOUT, sessionTimeout: undefined, opcuaSession: undefined, opcuaClient: undefined }; } exports.initCoreNode = initCoreNode; function initCoreServerNode() { return { initialized: false, opcuaServer: null }; } exports.initCoreServerNode = initCoreServerNode; function getItemFilterValueWithElement(item, element) { let filterValue = ''; switch (element.name) { case 'browseName': case 'statusCode': filterValue = item[element.name].name; break; case 'displayName': filterValue = item[element.name].text; break; case 'value': case 'dataType': if (item.value && item.value.hasOwnProperty('value')) { filterValue = item.value[element.name]; } else { filterValue = item[element.name]; } break; case 'nodeClass': filterValue = node_opcua_1.NodeClass[item['nodeClass']]; break; default: filterValue = item[element.name]; } return filterValue; } exports.getItemFilterValueWithElement = getItemFilterValueWithElement; function handleErrorInsideNode(node, err) { logger.internalDebugLog(typeof node + ' ' + err.message); if (node.showErrors) { node.error(err, { payload: err.message }); } } exports.handleErrorInsideNode = handleErrorInsideNode; function checkCrawlerItemIsNotToFilter(node, item, element, result) { try { let filterValue = getItemFilterValueWithElement(item, element); if (filterValue && typeof filterValue !== "string" && filterValue.key && filterValue.key.match) { if (!filterValue.key.match(element.value)) { result = 0; } } else { if (filterValue && filterValue.match) { if (!filterValue.match(element.value)) { result = 0; } } else { if (filterValue && filterValue.toString) { filterValue = filterValue.toString(); if (filterValue && filterValue.match) { if (!filterValue.match(element.value)) { result = 0; } } } } } } catch (err) { handleErrorInsideNode(node, err); } return result; } exports.checkCrawlerItemIsNotToFilter = checkCrawlerItemIsNotToFilter; function checkResponseItemIsNotToFilter(node, item, element, result) { try { let filterValue = getItemFilterValueWithElement(item, element); if (filterValue) { if (typeof filterValue !== 'string' && filterValue.key && filterValue.key.match) { result &= filterValue.key.match(element.value) !== null ? 1 : 0; } else { if (filterValue.match) { result &= filterValue.match(element.value) !== null ? 1 : 0; } else { if (filterValue.toString) { filterValue = filterValue.toString(); if (filterValue.match) { result &= filterValue.match(element.value) !== null ? 1 : 0; } } } } } else { result &= 0; // undefined items } } catch (err) { handleErrorInsideNode(node, err); } return result; } exports.checkResponseItemIsNotToFilter = checkResponseItemIsNotToFilter; function checkItemForUnsetState(node, item) { let result = 1; if (node.activateUnsetFilter) { result &= item !== null ? 1 : 0; if (item && item.hasOwnProperty('value')) { if (item.value && item.value.hasOwnProperty('value')) { result &= item.value.value !== null ? 1 : 0; } else { result &= item.value !== null ? 1 : 0; } } } return result; } exports.checkItemForUnsetState = checkItemForUnsetState; function resetIiotNode(node) { // coreListener.internalDebugLog('reset IIoT of the Node with id:' + node.id) /// Invalid import of lower hirarchy module // Valid hirarchy is supposed to be: Core -> CoreSpecific (CoreListener, CoreConnector, ...) -> Specific (Listener, Browser, ...) // This is because looped imports and usages before declaration can happen if this is not kept in mind if (underscore_1.default.isObject(node) == false || underscore_1.default.isEmpty(node.iiot)) { return; } else { if (underscore_1.default.isFunction(node.resetAllTimer)) { node.resetAllTimer(); // call to close all timer otherwise it stops until timeout and node-red hangs on } } if (isInitializedIIoTNode(node.iiot) && underscore_1.default.isFunction(node.iiot.resetAllTimer)) { node.iiot.resetAllTimer(); } } exports.resetIiotNode = resetIiotNode; function filterListEntryByNodeId(nodeId, list) { return list.filter((item) => { return item.toString().includes(nodeId); }); } exports.filterListEntryByNodeId = filterListEntryByNodeId; function filterListByNodeId(nodeId, list) { if (nodeId === '') { return list; } return list.filter((item) => { // if item.nodeId is null, item may itself be a nodeId return (item.nodeId || item).toString().includes(nodeId); }); } exports.filterListByNodeId = filterListByNodeId; function isNodeTypeToFilterResponse(payload) { return payload.nodetype === 'read' || payload.nodetype === 'browse' || payload.nodetype === 'crawl' || payload.nodetype === 'method'; } exports.isNodeTypeToFilterResponse = isNodeTypeToFilterResponse; function isInitializedIIoTNode(node) { return !!node; } exports.isInitializedIIoTNode = isInitializedIIoTNode; //# sourceMappingURL=opcua-iiot-core.js.map