const { Settler } = require('./specificClass.js'); class nodeClass { /** * Node-RED node class for settler. * @param {object} uiConfig - Node-RED node configuration * @param {object} RED - Node-RED runtime API * @param {object} nodeInstance - Node-RED node instance * @param {string} nameOfNode - Name of the node */ constructor(uiConfig, RED, nodeInstance, nameOfNode) { // Preserve RED reference for HTTP endpoints if needed this.node = nodeInstance; this.RED = RED; this.name = nameOfNode; this.source = null; this._loadConfig(uiConfig) this._setupClass(); this._attachInputHandler(); this._registerChild(); this._startTickLoop(); this._attachCloseHandler(); } /** * Handle node-red input messages */ _attachInputHandler() { this.node.on('input', (msg, send, done) => { switch (msg.topic) { case 'registerChild': // Register this node as a parent of the child node const childId = msg.payload; const childObj = this.RED.nodes.getNode(childId); this.source.childRegistrationUtils.registerChild(childObj.source, msg.positionVsParent); break; default: console.log("Unknown topic: " + msg.topic); } if (done) { done(); } }); } /** * Parse node configuration * @param {object} uiConfig Config set in UI in node-red */ _loadConfig(uiConfig) { this.config = { general: { name: uiConfig.name || this.name, id: this.node.id, unit: null, logging: { enabled: uiConfig.enableLog, logLevel: uiConfig.logLevel } }, functionality: { positionVsParent: uiConfig.positionVsParent || 'atEquipment', // Default to 'atEquipment' if not specified softwareType: "settler" // should be set in config manager } } } /** * Register this node as a child upstream and downstream. * Delayed to avoid Node-RED startup race conditions. */ _registerChild() { setTimeout(() => { this.node.send([ null, null, { topic: 'registerChild', payload: this.node.id, positionVsParent: this.config?.functionality?.positionVsParent || 'atEquipment' } ]); }, 100); } /** * Setup settler class */ _setupClass() { this.source = new Settler(this.config); // protect from reassignment this.node.source = this.source; } _startTickLoop() { setTimeout(() => { this._tickInterval = setInterval(() => this._tick(), 1000); }, 1000); } _tick(){ this.node.send([this.source.getEffluent, null, null]); } _attachCloseHandler() { this.node.on('close', (done) => { clearInterval(this._tickInterval); done(); }); } } module.exports = nodeClass;