// ChildRegistrationUtils.js class ChildRegistrationUtils { constructor(mainClass) { this.mainClass = mainClass; // Reference to the main class this.logger = mainClass.logger; } async registerChild(child, positionVsParent) { this.logger.debug(`Registering child: ${child.id} with position=${positionVsParent}`); const { softwareType } = child.config.functionality; const { name, id, unit } = child.config.general; const { category = "", type = "" } = child.config.asset || {}; console.log(`Registering child: ${name}, id: ${id}, softwareType: ${softwareType}, category: ${category}, type: ${type}, positionVsParent: ${positionVsParent}` ); const emitter = child.emitter; //define position vs parent in child child.positionVsParent = positionVsParent; child.parent = this.mainClass; if (!this.mainClass.child) this.mainClass.child = {}; if (!this.mainClass.child[softwareType]) this.mainClass.child[softwareType] = {}; if (!this.mainClass.child[softwareType][category]) this.mainClass.child[softwareType][category] = {}; if (!this.mainClass.child[softwareType][category][type]) this.mainClass.child[softwareType][category][type] = {}; // Use an array to handle multiple categories if (!Array.isArray(this.mainClass.child[softwareType][category][type])) { this.mainClass.child[softwareType][category][type] = []; } // Push the new child to the array of the mainclass so we can track the childs this.mainClass.child[softwareType][category][type].push({ name, id, unit, emitter, }); //then connect the child depending on the type type etc.. this.connectChild( id, softwareType, emitter, category, child, type, positionVsParent ); } connectChild( id, softwareType, emitter, category, child, type, positionVsParent ) { this.logger.debug( `Connecting child id=${id}: desc=${softwareType}, category=${category},type=${type}, position=${positionVsParent}` ); switch (softwareType) { case "measurement": this.logger.debug( `Registering measurement child: ${id} with category=${category}` ); this.connectMeasurement(child, type, positionVsParent); break; case "machine": this.logger.debug(`Registering complete machine child: ${id}`); this.connectMachine(child); break; case "valve": this.logger.debug(`Registering complete valve child: ${id}`); this.connectValve(child); break; case "machineGroup": this.logger.debug(`Registering complete machineGroup child: ${id}`); this.connectMachineGroup(child); break; case "actuator": this.logger.debug(`Registering linear actuator child: ${id}`); this.connectActuator(child,positionVsParent); break; default: this.logger.error(`Child registration unrecognized desc: ${desc}`); this.logger.error(`Unrecognized softwareType: ${softwareType}`); } } connectMeasurement(child, type, position) { this.logger.debug( `Connecting measurement child: ${type} with position=${position}` ); // Check if type is valid if (!type) { this.logger.error(`Invalid type for measurement: ${type}`); return; } // initialize the measurement to a number - logging each step for debugging try { this.logger.debug( `Initializing measurement: ${type}, position: ${position} value: 0` ); const typeResult = this.mainClass.measurements.type(type); const variantResult = typeResult.variant("measured"); const positionResult = variantResult.position(position); positionResult.value(0); this.logger.debug( `Subscribing on mAbs event for measurement: ${type}, position: ${position}` ); // Listen for the mAbs event and update the measurement this.logger.debug( `Successfully initialized measurement: ${type}, position: ${position}` ); } catch (error) { this.logger.error(`Failed to initialize measurement: ${error.message}`); return; } //testing new emitter strategy child.measurements.emitter.on("newValue", (data) => { this.logger.warn( `Value change event received for measurement: ${type}, position: ${position}, value: ${data.value}` ); }); child.emitter.on("mAbs", (value) => { // Use the same method chaining approach that worked during initialization this.mainClass.measurements .type(type) .variant("measured") .position(position) .value(value); this.mainClass.updateMeasurement("measured", type, value, position); //this.logger.debug(`--------->>>>>>>>>Updated measurement: ${type}, value: ${value}, position: ${position}`); }); } connectMachine(machine) { if (!machine) { this.logger.error("Invalid machine provided."); return; } const machineId = Object.keys(this.mainClass.machines).length + 1; this.mainClass.machines[machineId] = machine; this.logger.info( `Setting up pressureChange listener for machine ${machineId}` ); machine.emitter.on("pressureChange", () => this.mainClass.handlePressureChange(machine) ); //update of child triggers the handler this.mainClass.handleChildChange(); this.logger.info(`Machine ${machineId} registered successfully.`); } connectValve(valve) { if (!valve) { this.logger.warn("Invalid valve provided."); return; } const valveId = Object.keys(this.mainClass.valves).length + 1; this.mainClass.valves[valveId] = valve; // Gooit valve object in de valves attribute met valve objects valve.state.emitter.on("positionChange", (data) => { //ValveGroupController abboneren op klepstand verandering this.mainClass.logger.debug(`Position change of valve detected: ${data}`); this.mainClass.calcValveFlows(); }); //bepaal nieuwe flow per valve valve.emitter.on("deltaPChange", () => { this.mainClass.logger.debug("DeltaP change of valve detected"); this.mainClass.calcMaxDeltaP(); }); //bepaal nieuwe max deltaP this.logger.info(`Valve ${valveId} registered successfully.`); } connectMachineGroup(machineGroup) { if (!machineGroup) { this.logger.warn("Invalid machineGroup provided."); return; } try { const machineGroupId = Object.keys(this.mainClass.machineGroups).length + 1; this.mainClass.machineGroups[machineGroupId] = machineGroup; } catch (error) { this.logger.warn(`Skip machinegroup connnection: ${error.message}`); } machineGroup.emitter.on("totalFlowChange", (data) => { this.mainClass.logger.debug('Total flow change of machineGroup detected'); this.mainClass.handleInput("parent", "totalFlowChange", data)}); //Geef nieuwe totale flow door aan valveGrouControl this.logger.info(`MachineGroup ${machineGroup.config.general.name} registered successfully.`); } connectActuator(actuator, positionVsParent) { if (!actuator) { this.logger.warn("Invalid actuator provided."); return; } //Special case gateGroupControl if ( this.mainClass.config.functionality.softwareType == "gateGroupControl" ) { if (Object.keys(this.mainClass.actuators).length < 2) { if (positionVsParent == "downstream") { this.mainClass.actuators[0] = actuator; } if (positionVsParent == "upstream") { this.mainClass.actuators[1] = actuator; } //define emitters actuator.state.emitter.on("positionChange", (data) => { this.mainClass.logger.debug(`Position change of actuator detected: ${data}`); this.mainClass.eventUpdate(); }); //define emitters actuator.state.emitter.on("stateChange", (data) => { this.mainClass.logger.debug(`State change of actuator detected: ${data}`); this.mainClass.eventUpdate(); }); } else { this.logger.error( "Too many actuators registered. Only two are allowed." ); } } } //wanneer hij deze ontvangt is deltaP van een van de valves veranderd (kan ook zijn niet child zijn, maar dat maakt niet uit) } module.exports = ChildRegistrationUtils;