Compare commits

..

3 Commits

Author SHA1 Message Date
znetsixe
fa7c59fcab updates 2025-07-24 13:15:33 +02:00
znetsixe
3fc8dbefe8 bug fix 2025-07-02 17:07:19 +02:00
znetsixe
f24a5fb90b bug fixes 2025-07-02 16:00:52 +02:00
3 changed files with 52 additions and 32 deletions

View File

@@ -57,11 +57,11 @@
waitForMenuData(); waitForMenuData();
// your existing projectsettings & asset dropdown logic can remain here // your existing projectsettings & asset dropdown logic can remain here
document.getElementById("node-input-speed"), document.getElementById("node-input-speed");
document.getElementById("node-input-startup"), document.getElementById("node-input-startup");
document.getElementById("node-input-warmup"), document.getElementById("node-input-warmup");
document.getElementById("node-input-shutdown"), document.getElementById("node-input-shutdown");
document.getElementById("node-input-cooldown") document.getElementById("node-input-cooldown");
}, },
oneditsave: function() { oneditsave: function() {

View File

@@ -20,12 +20,13 @@ class nodeClass {
this.RED = RED; // This is the Node-RED runtime API, we can use this to create endpoints if needed this.RED = RED; // This is the Node-RED runtime API, we can use this to create endpoints if needed
this.name = nameOfNode; // This is the name of the node, it should match the file name and the node type in Node-RED this.name = nameOfNode; // This is the name of the node, it should match the file name and the node type in Node-RED
this.source = null; // Will hold the specific class instance this.source = null; // Will hold the specific class instance
this.config = null; // Will hold the merged configuration
// Load default & UI config // Load default & UI config
this._loadConfig(uiConfig,this.node); this._loadConfig(uiConfig,this.node);
// Instantiate core Measurement class // Instantiate core class
this._setupSpecificClass(); this._setupSpecificClass(uiConfig);
// Wire up event and lifecycle handlers // Wire up event and lifecycle handlers
this._bindEvents(); this._bindEvents();
@@ -40,8 +41,6 @@ class nodeClass {
* @param {object} uiConfig - Raw config from Node-RED UI. * @param {object} uiConfig - Raw config from Node-RED UI.
*/ */
_loadConfig(uiConfig,node) { _loadConfig(uiConfig,node) {
const cfgMgr = new configManager();
this.defaultConfig = cfgMgr.getConfig(this.name);
// Merge UI config over defaults // Merge UI config over defaults
this.config = { this.config = {
@@ -75,7 +74,7 @@ class nodeClass {
/** /**
* Instantiate the core Measurement logic and store as source. * Instantiate the core Measurement logic and store as source.
*/ */
_setupSpecificClass() { _setupSpecificClass(uiConfig) {
const machineConfig = this.config; const machineConfig = this.config;
// need extra state for this // need extra state for this
@@ -87,13 +86,13 @@ class nodeClass {
} }
}, },
movement: { movement: {
speed: Number(machineConfig.speed) speed: Number(uiConfig.speed)
}, },
time: { time: {
starting: Number(machineConfig.startup), starting: Number(uiConfig.startup),
warmingup: Number(machineConfig.warmup), warmingup: Number(uiConfig.warmup),
stopping: Number(machineConfig.shutdown), stopping: Number(uiConfig.shutdown),
coolingdown: Number(machineConfig.cooldown) coolingdown: Number(uiConfig.cooldown)
} }
}; };
@@ -108,9 +107,7 @@ class nodeClass {
* Bind events to Node-RED status updates. Using internal emitter. --> REMOVE LATER WE NEED ONLY COMPLETE CHILDS AND THEN CHECK FOR UPDATES * Bind events to Node-RED status updates. Using internal emitter. --> REMOVE LATER WE NEED ONLY COMPLETE CHILDS AND THEN CHECK FOR UPDATES
*/ */
_bindEvents() { _bindEvents() {
this.source.emitter.on('mAbs', (val) => {
this.node.status({ fill: 'green', shape: 'dot', text: `${val} ${this.config.general.unit}` });
});
} }
_updateNodeStatus() { _updateNodeStatus() {
@@ -206,7 +203,7 @@ class nodeClass {
} }
/** /**
* Start the periodic tick loop to drive the Measurement class. * Start the periodic tick loop.
*/ */
_startTickLoop() { _startTickLoop() {
setTimeout(() => { setTimeout(() => {
@@ -269,9 +266,9 @@ class nodeClass {
const { source: esSource, action: esAction } = msg.payload; const { source: esSource, action: esAction } = msg.payload;
m.handleInput(esSource, esAction); m.handleInput(esSource, esAction);
break; break;
case 'showCompleteCurve': case 'showWorkingCurves':
m.showCompleteCurve(); m.showWorkingCurves();
send({ topic : "Showing curve" , payload: m.showCompleteCurve() }); send({ topic : "Showing curve" , payload: m.showWorkingCurves() });
break; break;
case 'CoG': case 'CoG':
m.showCoG(); m.showCoG();

View File

@@ -63,6 +63,9 @@ class Machine {
this.model = machineConfig.asset.model; // Get the model from the machineConfig this.model = machineConfig.asset.model; // Get the model from the machineConfig
this.curve = this.model ? loadCurve(this.model) : null; this.curve = this.model ? loadCurve(this.model) : null;
//Init config and check if it is valid
this.config = this.configUtils.initConfig(machineConfig);
if (!this.model || !this.curve) { if (!this.model || !this.curve) {
this.logger.warning(`${!this.model ? 'Model not specified' : 'Curve not found for model ' + this.model} in machineConfig. Cannot make predictions.`); this.logger.warning(`${!this.model ? 'Model not specified' : 'Curve not found for model ' + this.model} in machineConfig. Cannot make predictions.`);
// Set prediction objects to null to prevent method calls // Set prediction objects to null to prevent method calls
@@ -73,8 +76,10 @@ class Machine {
} }
else{ else{
this.hasCurve = true; this.hasCurve = true;
this.config = this.configUtils.updateConfig(this.config, {
asset: { ...this.config.asset, machineCurve: this.curve }
});
machineConfig = { ...machineConfig, asset: { ...machineConfig.asset, machineCurve: this.curve } }; // Merge curve into machineConfig machineConfig = { ...machineConfig, asset: { ...machineConfig.asset, machineCurve: this.curve } }; // Merge curve into machineConfig
this.config = this.configUtils.initConfig(machineConfig);
this.predictFlow = new predict({ curve: this.config.asset.machineCurve.nq }); // load nq (x : ctrl , y : flow relationship) this.predictFlow = new predict({ curve: this.config.asset.machineCurve.nq }); // load nq (x : ctrl , y : flow relationship)
this.predictPower = new predict({ curve: this.config.asset.machineCurve.np }); // load np (x : ctrl , y : power relationship) this.predictPower = new predict({ curve: this.config.asset.machineCurve.np }); // load np (x : ctrl , y : power relationship)
this.predictCtrl = new predict({ curve: this.reverseCurve(this.config.asset.machineCurve.nq) }); // load reversed nq (x: flow, y: ctrl relationship) this.predictCtrl = new predict({ curve: this.reverseCurve(this.config.asset.machineCurve.nq) }); // load reversed nq (x: flow, y: ctrl relationship)
@@ -104,8 +109,6 @@ class Machine {
this.updatePosition(); this.updatePosition();
}); });
//this.calcCog();
this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility
} }
@@ -197,7 +200,7 @@ class Machine {
} }
setMode(newMode) { setMode(newMode) {
const availableModes = defaultConfig.mode.current.rules.values.map(v => v.value); const availableModes = this.defaultConfig.mode.current.rules.values.map(v => v.value);
if (!availableModes.includes(newMode)) { if (!availableModes.includes(newMode)) {
this.logger.warn(`Invalid mode '${newMode}'. Allowed modes are: ${availableModes.join(', ')}`); this.logger.warn(`Invalid mode '${newMode}'. Allowed modes are: ${availableModes.join(', ')}`);
return; return;
@@ -244,6 +247,8 @@ class Machine {
throw new Error("Invalid setpoint: Setpoint must be a non-negative number."); throw new Error("Invalid setpoint: Setpoint must be a non-negative number.");
} }
this.logger.info(`Setting setpoint to ${setpoint}. Current position: ${this.state.getCurrentPosition()}`);
// Move to the desired setpoint // Move to the desired setpoint
await this.state.moveTo(setpoint); await this.state.moveTo(setpoint);
@@ -254,7 +259,7 @@ class Machine {
// Calculate flow based on current pressure and position // Calculate flow based on current pressure and position
calcFlow(x) { calcFlow(x) {
if(!this.hasCurve) { if(this.hasCurve) {
const state = this.state.getCurrentState(); const state = this.state.getCurrentState();
if (!["operational", "accelerating", "decelerating"].includes(state)) { if (!["operational", "accelerating", "decelerating"].includes(state)) {
@@ -279,7 +284,7 @@ class Machine {
// Calculate power based on current pressure and position // Calculate power based on current pressure and position
calcPower(x) { calcPower(x) {
if(!this.hasCurve) { if(this.hasCurve) {
const state = this.state.getCurrentState(); const state = this.state.getCurrentState();
if (!["operational", "accelerating", "decelerating"].includes(state)) { if (!["operational", "accelerating", "decelerating"].includes(state)) {
this.measurements.type("power").variant("predicted").position('upstream').value(0); this.measurements.type("power").variant("predicted").position('upstream').value(0);
@@ -302,7 +307,7 @@ class Machine {
// calculate the power consumption using only flow and pressure // calculate the power consumption using only flow and pressure
inputFlowCalcPower(flow) { inputFlowCalcPower(flow) {
if(!this.hasCurve) { if(this.hasCurve) {
this.predictCtrl.currentX = flow; this.predictCtrl.currentX = flow;
const cCtrl = this.predictCtrl.y(flow); const cCtrl = this.predictCtrl.y(flow);
@@ -320,7 +325,7 @@ class Machine {
// Function to predict control value for a desired flow // Function to predict control value for a desired flow
calcCtrl(x) { calcCtrl(x) {
if(!this.hasCurve) { if(this.hasCurve) {
this.predictCtrl.currentX = x; this.predictCtrl.currentX = x;
const cCtrl = this.predictCtrl.y(x); const cCtrl = this.predictCtrl.y(x);
this.measurements.type("ctrl").variant("predicted").position('upstream').value(cCtrl); this.measurements.type("ctrl").variant("predicted").position('upstream').value(cCtrl);
@@ -407,7 +412,7 @@ class Machine {
} }
// get // get
const upstreamFlow = this.measurements.type('pressure').variant('measured').position('upstream').getCurrentValue(); const upstreamFlow = this.measurements.type('flow').variant('measured').position('upstream').getCurrentValue();
// Only upstream => might still accept it, but warn // Only upstream => might still accept it, but warn
if (upstreamFlow != null) { if (upstreamFlow != null) {
@@ -416,7 +421,7 @@ class Machine {
} }
// get // get
const downstreamFlow = this.measurements.type('pressure').variant('measured').position('downstream').getCurrentValue(); const downstreamFlow = this.measurements.type('flow').variant('measured').position('downstream').getCurrentValue();
// Only downstream => might still accept it, but warn // Only downstream => might still accept it, but warn
if (downstreamFlow != null) { if (downstreamFlow != null) {
@@ -450,6 +455,7 @@ class Machine {
if (this.state.getCurrentState() == "operational" || this.state.getCurrentState() == "accelerating" || this.state.getCurrentState() == "decelerating") { if (this.state.getCurrentState() == "operational" || this.state.getCurrentState() == "accelerating" || this.state.getCurrentState() == "decelerating") {
// put value in measurements // put value in measurements
this.measurements.type("pressure").variant("measured").position(position).value(value); this.measurements.type("pressure").variant("measured").position(position).value(value);
this.logger.debug(`Updated measured pressure: ${value} at position: ${position}`);
//when measured pressure gets updated we need some logic to fetch the relevant value which could be downstream or differential pressure //when measured pressure gets updated we need some logic to fetch the relevant value which could be downstream or differential pressure
const pressure = this.getMeasuredPressure(); const pressure = this.getMeasuredPressure();
//update the flow power and cog //update the flow power and cog
@@ -539,6 +545,23 @@ class Machine {
return distance; return distance;
} }
showWorkingCurves() {
// Show the current curves for debugging
const { powerCurve, flowCurve } = this.getCurrentCurves();
return {
powerCurve: powerCurve,
flowCurve: flowCurve,
cog: this.cog,
cogIndex: this.cogIndex,
NCog: this.NCog,
minEfficiency: this.minEfficiency,
currentEfficiencyCurve: this.currentEfficiencyCurve,
absDistFromPeak: this.absDistFromPeak,
relDistFromPeak: this.relDistFromPeak
};
}
// Calculate the center of gravity for current pressure // Calculate the center of gravity for current pressure
calcCog() { calcCog() {