UNPKG

node-red-contrib-iiot-opcua

Version:

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

329 lines (326 loc) 14.5 kB
/* The BSD 3-Clause License Copyright 2022 - DATATRONiQ GmbH (https://datatroniq.com) Copyright (c) 2018-2022 Klaus Landsdorf (http://node-red.plus/) All rights reserved. node-red-contrib-iiot-opcua */ 'use strict'; 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_filter_1 = __importDefault(require("./core/opcua-iiot-core-filter")); const opcua_iiot_core_1 = require("./core/opcua-iiot-core"); /** * OPC UA node representation for Node-RED OPC UA IIoT nodes. * * @param RED */ module.exports = (RED) => { // SOURCE-MAP-REQUIRED const _ = require('underscore'); function OPCUAIIoTResultFilter(config) { RED.nodes.createNode(this, config); this.nodeId = config.nodeId; this.datatype = config.datatype; this.fixedValue = config.fixedValue; this.fixPoint = parseInt(config.fixPoint) | 2; this.withPrecision = config.withPrecision; this.precision = parseInt(config.precision) | 2; this.entry = config.entry || 1; this.justValue = config.justValue; this.withValueCheck = config.withValueCheck; this.minvalue = config.minvalue; this.maxvalue = config.maxvalue; this.defaultvalue = config.defaultvalue; this.topic = config.topic; this.name = config.name; this.showErrors = config.showErrors; let self = this; self.iiot = {}; this.status({ fill: 'blue', shape: 'ring', text: 'new' }); const isNodeIdNotToFindInAddressSpaceItems = function (msg) { if (msg.payload.addressSpaceItems) { let filteredNodeIds = _.filter(msg.payload.addressSpaceItems, function (entry) { return entry.nodeId === self.nodeId; }); return filteredNodeIds.length < 1; } else { return true; } }; const messageIsToFilter = function (msg) { return isNodeIdNotToFindInAddressSpaceItems(msg); }; this.on('input', (msg) => { if (!msg.hasOwnProperty('payload') || msg.payload === null || msg.payload === void 0) { // values with false has to be true opcua_iiot_core_filter_1.default.internalDebugLog('filtering message without payload'); return; } /* if (messageIsToFilter(msg)) { coreFilter.internalDebugLog('filtering message on filter') return } */ const payload = msg.payload; const filtered = filterByType(payload); const value = self.justValue // if justValue, return the filtered value of the input message // Spread operator placement should handle all formats of filtered objects ? filterResult(Object.assign(Object.assign({ value: filtered }, filtered), { nodetype: payload.nodetype })) // otherwise return the value field of the payload // The field considered 'value' is different for crawler and browsers : (filtered.value || filtered.crawlerResults || filtered.browserResults); const convertedValue = (this.fixedValue || this.withPrecision) ? convertAllResults(payload, value) : value; const { msg: msgKey } = payload, restPayload = __rest(payload, ["msg"]); const outputPayload = Object.assign(Object.assign(Object.assign(Object.assign({}, restPayload), { filtertype: "filter", justValue: self.justValue, nodeId: self.nodeId }), filtered), { value: convertedValue.length === 1 ? convertedValue[0] : convertedValue, filter: true }); const outputMessage = { payload: outputPayload, _msgid: msg._msgid, topic: self.topic || msg.topic }; this.send(outputMessage); }); const filterByType = (payload) => { let result = null; switch (payload.nodetype) { case 'read': result = filterByReadType(payload); break; case 'write': result = filterByWriteType(payload); break; case 'listen': result = filterByListenType(payload); break; case 'browse': result = filterByBrowserType(payload); break; case 'crawl': result = filterByCrawlerType(payload); break; default: opcua_iiot_core_filter_1.default.internalDebugLog('unknown node type injected to filter for ' + payload.nodetype); if (self.showErrors) { this.error(new Error('unknown node type injected to filter for ' + payload.nodetype), { payload: payload }); } } return result; }; const convertAllResults = (payload, result) => { if (!Array.isArray(result)) { return convertResult(payload, result); } else { return result.map((item) => { if ('value' in item) { return convertResult(payload, item.value || item); } else { return item; } }); } }; const convertResult = (payload, result) => { if (result.value) result = result.value; try { let convertedResult = null; if (self.fixPoint >= 0 && self.fixedValue) { convertedResult = Number.parseFloat(result).toFixed(self.fixPoint); convertedResult = parseFloat(convertedResult); } if (self.precision >= 0 && self.withPrecision) { convertedResult = Number.parseFloat(result).toPrecision(self.precision); convertedResult = parseFloat(convertedResult); } if (convertedResult === null) { convertedResult = result; } if (self.withValueCheck && typeof convertedResult === "number") { if (convertedResult < self.minvalue || convertedResult > self.maxvalue) { convertedResult = self.defaultvalue; } } return convertedResult; } catch (err) { opcua_iiot_core_filter_1.default.internalDebugLog('result converting error ' + err.message); if (self.showErrors) { this.error(err, { payload }); } return result; } }; const convertResultValue = (payload) => { let result = payload.value; if (result === null || result === void 0) { opcua_iiot_core_filter_1.default.internalDebugLog('result null or undefined'); if (self.showErrors) { this.error(new Error('converted result null or undefined'), { payload }); } return result; } if (result.hasOwnProperty('value')) { result = result.value; } if (!self.datatype) { opcua_iiot_core_filter_1.default.internalDebugLog('data type unknown - set the data type inside the result filter node'); return result; } result = convertDataType(result); if (result === null || result === void 0) { opcua_iiot_core_filter_1.default.internalDebugLog('data type result null or undefined'); if (self.showErrors) { this.error(new Error('converted by data type result null or undefined'), { payload }); } } else { result = convertResult(payload, result); } return result; }; const filterResult = function (payload) { if (payload.nodetype === 'read' || payload.nodetype === 'listen') { return convertResultValue(payload); } else if (payload.nodetype === 'browse' || payload.nodetype === 'crawl') { return payload.crawlerResults || payload.browserResults; } return payload.value; }; const extractValueFromOPCUAArrayStructure = function (payloadInput, entryIndex) { let result = null; let payload = payloadInput[entryIndex]; if (!payload) { return result; } if (payload.hasOwnProperty('value')) { if (payload.value.hasOwnProperty('value')) { result = payload.value.value; } else { result = payload.value; } } else { result = payload; } return result; }; const extractValueFromOPCUAStructure = function (payload) { let result; if (payload.hasOwnProperty('value')) { if (payload.value.hasOwnProperty('value')) { result = payload.value.value; } else { result = payload.value; } } return result; }; const filterByReadType = (payload) => { const value = payload.value; if (Array.isArray(value)) return { value: value.filter((item) => { return item.nodeId.toString().includes(this.nodeId); }) }; else { this.error('wrong payload type'); return payload; } }; const filterByWriteType = function (payload) { return { value: payload.nodesToWrite.map((item) => { while (item.value) { item = item.value; } return item; }) }; }; const filterByListenType = function (payload) { let result; if (payload && payload.hasOwnProperty('value')) { result = payload.value; } else { result = payload; } if (result && result.hasOwnProperty('value')) { result = result.value; } return result; }; const filterByBrowserType = (payload) => { const browserResults = (0, opcua_iiot_core_1.filterListByNodeId)(self.nodeId, payload.browserResults); const addressSpaceItems = (payload.addressSpaceItems && payload.addressSpaceItems.length) ? (0, opcua_iiot_core_1.filterListByNodeId)(self.nodeId, payload.addressSpaceItems) : []; const nodesToRead = (payload.nodesToRead && payload.nodesToRead.length) ? (0, opcua_iiot_core_1.filterListEntryByNodeId)(self.nodeId, payload.nodesToRead) : []; const nodesToReadCount = (payload.nodesToRead && payload.nodesToRead.length) ? nodesToRead.length : 0; const addressItemsToRead = (payload.addressItemsToRead && payload.addressItemsToRead.length) ? (0, opcua_iiot_core_1.filterListByNodeId)(self.nodeId, payload.addressItemsToRead) : []; const addressItemsToReadCount = (payload.addressItemsToRead && payload.addressItemsToRead.length) ? addressItemsToRead.length : 0; const addressItemsToBrowse = (payload.addressItemsToBrowse && payload.addressItemsToBrowse.length) ? (0, opcua_iiot_core_1.filterListByNodeId)(self.nodeId, payload.addressItemsToBrowse) : []; const addressItemsToBrowseCount = (payload.addressItemsToBrowse && payload.addressItemsToBrowse.length) ? addressItemsToBrowse.length : 0; return { browserResults, addressSpaceItems, nodesToRead, nodesToReadCount, addressItemsToRead, addressItemsToReadCount, addressItemsToBrowse, addressItemsToBrowseCount, }; }; const filterByCrawlerType = function (msg) { const crawlerResults = (0, opcua_iiot_core_1.filterListByNodeId)(self.nodeId, msg.crawlerResults); const addressItems = (msg.addressSpaceItems && msg.addressSpaceItems.length) ? (0, opcua_iiot_core_1.filterListByNodeId)(self.nodeId, msg.addressSpaceItems) : []; return { crawlerResults, addressItems, }; }; const convertDataType = function (result) { opcua_iiot_core_filter_1.default.internalDebugLog('data type convert for ' + self.nodeId); return (0, opcua_iiot_core_1.convertDataValueByDataType)(result, self.datatype); }; if (self.withValueCheck) { self.minvalue = convertDataType(self.minvalue); self.maxvalue = convertDataType(self.maxvalue); } this.status({ fill: 'green', shape: 'dot', text: 'active' }); if (process.env.TEST === "true") self.functions = { convertResultValue }; } RED.nodes.registerType('OPCUA-IIoT-Result-Filter', OPCUAIIoTResultFilter); }; //# sourceMappingURL=opcua-iiot-result-filter.js.map