Compare commits
2 Commits
2a31c7ec69
...
d44cbc978b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d44cbc978b | ||
|
|
f243761f00 |
@@ -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)} m³`
|
||||||
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)} m³`,
|
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(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
const EventEmitter = require('events');
|
const EventEmitter = require('events');
|
||||||
const {logger,configUtils,configManager,childRegistrationUtils,MeasurementContainer,coolprop,interpolation} = require('generalFunctions');
|
const {logger,configUtils,configManager,childRegistrationUtils,MeasurementContainer,coolprop,interpolation} = require('generalFunctions');
|
||||||
class PumpingStationV2 {
|
class PumpingStation {
|
||||||
constructor(config = {}) {
|
constructor(config = {}) {
|
||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
this.configManager = new configManager();
|
this.configManager = new configManager();
|
||||||
@@ -12,12 +12,14 @@ class PumpingStationV2 {
|
|||||||
|
|
||||||
this.measurements = new MeasurementContainer({ autoConvert: true });
|
this.measurements = new MeasurementContainer({ autoConvert: true });
|
||||||
this.measurements.setPreferredUnit('flow', 'm3/s');
|
this.measurements.setPreferredUnit('flow', 'm3/s');
|
||||||
|
this.measurements.setPreferredUnit('netFlowRate', 'm3/s');
|
||||||
this.measurements.setPreferredUnit('level', 'm');
|
this.measurements.setPreferredUnit('level', 'm');
|
||||||
this.measurements.setPreferredUnit('volume', 'm3');
|
this.measurements.setPreferredUnit('volume', 'm3');
|
||||||
this.childRegistrationUtils = new childRegistrationUtils(this);
|
this.childRegistrationUtils = new childRegistrationUtils(this);
|
||||||
this.machines = {};
|
this.machines = {};
|
||||||
this.stations = {};
|
this.stations = {};
|
||||||
|
|
||||||
|
|
||||||
//variants in determining what gets priority
|
//variants in determining what gets priority
|
||||||
this.flowVariants = ['measured', 'predicted'];
|
this.flowVariants = ['measured', 'predicted'];
|
||||||
this.levelVariants = ['measured', 'predicted'];
|
this.levelVariants = ['measured', 'predicted'];
|
||||||
@@ -61,6 +63,8 @@ class PumpingStationV2 {
|
|||||||
this._updatePredictedVolume(snapshot);
|
this._updatePredictedVolume(snapshot);
|
||||||
|
|
||||||
const netFlow = this._selectBestNetFlow(snapshot);
|
const netFlow = this._selectBestNetFlow(snapshot);
|
||||||
|
//write netflow in measurment container
|
||||||
|
|
||||||
const remaining = this._computeRemainingTime(snapshot, netFlow);
|
const remaining = this._computeRemainingTime(snapshot, netFlow);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -160,8 +164,8 @@ class PumpingStationV2 {
|
|||||||
.value(volume, context.timestamp, 'm3');
|
.value(volume, context.timestamp, 'm3');
|
||||||
|
|
||||||
this.measurements
|
this.measurements
|
||||||
.type('volume')
|
.type('volumePercent')
|
||||||
.variant('percent')
|
.variant('measured')
|
||||||
.position('atequipment')
|
.position('atequipment')
|
||||||
.value(percent, context.timestamp, '%');
|
.value(percent, context.timestamp, '%');
|
||||||
}
|
}
|
||||||
@@ -297,12 +301,16 @@ class PumpingStationV2 {
|
|||||||
_selectBestNetFlow(snapshot) {
|
_selectBestNetFlow(snapshot) {
|
||||||
for (const variant of this.flowVariants) {
|
for (const variant of this.flowVariants) {
|
||||||
const flow = snapshot.flows[variant];
|
const flow = snapshot.flows[variant];
|
||||||
|
|
||||||
if (!flow.inflow.exists && !flow.outflow.exists) continue;
|
if (!flow.inflow.exists && !flow.outflow.exists) continue;
|
||||||
|
|
||||||
const inflow = flow.inflow.current?.value ?? 0;
|
const inflow = flow.inflow.current?.value ?? 0;
|
||||||
const outflow = flow.outflow.current?.value ?? 0;
|
const outflow = flow.outflow.current?.value ?? 0;
|
||||||
const net = inflow - outflow; // positive => filling
|
const net = inflow - outflow; // positive => filling
|
||||||
|
|
||||||
|
this.measurements.type('netFlowRate').variant(variant).position('atequipment').value(net).unit('m3/s');
|
||||||
|
this.logger.debug(`inflow : ${inflow} - outflow : ${outflow}`);
|
||||||
|
|
||||||
return { value: net,source: variant,direction: this._deriveDirection(net) };
|
return { value: net,source: variant,direction: this._deriveDirection(net) };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,6 +424,22 @@ class PumpingStationV2 {
|
|||||||
.value(nextLevel, writeTimestamp, 'm')
|
.value(nextLevel, writeTimestamp, 'm')
|
||||||
.unit('m');
|
.unit('m');
|
||||||
|
|
||||||
|
//calc how full this is in procen using minVol vs maxVolOverflow
|
||||||
|
const percent = this.interpolate.interpolate_lin_single_point(
|
||||||
|
currentVolume,
|
||||||
|
this.basin.minVol,
|
||||||
|
this.basin.maxVolOverflow,
|
||||||
|
0,
|
||||||
|
100
|
||||||
|
);
|
||||||
|
|
||||||
|
//store this percent value
|
||||||
|
this.measurements
|
||||||
|
.type('volumePercent')
|
||||||
|
.variant('predicted')
|
||||||
|
.position('atequipment')
|
||||||
|
.value(percent);
|
||||||
|
|
||||||
this._predictedFlowState.lastTimestamp = writeTimestamp;
|
this._predictedFlowState.lastTimestamp = writeTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,7 +489,7 @@ class PumpingStationV2 {
|
|||||||
.type('volume')
|
.type('volume')
|
||||||
.variant('predicted')
|
.variant('predicted')
|
||||||
.position('atEquipment')
|
.position('atEquipment')
|
||||||
.value(maxVol)
|
.value(maxVolOverflow)
|
||||||
.unit('m3');
|
.unit('m3');
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
@@ -501,12 +525,12 @@ class PumpingStationV2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = PumpingStationV2;
|
module.exports = PumpingStation;
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
/* Example usage */
|
/* Example usage */
|
||||||
/* ------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------- */
|
||||||
|
/*
|
||||||
if (require.main === module) {
|
if (require.main === module) {
|
||||||
const Measurement = require('../../measurement/src/specificClass');
|
const Measurement = require('../../measurement/src/specificClass');
|
||||||
const RotatingMachine = require('../../rotatingMachine/src/specificClass');
|
const RotatingMachine = require('../../rotatingMachine/src/specificClass');
|
||||||
@@ -525,10 +549,10 @@ if (require.main === module) {
|
|||||||
},
|
},
|
||||||
basin: {
|
basin: {
|
||||||
volume: 43.75,
|
volume: 43.75,
|
||||||
height: 3.5,
|
height: 10,
|
||||||
heightInlet: 0.3,
|
heightInlet: 3,
|
||||||
heightOutlet: 0.2,
|
heightOutlet: 0.2,
|
||||||
heightOverflow: 3.0
|
heightOverflow: 3.2
|
||||||
},
|
},
|
||||||
hydraulics: {
|
hydraulics: {
|
||||||
refHeight: 'NAP',
|
refHeight: 'NAP',
|
||||||
@@ -630,7 +654,7 @@ if (require.main === module) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
(async function demo() {
|
(async function demo() {
|
||||||
const station = new PumpingStationV2(createPumpingStationConfig('PumpingStationDemo'));
|
const station = new PumpingStation(createPumpingStationConfig('PumpingStationDemo'));
|
||||||
const pump1 = new RotatingMachine(createMachineConfig('Pump1','downstream'), createMachineStateConfig());
|
const pump1 = new RotatingMachine(createMachineConfig('Pump1','downstream'), createMachineStateConfig());
|
||||||
const pump2 = new RotatingMachine(createMachineConfig('Pump2','upstream'), createMachineStateConfig());
|
const pump2 = new RotatingMachine(createMachineConfig('Pump2','upstream'), createMachineStateConfig());
|
||||||
|
|
||||||
@@ -638,20 +662,19 @@ if (require.main === module) {
|
|||||||
const inflowSensor = new Measurement(createFlowMeasurementConfig('InfluentFlow', 'in'));
|
const inflowSensor = new Measurement(createFlowMeasurementConfig('InfluentFlow', 'in'));
|
||||||
const outflowSensor = new Measurement(createFlowMeasurementConfig('PumpDischargeFlow', 'out'));
|
const outflowSensor = new Measurement(createFlowMeasurementConfig('PumpDischargeFlow', 'out'));
|
||||||
|
|
||||||
/*
|
//station.childRegistrationUtils.registerChild(levelSensor, levelSensor.config.functionality.softwareType);
|
||||||
station.childRegistrationUtils.registerChild(levelSensor, levelSensor.config.functionality.softwareType);
|
//station.childRegistrationUtils.registerChild(inflowSensor, inflowSensor.config.functionality.softwareType);
|
||||||
station.childRegistrationUtils.registerChild(inflowSensor, inflowSensor.config.functionality.softwareType);
|
//station.childRegistrationUtils.registerChild(outflowSensor, outflowSensor.config.functionality.softwareType);
|
||||||
station.childRegistrationUtils.registerChild(outflowSensor, outflowSensor.config.functionality.softwareType);
|
|
||||||
*/
|
|
||||||
station.childRegistrationUtils.registerChild(pump1, 'machine');
|
station.childRegistrationUtils.registerChild(pump1, 'machine');
|
||||||
station.childRegistrationUtils.registerChild(pump2, 'machine');
|
station.childRegistrationUtils.registerChild(pump2, 'machine');
|
||||||
|
|
||||||
// Seed initial measurements
|
// Seed initial measurements
|
||||||
/*
|
|
||||||
seedSample(levelSensor, 'level', 1.8, 'm');
|
//seedSample(levelSensor, 'level', 1.8, 'm');
|
||||||
seedSample(inflowSensor, 'flow', 0.35, 'm3/s');
|
//seedSample(inflowSensor, 'flow', 0.35, 'm3/s');
|
||||||
seedSample(outflowSensor, 'flow', 0.20, 'm3/s');
|
//seedSample(outflowSensor, 'flow', 0.20, 'm3/s');
|
||||||
*/
|
|
||||||
setInterval(
|
setInterval(
|
||||||
() => station.tick(), 1000);
|
() => station.tick(), 1000);
|
||||||
|
|
||||||
@@ -672,3 +695,4 @@ if (require.main === module) {
|
|||||||
console.error('Demo failed:', err);
|
console.error('Demo failed:', err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
//*/
|
||||||
|
|||||||
Reference in New Issue
Block a user