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
JavaScript
/*
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