Compare commits

12 Commits

Author SHA1 Message Date
znetsixe
0a6c7ee2e1 Further bug fixes and optimized level control for groups and machines alike 2025-11-13 19:37:41 +01:00
znetsixe
4cc529b1c2 Fixes next idle machine for level control 2025-11-12 17:37:09 +01:00
znetsixe
fbfcec4b47 Added simpel case for level control 2025-11-10 16:20:23 +01:00
znetsixe
43eb97407f added safeguarding when vol gets too low for machines, 2025-11-07 15:07:56 +01:00
znetsixe
9e4b149b64 fixed multiple children being able to pull and push to pumpingstation 2025-11-06 16:46:54 +01:00
znetsixe
1848486f1c bug fixes output formatting 2025-11-06 11:19:20 +01:00
znetsixe
d44cbc978b updates visual 2025-11-03 09:17:22 +01:00
znetsixe
f243761f00 Updated node status 2025-11-03 07:42:51 +01:00
znetsixe
2a31c7ec69 working pumpingstation with machines 2025-10-28 17:04:26 +01:00
znetsixe
69f68adffe testing codex 2025-10-27 19:55:48 +01:00
znetsixe
5a1eff37d7 Need to remove wobble on level only 2025-10-27 17:45:48 +01:00
znetsixe
e8f9207a92 some major design choises updated 2025-10-27 16:39:06 +01:00
2 changed files with 1072 additions and 691 deletions

View File

@@ -101,65 +101,60 @@ class nodeClass {
_updateNodeStatus() { _updateNodeStatus() {
const ps = this.source; const ps = this.source;
try {
// --- Basin & measurements ------------------------------------------------- const pickVariant = (type, prefer = ['measured', 'predicted'], position = 'atEquipment', unit) => {
for (const variant of prefer) {
const chain = ps.measurements.type(type).variant(variant).position(position);
const value = unit ? chain.getCurrentValue(unit) : chain.getCurrentValue();
if (value != null) return { value, variant };
}
return { value: null, variant: null };
};
const vol = pickVariant('volume', ['measured', 'predicted'], 'atEquipment', 'm3');
const volPercent = pickVariant('volumePercent', ['measured','predicted'], 'atEquipment'); // already unitless
const level = pickVariant('level', ['measured', 'predicted'], 'atEquipment', 'm');
const netFlow = pickVariant('netFlowRate', ['measured', 'predicted'], 'atEquipment', 'm3/h');
const maxVolBeforeOverflow = ps.basin?.maxVolOverflow ?? ps.basin?.maxVol ?? 0; const maxVolBeforeOverflow = ps.basin?.maxVolOverflow ?? ps.basin?.maxVol ?? 0;
const volumeMeasurement = ps.measurements.type("volume").variant("measured").position("atEquipment"); const currentVolume = vol.value ?? 0;
const currentVolume = volumeMeasurement.getCurrentValue("m3") ?? 0; const currentvolPercent = volPercent.value ?? 0;
const netFlowMeasurement = ps.measurements.type("netFlowRate").variant("predicted").position("atEquipment"); const netFlowM3h = netFlow.value ?? 0;
const netFlowM3s = netFlowMeasurement?.getCurrentValue("m3/s") ?? 0;
const netFlowM3h = netFlowM3s * 3600;
const percentFull = ps.measurements.type("volume").variant("procent").position("atEquipment").getCurrentValue() ?? 0;
// --- State information ---------------------------------------------------- const direction = ps.state?.direction ?? 'unknown';
const direction = ps.state?.direction || "unknown";
const secondsRemaining = ps.state?.seconds ?? null; const secondsRemaining = ps.state?.seconds ?? null;
const timeRemainingMinutes = secondsRemaining != null ? Math.round(secondsRemaining / 60) : null;
const timeRemaining = secondsRemaining ? `${Math.round(secondsRemaining / 60)}` : 0 + " min"; const badgePieces = [];
badgePieces.push(`${currentvolPercent.toFixed(1)}% `);
// --- Icon / colour selection --------------------------------------------- badgePieces.push(
let symbol = "❔"; `V=${currentVolume.toFixed(2)} / ${maxVolBeforeOverflow.toFixed(2)}`
let fill = "grey"; );
badgePieces.push(`net: ${netFlowM3h.toFixed(0)} m³/h`);
switch (direction) { if (timeRemainingMinutes != null) {
case "filling": badgePieces.push(`t≈${timeRemainingMinutes} min)`);
symbol = "⬆️";
fill = "blue";
break;
case "draining":
symbol = "⬇️";
fill = "orange";
break;
case "stable":
symbol = "⏸️";
fill = "green";
break;
default:
symbol = "❔";
fill = "grey";
break;
} }
// --- Status text ---------------------------------------------------------- const { symbol, fill } = (() => {
const textParts = [ switch (direction) {
`${symbol} ${percentFull.toFixed(1)}%`, case 'filling': return { symbol: '⬆️', fill: 'blue' };
`V=${currentVolume.toFixed(2)} / ${maxVolBeforeOverflow.toFixed(2)}`, case 'draining': return { symbol: '⬇️', fill: 'orange' };
`net=${netFlowM3h.toFixed(1)} m³/h`, case 'steady': return { symbol: '⏸️', fill: 'green' };
`t≈${timeRemaining}` default: return { symbol: '❔', fill: 'grey' };
]; }
})();
badgePieces[0] = `${symbol} ${badgePieces[0]}`;
return { return {
fill, fill,
shape: "dot", shape: 'dot',
text: textParts.join(" | ") text: badgePieces.join(' | ')
}; };
} catch (error) {
this.node.error("Error in updateNodeStatus: " + error.message);
return { fill: "red", shape: "ring", text: "Status Error" };
}
} }
// any time based functions here // any time based functions here
_startTickLoop() { _startTickLoop() {
setTimeout(() => { setTimeout(() => {
@@ -182,8 +177,8 @@ class nodeClass {
//pumping station needs time based ticks to recalc level when predicted //pumping station needs time based ticks to recalc level when predicted
this.source.tick(); this.source.tick();
const raw = this.source.getOutput(); const raw = this.source.getOutput();
const processMsg = this._output.formatMsg(raw, this.config, 'process'); const processMsg = this._output.formatMsg(raw, this.source.config, 'process');
const influxMsg = this._output.formatMsg(raw, this.config, 'influxdb'); const influxMsg = this._output.formatMsg(raw, this.source.config, 'influxdb');
// Send only updated outputs on ports 0 & 1 // Send only updated outputs on ports 0 & 1
this.node.send([processMsg, influxMsg]); this.node.send([processMsg, influxMsg]);
@@ -209,6 +204,14 @@ class nodeClass {
const childObj = this.RED.nodes.getNode(childId); const childObj = this.RED.nodes.getNode(childId);
this.source.childRegistrationUtils.registerChild(childObj.source ,msg.positionVsParent); this.source.childRegistrationUtils.registerChild(childObj.source ,msg.positionVsParent);
break; break;
case 'calibratePredictedVolume':
const calibratedVolume = this.source.measurements
.type('volume')
.variant('measured')
.position('atequipment')
.getCurrentValue('m3');
this.source.calibratePredictedVolume(calibratedVolume);
break;
} }
done(); done();
}); });

File diff suppressed because it is too large Load Diff