Files
monster/src/nodeClass.js
2026-03-12 16:43:29 +01:00

157 lines
4.4 KiB
JavaScript

const { outputUtils, configManager, POSITIONS } = require('generalFunctions');
const Specific = require('./specificClass');
class nodeClass {
constructor(uiConfig, RED, nodeInstance, nameOfNode) {
this.node = nodeInstance;
this.RED = RED;
this.name = nameOfNode;
this.source = null;
this._loadConfig(uiConfig);
this._setupSpecificClass();
this._bindEvents();
this._registerChild();
this._startTickLoop();
this._attachInputHandler();
this._attachCloseHandler();
}
_loadConfig(uiConfig) {
const cfgMgr = new configManager();
this.config = cfgMgr.buildConfig(this.name, uiConfig, this.node.id, {
constraints: {
samplingtime: Number(uiConfig.samplingtime) || 0,
minVolume: Number(uiConfig.minvolume ?? uiConfig.minVolume) || 5,
maxWeight: Number(uiConfig.maxweight ?? uiConfig.maxWeight) || 23,
},
});
this.config.functionality = {
...this.config.functionality,
role: 'samplingCabinet',
aquonSampleName: uiConfig.aquon_sample_name || undefined,
};
this.config.asset = {
uuid: uiConfig.uuid || null,
supplier: uiConfig.supplier || 'Unknown',
type: 'sensor',
subType: uiConfig.subType || 'pressure',
model: uiConfig.model || 'Unknown',
emptyWeightBucket: Number(uiConfig.emptyWeightBucket) || 3,
};
this._output = new outputUtils();
}
_setupSpecificClass() {
this.source = new Specific(this.config);
this.node.source = this.source;
}
_bindEvents() {}
_updateNodeStatus() {
try {
const stateText = this.source.running
? `${this.source.currentMode}: ON => ${this.source.bucketVol} | ${this.source.maxVolume}`
: `${this.source.currentMode}: OFF`;
return {
fill: this.source.running ? 'green' : 'red',
shape: 'dot',
text: stateText,
};
} catch (error) {
this.node.error(`Error in updateNodeStatus: ${error.message}`);
return { fill: 'red', shape: 'ring', text: 'Status Error' };
}
}
_registerChild() {
setTimeout(() => {
this.node.send([
null,
null,
{ topic: 'registerChild', payload: this.node.id, positionVsParent: POSITIONS.UPSTREAM },
{ topic: 'registerChild', payload: this.node.id, positionVsParent: POSITIONS.DOWNSTREAM },
]);
}, 100);
}
_startTickLoop() {
setTimeout(() => {
this._tickInterval = setInterval(() => this._tick(), 1000);
this._statusInterval = setInterval(() => {
this.node.status(this._updateNodeStatus());
}, 1000);
}, 1000);
}
_tick() {
this.source.tick();
const raw = this.source.getOutput();
const processMsg = this._output.formatMsg(raw, this.config, 'process');
const influxMsg = this._output.formatMsg(raw, this.config, 'influxdb');
this.node.send([processMsg, influxMsg, null, null]);
}
_attachInputHandler() {
this.node.on('input', (msg, _send, done) => {
try {
switch (msg.topic) {
case 'registerChild': {
const childId = msg.payload;
const childObj = this.RED.nodes.getNode(childId);
if (childObj?.source) {
this.source.childRegistrationUtils.registerChild(childObj.source, msg.positionVsParent);
}
break;
}
case 'setMode':
this.source.setMode(msg.payload);
break;
case 'start':
case 'i_start':
this.source.i_start = true;
break;
case 'i_flow':
this.source.q = Number(msg.payload) || 0;
break;
case 'aquon_monsternametijden':
this.source.monsternametijden = msg.payload;
break;
case 'rain_data':
this.source.rain_data = msg.payload;
break;
case 'model_prediction':
this.source.setModelPrediction(msg.payload);
break;
default:
this.source.logger.warn(`Unknown topic: ${msg.topic}`);
break;
}
} catch (error) {
this.node.error(`Error in input function: ${error.message}`);
this.node.status({ fill: 'red', shape: 'ring', text: 'Input Error' });
}
done();
});
}
_attachCloseHandler() {
this.node.on('close', (done) => {
clearInterval(this._tickInterval);
clearInterval(this._statusInterval);
done();
});
}
}
module.exports = nodeClass;