# Conflicts: # index.js # src/configs/index.js # src/configs/machineGroupControl.json # src/helper/assetUtils.js # src/helper/childRegistrationUtils.js # src/helper/configUtils.js # src/helper/logger.js # src/helper/menuUtils.js # src/helper/menuUtils_DEPRECATED.js # src/helper/outputUtils.js # src/helper/validationUtils.js # src/measurements/Measurement.js # src/measurements/MeasurementContainer.js # src/measurements/examples.js # src/outliers/outlierDetection.js
117 lines
3.4 KiB
JavaScript
117 lines
3.4 KiB
JavaScript
const { getFormatter } = require('./formatters');
|
|
|
|
//this class will handle the output events for the node red node
|
|
class OutputUtils {
|
|
constructor() {
|
|
this.output = {};
|
|
}
|
|
|
|
checkForChanges(output, format) {
|
|
if (!output || typeof output !== 'object') {
|
|
return {};
|
|
}
|
|
this.output[format] = this.output[format] || {};
|
|
const changedFields = {};
|
|
for (const key in output) {
|
|
if (Object.prototype.hasOwnProperty.call(output, key) && output[key] !== this.output[format][key]) {
|
|
let value = output[key];
|
|
// For fields: if the value is an object (and not a Date), stringify it.
|
|
if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
|
|
changedFields[key] = JSON.stringify(value);
|
|
} else {
|
|
changedFields[key] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Update the saved output state.
|
|
this.output[format] = { ...this.output[format], ...changedFields };
|
|
|
|
return changedFields;
|
|
}
|
|
|
|
formatMsg(output, config, format) {
|
|
let msg = {};
|
|
|
|
// Compare output with last output and only include changed values
|
|
const changedFields = this.checkForChanges(output,format);
|
|
|
|
if (Object.keys(changedFields).length > 0) {
|
|
const measurement = config.general.name;
|
|
const flatTags = this.flattenTags(this.extractRelevantConfig(config));
|
|
const formatterName = this.resolveFormatterName(config, format);
|
|
const formatter = getFormatter(formatterName);
|
|
const payload = formatter.format(measurement, {
|
|
fields: changedFields,
|
|
tags: flatTags,
|
|
config,
|
|
channel: format,
|
|
});
|
|
msg = this.wrapMessage(measurement, payload);
|
|
return msg;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
resolveFormatterName(config, channel) {
|
|
const outputConfig = config.output || {};
|
|
if (channel === 'process') {
|
|
return outputConfig.process || 'process';
|
|
}
|
|
if (channel === 'influxdb') {
|
|
return outputConfig.dbase || 'influxdb';
|
|
}
|
|
return outputConfig[channel] || channel;
|
|
}
|
|
|
|
wrapMessage(measurement, payload) {
|
|
return {
|
|
topic: measurement,
|
|
payload,
|
|
};
|
|
}
|
|
|
|
flattenTags(obj) {
|
|
const result = {};
|
|
for (const key in obj) {
|
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
const value = obj[key];
|
|
if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
|
|
// Recursively flatten the nested object.
|
|
const flatChild = this.flattenTags(value);
|
|
for (const childKey in flatChild) {
|
|
if (Object.prototype.hasOwnProperty.call(flatChild, childKey)) {
|
|
result[`${key}_${childKey}`] = String(flatChild[childKey]);
|
|
}
|
|
}
|
|
} else {
|
|
// InfluxDB tags must be strings.
|
|
result[key] = String(value);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
extractRelevantConfig(config) {
|
|
|
|
return {
|
|
// general properties
|
|
id: config.general?.id,
|
|
// functionality properties
|
|
softwareType: config.functionality?.softwareType,
|
|
role: config.functionality?.role,
|
|
// asset properties (exclude machineCurve)
|
|
uuid: config.asset?.uuid,
|
|
tagcode: config.asset?.tagcode,
|
|
geoLocation: config.asset?.geoLocation,
|
|
category: config.asset?.category,
|
|
type: config.asset?.type,
|
|
model: config.asset?.model,
|
|
unit: config.general?.unit,
|
|
};
|
|
}
|
|
}
|
|
|
|
module.exports = OutputUtils;
|