module.exports = function (RED) { function machineGroupControl(config) { //create node RED.nodes.createNode(this, config); //call this => node so whenver you want to call a node function type node and the function behind it var node = this; //fetch machine object from machine.js const MachineGroup = require('./dependencies/machineGroup/machineGroup'); const OutputUtils = require("../generalFunctions/helper/outputUtils"); const mgConfig = config = { general: { name: config.name, id : config.id, logging: { enabled: config.loggingEnabled, logLevel: config.logLevel, } }, }; //make new class on creation to work with. const mg = new MachineGroup(mgConfig); // put mg on node memory as source node.source = mg; //load output utils const output = new OutputUtils(); //update node status function updateNodeStatus(mg) { const mode = mg.mode; const scaling = mg.scaling; const totalFlow = Math.round(mg.measurements.type("flow").variant("predicted").position("downstream").getCurrentValue() * 1) / 1; const totalPower = Math.round(mg.measurements.type("power").variant("predicted").position("upstream").getCurrentValue() * 1) / 1; // Calculate total capacity based on available machines const availableMachines = Object.values(mg.machines).filter(machine => { const state = machine.state.getCurrentState(); const mode = machine.currentMode; return !(state === "off" || state === "maintenance" || mode === "maintenance"); }); const totalCapacity = Math.round(mg.dynamicTotals.flow.max * 1) / 1; // Determine overall status based on available machines const status = availableMachines.length > 0 ? `${availableMachines.length} machines` : "No machines"; let scalingSymbol = ''; switch (scaling.toLowerCase()) { case 'absolute': scalingSymbol = 'Ⓐ'; // Clear symbol for Absolute mode break; case 'normalized': scalingSymbol = 'Ⓝ'; // Clear symbol for Normalized mode break; default: scalingSymbol = mode; break; } // Generate status text in a single line const text = ` ${mode} | ${scalingSymbol}: 💨=${totalFlow}/${totalCapacity} | ⚡=${totalPower} | ${status}`; return { fill: availableMachines.length > 0 ? "green" : "red", shape: "dot", text }; } //never ending functions function tick(){ //source.tick(); const status = updateNodeStatus(mg); node.status(status); //get output const classOutput = mg.getOutput(); const dbOutput = output.formatMsg(classOutput, mg.config, "influxdb"); const pOutput = output.formatMsg(classOutput, mg.config, "process"); //only send output on values that changed let msgs = []; msgs[0] = pOutput; msgs[1] = dbOutput; node.send(msgs); } // register child on first output this timeout is needed because of node - red stuff setTimeout( () => { /*---execute code on first start----*/ let msgs = []; msgs[2] = { topic : "registerChild" , payload: node.id, positionVsParent: "upstream" }; msgs[3] = { topic : "registerChild" , payload: node.id, positionVsParent: "downstream" }; //send msg this.send(msgs); }, 100 ); //declare refresh interval internal node setTimeout( () => { /*---execute code on first start----*/ this.interval_id = setInterval(function(){ tick() },1000) }, 1000 ); //-------------------------------------------------------------------->>what to do on input node.on("input", async function (msg,send,done) { if(msg.topic == 'registerChild'){ const childId = msg.payload; const childObj = RED.nodes.getNode(childId); mg.childRegistrationUtils.registerChild(childObj.source,msg.positionVsParent); } if(msg.topic == 'setMode'){ const mode = msg.payload; const source = "parent"; mg.setMode(source,mode); } if(msg.topic == 'setScaling'){ const scaling = msg.payload; mg.setScaling(scaling); } if(msg.topic == 'Qd'){ const Qd = parseFloat(msg.payload); const source = "parent"; if (isNaN(Qd)) { return mg.logger.error(`Invalid demand value: ${Qd}`); }; try{ await mg.handleInput(source,Qd); msg.topic = mg.config.general.name; msg.payload = "done"; send(msg); }catch(e){ console.log(e); } } // tidy up any async code here - shutdown connections and so on. node.on('close', function() { clearTimeout(this.interval_id); }); }); } RED.nodes.registerType("machineGroupControl", machineGroupControl); };