From 4ae6beba3767ae39b8e0fda306c151edec36b768 Mon Sep 17 00:00:00 2001 From: znetsixe <73483679+znetsixe@users.noreply.github.com> Date: Fri, 31 Oct 2025 18:35:40 +0100 Subject: [PATCH 1/3] updated measurement node to match selected units from user and convert it properly --- src/nodeClass.js | 4 ++-- src/specificClass.js | 33 ++++++++++++++++++++++++++++++--- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/nodeClass.js b/src/nodeClass.js index 6d20326..7fc2acd 100644 --- a/src/nodeClass.js +++ b/src/nodeClass.js @@ -114,8 +114,8 @@ class nodeClass { try { const mode = m.currentMode; const state = m.state.getCurrentState(); - const flow = Math.round(m.measurements.type("flow").variant("predicted").position('downstream').getCurrentValue()); - const power = Math.round(m.measurements.type("power").variant("predicted").position('upstream').getCurrentValue()); + const flow = Math.round(m.measurements.type("flow").variant("predicted").position('downstream').getCurrentValue('m3/h')); + const power = Math.round(m.measurements.type("power").variant("predicted").position('atequipment').getCurrentValue('kW')); let symbolState; switch(state){ case "off": diff --git a/src/specificClass.js b/src/specificClass.js index c5e1a74..999443c 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -48,7 +48,17 @@ class Machine { this.errorMetrics = new nrmse(errorMetricsConfig, this.logger); // Initialize measurements - this.measurements = new MeasurementContainer(); + this.measurements = new MeasurementContainer({ + autoConvert: true, + windowSize: 50, + defaultUnits: { + pressure: 'mbar', + flow: this.config.general.unit, + power: 'kW', + temperature: 'C' + } + }); + this.interpolation = new interpolation(); this.flowDrift = null; @@ -68,11 +78,25 @@ class Machine { this.updatePosition(); }); + //When state changes look if we need to do other updates + this.state.emitter.on("stateChange", (newState) => { + this.logger.debug(`State change detected: ${newState}`); + this._updateState(); + }); + this.child = {}; // object to hold child information so we know on what to subscribe this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility } + _updateState(){ + const isOperational = this._isOperationalState(); + if(!isOperational){ + //overrule the last prediction this should be 0 now + this.measurements.type("flow").variant("predicted").position("downstream").value(0); + } + } + /*------------------- Register child events -------------------*/ registerChild(child, softwareType) { this.logger.debug('Setting up child event for softwaretype ' + softwareType); @@ -501,13 +525,14 @@ _callMeasurementHandler(measurementType, value, position, context) { // Update predicted flow if you have prediction capability if (this.predictFlow) { - this.measurements.type("flow").variant("predicted").position("atEquipment").value(this.predictFlow.outputY || 0); + this.measurements.type("flow").variant("predicted").position("downstream").value(this.predictFlow.outputY || 0); } } // Helper method for operational state check _isOperationalState() { const state = this.state.getCurrentState(); + this.logger.debug(`Checking operational state ${this.state.getCurrentState()} ? ${["operational", "accelerating", "decelerating"].includes(state)}`); return ["operational", "accelerating", "decelerating"].includes(state); } @@ -531,6 +556,9 @@ _callMeasurementHandler(measurementType, value, position, context) { this.calcDistanceBEP(efficiency,cog,minEfficiency); } + + + } calcDistanceFromPeak(currentEfficiency,peakEfficiency){ @@ -561,7 +589,6 @@ _callMeasurementHandler(measurementType, value, position, context) { }; } - // Calculate the center of gravity for current pressure calcCog() { From 51f966cfb9375a9f55b7690ee7e3e8f8f67678a2 Mon Sep 17 00:00:00 2001 From: znetsixe <73483679+znetsixe@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:47:39 +0100 Subject: [PATCH 2/3] Added sanitizing of input for handleInput for rotating machine --- src/specificClass.js | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index 999443c..2409c4b 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -199,6 +199,11 @@ _callMeasurementHandler(measurementType, value, position, context) { async handleInput(source, action, parameter) { + //sanitize input + if( typeof action !== 'string'){this.logger.error(`Action must be string`); return;} + //convert to lower case to avoid to many mistakes in commands + action = action.toLowerCase(); + if (!this.isValidSourceForMode(source, this.currentMode)) { let warningTxt = `Source '${source}' is not valid for mode '${this.currentMode}'.`; this.logger.warn(warningTxt); @@ -209,23 +214,24 @@ _callMeasurementHandler(measurementType, value, position, context) { try { switch (action) { - case "execSequence": + + case "execsequence": return await this.executeSequence(parameter); - case "execMovement": + case "execmovement": return await this.setpoint(parameter); - case "flowMovement": + case "flowmovement": // Calculate the control value for a desired flow const pos = this.calcCtrl(parameter); // Move to the desired setpoint return await this.setpoint(pos); - case "emergencyStop": + case "emergencystop": this.logger.warn(`Emergency stop activated by '${source}'.`); return await this.executeSequence("emergencyStop"); - case "statusCheck": + case "statuscheck": this.logger.info(`Status Check: Mode = '${this.currentMode}', Source = '${source}'.`); break; @@ -704,23 +710,12 @@ _callMeasurementHandler(measurementType, value, position, context) { // Improved output object generation const output = {}; - //build the output object - this.measurements.getTypes().forEach(type => { - this.measurements.getVariants(type).forEach(variant => { - const downstreamVal = this.measurements.type(type).variant(variant).position("downstream").getCurrentValue(); - const upstreamVal = this.measurements.type(type).variant(variant).position("upstream").getCurrentValue(); - - if (downstreamVal != null) { - output[`downstream_${variant}_${type}`] = downstreamVal; - } - if (upstreamVal != null) { - output[`upstream_${variant}_${type}`] = upstreamVal; - } - if (downstreamVal != null && upstreamVal != null) { - const diffVal = this.measurements.type(type).variant(variant).difference().value; - output[`differential_${variant}_${type}`] = diffVal; - } + Object.entries(this.measurements.measurements).forEach(([type, variants]) => { + Object.entries(variants).forEach(([variant, positions]) => { + Object.entries(positions).forEach(([position, measurement]) => { + output[`${type}.${variant}.${position}`] = measurement.getCurrentValue(); + }); }); }); @@ -733,6 +728,7 @@ _callMeasurementHandler(measurementType, value, position, context) { output["cog"] = this.cog; // flow / power efficiency output["NCog"] = this.NCog; // normalized cog output["NCogPercent"] = Math.round(this.NCog * 100 * 100) / 100 ; + output["maintenanceTime"] = this.state.getMaintenanceTimeHours(); if(this.flowDrift != null){ const flowDrift = this.flowDrift; From 4b5ec33c1d272c215ddbab7a6702338e68b3489b Mon Sep 17 00:00:00 2001 From: znetsixe <73483679+znetsixe@users.noreply.github.com> Date: Wed, 5 Nov 2025 17:15:47 +0100 Subject: [PATCH 3/3] fixed bugs for rotating machine execSequence --- src/nodeClass.js | 3 +++ src/specificClass.js | 33 ++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/nodeClass.js b/src/nodeClass.js index 7fc2acd..2b83066 100644 --- a/src/nodeClass.js +++ b/src/nodeClass.js @@ -145,6 +145,9 @@ class nodeClass { case "decelerating": symbolState = "⏪"; break; + case "maintenance": + symbolState = "🔧"; + break; } const position = m.state.getCurrentPosition(); const roundedPosition = Math.round(position * 100) / 100; diff --git a/src/specificClass.js b/src/specificClass.js index 2409c4b..b2dd199 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -189,26 +189,37 @@ _callMeasurementHandler(measurementType, value, position, context) { // -------- Mode and Input Management -------- // isValidSourceForMode(source, mode) { const allowedSourcesSet = this.config.mode.allowedSources[mode] || []; - return allowedSourcesSet.has(source); + const allowed = allowedSourcesSet.has(source); + allowed? + this.logger.debug(`source is allowed proceeding with ${source} for mode ${mode}`) : + this.logger.warn(`${source} is not allowed in mode ${mode}`); + + return allowed; } isValidActionForMode(action, mode) { const allowedActionsSet = this.config.mode.allowedActions[mode] || []; - return allowedActionsSet.has(action); + const allowed = allowedActionsSet.has(action); + allowed ? + this.logger.debug(`Action is allowed proceeding with ${action} for mode ${mode}`) : + this.logger.warn(`${action} is not allowed in mode ${mode}`); + + return allowed; } async handleInput(source, action, parameter) { + this.logger.debug("hello"); //sanitize input if( typeof action !== 'string'){this.logger.error(`Action must be string`); return;} //convert to lower case to avoid to many mistakes in commands action = action.toLowerCase(); - if (!this.isValidSourceForMode(source, this.currentMode)) { - let warningTxt = `Source '${source}' is not valid for mode '${this.currentMode}'.`; - this.logger.warn(warningTxt); - return {status : false , feedback: warningTxt}; - } + // check for validity of the request + if(!this.isValidActionForMode(action,this.currentMode)){return ;} + if (!this.isValidSourceForMode(source, this.currentMode)) {return ;} + + this.logger.debug("hello2"); this.logger.info(`Handling input from source '${source}' with action '${action}' in mode '${this.currentMode}'.`); @@ -221,6 +232,14 @@ _callMeasurementHandler(measurementType, value, position, context) { case "execmovement": return await this.setpoint(parameter); + case "entermaintenance": + + return await this.executeSequence(parameter); + + + case "exitmaintenance": + return await this.executeSequence(parameter); + case "flowmovement": // Calculate the control value for a desired flow const pos = this.calcCtrl(parameter);