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;