UNPKG

node-red-contrib-iiot-opcua

Version:

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

276 lines (273 loc) 12.6 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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const opcua_iiot_core_1 = require("./core/opcua-iiot-core"); const opcua_iiot_core_browser_1 = __importDefault(require("./core/opcua-iiot-core-browser")); const assertion_1 = require("./types/assertion"); /** * Crawler Node-RED nodeConfig. * * @param RED */ module.exports = (RED) => { // SOURCE-MAP-REQUIRED function OPCUAIIoTCrawler(config) { RED.nodes.createNode(this, config); this.name = config.name; this.justValue = config.justValue; this.singleResult = config.singleResult; this.showStatusActivities = config.showStatusActivities; this.showErrors = config.showErrors; this.activateUnsetFilter = config.activateUnsetFilter; this.activateFilters = config.activateFilters; this.negateFilter = config.negateFilter; this.filters = config.filters; this.delayPerMessage = config.delayPerMessage || 0.2; this.timeout = config.timeout || 30; this.connector = RED.nodes.getNode(config.connector); let self = this; const { iiot, browseTopic } = opcua_iiot_core_browser_1.default.initBrowserNode(); self.browseTopic = browseTopic; self.iiot = iiot; self.iiot.delayMessageTimer = []; const filterCrawlerResults = function (crawlerResultToFilter) { let crawlerResult = crawlerResultToFilter || []; let filteredEntries = []; if (self.activateFilters && self.filters && self.filters.length > 0) { crawlerResult.forEach(function (item) { if (itemIsNotToFilter(item)) { filteredEntries.push(item); } }); crawlerResult = filteredEntries; } if (self.justValue) { crawlerResult.forEach(function (item) { if (item.references) { delete item['references']; } }); } return crawlerResult; }; const itemIsNotToFilter = function (item) { let result = (0, opcua_iiot_core_1.checkItemForUnsetState)(self, item); if (result) { result = self.filters.every((element) => { return (0, opcua_iiot_core_1.checkCrawlerItemIsNotToFilter)(self, item, element, result) !== 0; }) ? 1 : 0; } return (self.negateFilter) ? !result : result; }; const crawl = (session, payload, statusHandler) => __awaiter(this, void 0, void 0, function* () { if ((0, opcua_iiot_core_1.checkSessionNotValid)(self.connector.iiot.opcuaSession, 'Crawler')) { return; } opcua_iiot_core_browser_1.default.internalDebugLog('Browse Topic To Call Crawler ' + self.browseTopic); if (self.showStatusActivities && self.oldStatusParameter) { self.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(self, 'crawling', self.oldStatusParameter, self.showStatusActivities, statusHandler); } opcua_iiot_core_browser_1.default.crawl(session, self.browseTopic, payload, getSendWrapper(payload)); }); const callError = (err, msg) => { this.error(err, msg); }; const statusHandler = (status) => { this.status(status); }; const crawlForSingleResult = function (session, payload) { opcua_iiot_core_browser_1.default.crawlAddressSpaceItems(session, payload, getSendWrapper(payload), self.timeout); }; const handleResultArray = (results, payload) => { // map each result 1-to-1 input to output const crawlerResult = results.map(function (result) { if (result.value instanceof Error) { return result.value.toString(); } else { return filterCrawlerResults(result.value); } }); // combine the valid results into payload.value const value = crawlerResult.filter((result) => { return !(typeof result === 'string'); }).flatMap((result) => { return result; }); // list errors in payload.error const error = results.filter((result) => { return (result.value instanceof Error); }).map((result) => { return result.value; }); if (error.length > 0) { payload.error = error; } payload.value = value; sendMessage(payload, crawlerResult); }; /** * Returns a sendWrapper function with the correct payload context */ const getSendWrapper = (payload) => { return (result) => { if (result.promises) { handleResultArray(result.crawlerResult, payload); } else if (result instanceof Error) { opcua_iiot_core_browser_1.default.browseErrorHandling(self, result, payload, undefined, callError, statusHandler, self.oldStatusParameter, self.showErrors, self.showStatusActivities); } else { opcua_iiot_core_browser_1.default.internalDebugLog(result.rootNodeId + ' Crawler Results ' + result.crawlerResult.length); const filteredResults = filterCrawlerResults(result.crawlerResult); payload.value = [filteredResults]; sendMessage(payload, filteredResults); } }; }; const crawlForResults = function (session, payload) { var _a; (_a = payload.addressSpaceItems) === null || _a === void 0 ? void 0 : _a.forEach((entry) => { opcua_iiot_core_browser_1.default.crawl(session, entry.nodeId, payload, getSendWrapper(payload)); }); }; const crawlNodeList = function (session, payload) { if (self.showStatusActivities && self.oldStatusParameter) { self.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(self, 'crawling', self.oldStatusParameter, self.showStatusActivities, statusHandler); } if (self.singleResult) { crawlForSingleResult(session, payload); } else { crawlForResults(session, payload); } }; const sendMessage = (payload, crawlerResult) => { const { _msgid, topic } = payload, restMessage = __rest(payload, ["_msgid", "topic"]); restMessage.nodetype = 'crawl'; try { RED.util.setMessageProperty(restMessage, 'crawlerResults', JSON.parse(JSON.stringify(crawlerResult, null, 2))); } catch (err) { opcua_iiot_core_browser_1.default.internalDebugLog(err); if (self.showErrors) { this.error(err, restMessage); } restMessage.resultsConverted = JSON.stringify(crawlerResult, null, 2); restMessage.error = err.message; } if (self.browseTopic && self.browseTopic !== '') { restMessage.browseTopic = self.browseTopic; } if (restMessage.crawlerResults.length === 1 && (0, assertion_1.isArray)(restMessage.crawlerResults[0])) { restMessage.crawlerResults = restMessage.crawlerResults[0]; } if (!self.justValue) { restMessage.crawlerResultsCount = crawlerResult.length; if (self.connector) { restMessage.endpoint = self.connector.endpoint; } restMessage.session = self.connector.iiot.opcuaSession.name || 'none'; } const msg = { _msgid, topic, payload: restMessage }; self.iiot.messageList.push(msg); if (self.showStatusActivities && self.oldStatusParameter) { self.oldStatusParameter = (0, opcua_iiot_core_1.setNodeStatusTo)(self, 'active', self.oldStatusParameter, self.showStatusActivities, statusHandler); } // TODO: maybe here RED.util.set ... self.iiot.delayMessageTimer.push(setTimeout(() => { this.send(self.iiot.messageList.shift()); }, self.delayPerMessage * opcua_iiot_core_1.FAKTOR_SEC_TO_MSEC)); }; const resetAllTimer = function () { self.iiot.delayMessageTimer.forEach((timerId) => { clearTimeout(timerId); timerId = null; }); }; const startCrawling = (payload) => __awaiter(this, void 0, void 0, function* () { if (!self.connector) { return; } if (self.connector.functions.hasNoSession()) { yield self.connector.functions.startSession(self.id); } if (self.browseTopic && self.browseTopic !== '') { crawl(self.connector.iiot.opcuaSession, payload, statusHandler); } else { if (payload.addressSpaceItems && payload.addressSpaceItems.length) { opcua_iiot_core_browser_1.default.internalDebugLog('Start Crawling On AddressSpace Items'); crawlNodeList(self.connector.iiot.opcuaSession, payload); } else { this.error(new Error('No AddressSpace Items Or Root To Crawl'), payload); } } }); const errorHandler = (err, msg) => { this.error(err, msg); }; const setStatus = (status) => { this.status(status); }; const emitHandler = (msg) => { this.emit(msg); }; const onAlias = (event, callback) => { this.on(event, callback); }; this.on('input', function (msg) { const payload = msg.payload; self.browseTopic = opcua_iiot_core_browser_1.default.extractNodeIdFromTopic(payload, self); payload._msgid = msg._msgid; payload.topic = msg.topic; startCrawling(msg.payload).finally(); }); (0, opcua_iiot_core_1.registerToConnector)(this, setStatus, onAlias, errorHandler); this.on('close', (done) => { self.removeAllListeners(); resetAllTimer(); (0, opcua_iiot_core_1.deregisterToConnector)(this, () => { (0, opcua_iiot_core_1.resetIiotNode)(this); done(); }); }); } RED.nodes.registerType('OPCUA-IIoT-Crawler', OPCUAIIoTCrawler); }; //# sourceMappingURL=opcua-iiot-crawler.js.map