before functional changes by Codex
This commit is contained in:
@@ -87,10 +87,63 @@ class Machine {
|
||||
|
||||
this.child = {}; // object to hold child information so we know on what to subscribe
|
||||
this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility
|
||||
this.virtualPressureChildIds = {
|
||||
upstream: "dashboard-sim-upstream",
|
||||
downstream: "dashboard-sim-downstream",
|
||||
};
|
||||
this.virtualPressureChildren = {};
|
||||
this.realPressureChildIds = {
|
||||
upstream: new Set(),
|
||||
downstream: new Set(),
|
||||
};
|
||||
this._initVirtualPressureChildren();
|
||||
|
||||
|
||||
}
|
||||
|
||||
_initVirtualPressureChildren() {
|
||||
const createVirtualChild = (position) => {
|
||||
const id = this.virtualPressureChildIds[position];
|
||||
const name = `dashboard-sim-${position}`;
|
||||
const measurements = new MeasurementContainer({
|
||||
autoConvert: true,
|
||||
defaultUnits: {
|
||||
pressure: "mbar",
|
||||
flow: this.config.general.unit,
|
||||
power: "kW",
|
||||
temperature: "C",
|
||||
},
|
||||
});
|
||||
|
||||
measurements.setChildId(id);
|
||||
measurements.setChildName(name);
|
||||
measurements.setParentRef(this);
|
||||
|
||||
return {
|
||||
config: {
|
||||
general: { id, name },
|
||||
functionality: {
|
||||
softwareType: "measurement",
|
||||
positionVsParent: position,
|
||||
},
|
||||
asset: {
|
||||
type: "pressure",
|
||||
unit: "mbar",
|
||||
},
|
||||
},
|
||||
measurements,
|
||||
};
|
||||
};
|
||||
|
||||
const upstreamChild = createVirtualChild("upstream");
|
||||
const downstreamChild = createVirtualChild("downstream");
|
||||
this.virtualPressureChildren.upstream = upstreamChild;
|
||||
this.virtualPressureChildren.downstream = downstreamChild;
|
||||
|
||||
this.registerChild(upstreamChild, "measurement");
|
||||
this.registerChild(downstreamChild, "measurement");
|
||||
}
|
||||
|
||||
_init(){
|
||||
//assume standard temperature is 20degrees
|
||||
this.measurements.type('temperature').variant('measured').position('atEquipment').value(15).unit('C');
|
||||
@@ -118,13 +171,19 @@ class Machine {
|
||||
|
||||
/*------------------- Register child events -------------------*/
|
||||
registerChild(child, softwareType) {
|
||||
this.logger.debug('Setting up child event for softwaretype ' + softwareType);
|
||||
const resolvedSoftwareType = softwareType || child?.config?.functionality?.softwareType || "measurement";
|
||||
this.logger.debug('Setting up child event for softwaretype ' + resolvedSoftwareType);
|
||||
|
||||
if(softwareType === "measurement"){
|
||||
const position = child.config.functionality.positionVsParent;
|
||||
const distance = child.config.functionality.distanceVsParent || 0;
|
||||
if(resolvedSoftwareType === "measurement"){
|
||||
const position = String(child.config.functionality.positionVsParent || "atEquipment").toLowerCase();
|
||||
const measurementType = child.config.asset.type;
|
||||
const key = `${measurementType}_${position}`;
|
||||
const childId = child.config?.general?.id || `${measurementType}-${position}-unknown`;
|
||||
const isVirtualPressureChild = Object.values(this.virtualPressureChildIds).includes(childId);
|
||||
|
||||
if (measurementType === "pressure" && !isVirtualPressureChild) {
|
||||
this.realPressureChildIds[position]?.add(childId);
|
||||
}
|
||||
|
||||
//rebuild to measurementype.variant no position and then switch based on values not strings or names.
|
||||
const eventName = `${measurementType}.measured.${position}`;
|
||||
|
||||
@@ -140,6 +199,7 @@ class Machine {
|
||||
.type(measurementType)
|
||||
.variant("measured")
|
||||
.position(position)
|
||||
.child(childId)
|
||||
.value(eventData.value, eventData.timestamp, eventData.unit);
|
||||
|
||||
// Call the appropriate handler
|
||||
@@ -439,14 +499,16 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const pressureDiff = this.measurements.type('pressure').variant('measured').difference();
|
||||
const upstreamPressure = this._getPreferredPressureValue("upstream");
|
||||
const downstreamPressure = this._getPreferredPressureValue("downstream");
|
||||
|
||||
// Both upstream & downstream => differential
|
||||
if (pressureDiff) {
|
||||
this.logger.debug(`Pressure differential: ${pressureDiff.value}`);
|
||||
this.predictFlow.fDimension = pressureDiff.value;
|
||||
this.predictPower.fDimension = pressureDiff.value;
|
||||
this.predictCtrl.fDimension = pressureDiff.value;
|
||||
if (upstreamPressure != null && downstreamPressure != null) {
|
||||
const pressureDiffValue = downstreamPressure - upstreamPressure;
|
||||
this.logger.debug(`Pressure differential: ${pressureDiffValue}`);
|
||||
this.predictFlow.fDimension = pressureDiffValue;
|
||||
this.predictPower.fDimension = pressureDiffValue;
|
||||
this.predictCtrl.fDimension = pressureDiffValue;
|
||||
//update the cog
|
||||
const { cog, minEfficiency } = this.calcCog();
|
||||
// calc efficiency
|
||||
@@ -454,12 +516,9 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
||||
//update the distance from peak
|
||||
this.calcDistanceBEP(efficiency,cog,minEfficiency);
|
||||
|
||||
return pressureDiff.value;
|
||||
return pressureDiffValue;
|
||||
}
|
||||
|
||||
// get downstream
|
||||
const downstreamPressure = this.measurements.type('pressure').variant('measured').position('downstream').getCurrentValue();
|
||||
|
||||
// Only downstream => use it, warn that it's partial
|
||||
if (downstreamPressure != null) {
|
||||
this.logger.warn(`Using downstream pressure only for prediction: ${downstreamPressure} This is less acurate!!`);
|
||||
@@ -475,6 +534,21 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
||||
return downstreamPressure;
|
||||
}
|
||||
|
||||
// Only upstream => use it, warn that it's partial
|
||||
if (upstreamPressure != null) {
|
||||
this.logger.warn(`Using upstream pressure only for prediction: ${upstreamPressure} This is less acurate!!`);
|
||||
this.predictFlow.fDimension = upstreamPressure;
|
||||
this.predictPower.fDimension = upstreamPressure;
|
||||
this.predictCtrl.fDimension = upstreamPressure;
|
||||
//update the cog
|
||||
const { cog, minEfficiency } = this.calcCog();
|
||||
// calc efficiency
|
||||
const efficiency = this.calcEfficiency(this.predictPower.outputY, this.predictFlow.outputY, "predicted");
|
||||
//update the distance from peak
|
||||
this.calcDistanceBEP(efficiency,cog,minEfficiency);
|
||||
return upstreamPressure;
|
||||
}
|
||||
|
||||
this.logger.error(`No valid pressure measurements available to calculate prediction using last known pressure`);
|
||||
|
||||
//set default at 0 => lowest pressure possible
|
||||
@@ -493,6 +567,80 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_getPreferredPressureValue(position) {
|
||||
const realIds = Array.from(this.realPressureChildIds[position] || []);
|
||||
for (const childId of realIds) {
|
||||
const value = this.measurements
|
||||
.type("pressure")
|
||||
.variant("measured")
|
||||
.position(position)
|
||||
.child(childId)
|
||||
.getCurrentValue();
|
||||
if (value != null) return value;
|
||||
}
|
||||
|
||||
const virtualId = this.virtualPressureChildIds[position];
|
||||
if (virtualId) {
|
||||
const simulatedValue = this.measurements
|
||||
.type("pressure")
|
||||
.variant("measured")
|
||||
.position(position)
|
||||
.child(virtualId)
|
||||
.getCurrentValue();
|
||||
if (simulatedValue != null) return simulatedValue;
|
||||
}
|
||||
|
||||
return this.measurements
|
||||
.type("pressure")
|
||||
.variant("measured")
|
||||
.position(position)
|
||||
.getCurrentValue();
|
||||
}
|
||||
|
||||
getPressureInitializationStatus() {
|
||||
const upstreamPressure = this._getPreferredPressureValue("upstream");
|
||||
const downstreamPressure = this._getPreferredPressureValue("downstream");
|
||||
|
||||
const hasUpstream = upstreamPressure != null;
|
||||
const hasDownstream = downstreamPressure != null;
|
||||
const hasDifferential = hasUpstream && hasDownstream;
|
||||
|
||||
return {
|
||||
hasUpstream,
|
||||
hasDownstream,
|
||||
hasDifferential,
|
||||
initialized: hasUpstream || hasDownstream || hasDifferential,
|
||||
source: hasDifferential ? 'differential' : hasDownstream ? 'downstream' : hasUpstream ? 'upstream' : null,
|
||||
};
|
||||
}
|
||||
|
||||
updateSimulatedMeasurement(type, position, value, context = {}) {
|
||||
const normalizedType = String(type || "").toLowerCase();
|
||||
const normalizedPosition = String(position || "atEquipment").toLowerCase();
|
||||
|
||||
if (normalizedType !== "pressure") {
|
||||
this._callMeasurementHandler(normalizedType, value, normalizedPosition, context);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.virtualPressureChildIds[normalizedPosition]) {
|
||||
this.logger.warn(`Unsupported simulated pressure position '${normalizedPosition}'`);
|
||||
return;
|
||||
}
|
||||
|
||||
const child = this.virtualPressureChildren[normalizedPosition];
|
||||
if (!child?.measurements) {
|
||||
this.logger.error(`Virtual pressure child '${normalizedPosition}' is missing`);
|
||||
return;
|
||||
}
|
||||
|
||||
child.measurements
|
||||
.type("pressure")
|
||||
.variant("measured")
|
||||
.position(normalizedPosition)
|
||||
.value(value, context.timestamp || Date.now(), context.unit || "mbar");
|
||||
}
|
||||
|
||||
handleMeasuredFlow() {
|
||||
const flowDiff = this.measurements.type('flow').variant('measured').difference();
|
||||
|
||||
@@ -588,8 +736,9 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
||||
// 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);
|
||||
const activeStates = ["operational", "warmingup", "accelerating", "decelerating"];
|
||||
this.logger.debug(`Checking operational state ${this.state.getCurrentState()} ? ${activeStates.includes(state)}`);
|
||||
return activeStates.includes(state);
|
||||
}
|
||||
|
||||
//what is the internal functions that need updating when something changes that has influence on this.
|
||||
@@ -822,150 +971,3 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
||||
|
||||
module.exports = Machine;
|
||||
|
||||
/*------------------- Testing -------------------*/
|
||||
|
||||
/*
|
||||
curve = require('C:/Users/zn375/.node-red/public/fallbackData.json');
|
||||
|
||||
//import a child
|
||||
const Child = require('../../measurement/src/specificClass');
|
||||
|
||||
console.log(`Creating child...`);
|
||||
const PT1 = new Child(config={
|
||||
general:{
|
||||
name:"PT1",
|
||||
logging:{
|
||||
enabled:true,
|
||||
logLevel:"debug",
|
||||
},
|
||||
},
|
||||
functionality:{
|
||||
softwareType:"measurement",
|
||||
positionVsParent:"upstream",
|
||||
},
|
||||
asset:{
|
||||
supplier:"Vega",
|
||||
category:"sensor",
|
||||
type:"pressure",
|
||||
model:"Vegabar 82",
|
||||
unit: "mbar"
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
const PT2 = new Child(config={
|
||||
general:{
|
||||
name:"PT2",
|
||||
logging:{
|
||||
enabled:true,
|
||||
logLevel:"debug",
|
||||
},
|
||||
},
|
||||
functionality:{
|
||||
softwareType:"measurement",
|
||||
positionVsParent:"upstream",
|
||||
},
|
||||
asset:{
|
||||
supplier:"Vega",
|
||||
category:"sensor",
|
||||
type:"pressure",
|
||||
model:"Vegabar 82",
|
||||
unit: "mbar"
|
||||
},
|
||||
});
|
||||
|
||||
//create a machine
|
||||
console.log(`Creating machine...`);
|
||||
|
||||
const machineConfig = {
|
||||
general: {
|
||||
name: "Hydrostal",
|
||||
logging: {
|
||||
enabled: true,
|
||||
logLevel: "debug",
|
||||
}
|
||||
},
|
||||
asset: {
|
||||
supplier: "Hydrostal",
|
||||
type: "pump",
|
||||
category: "centrifugal",
|
||||
model: "H05K-S03R+HGM1X-X280KO", // Ensure this field is present.
|
||||
machineCurve: curve["machineCurves"]["Hydrostal"]["H05K-S03R+HGM1X-X280KO"],
|
||||
}
|
||||
}
|
||||
|
||||
const stateConfig = {
|
||||
general: {
|
||||
logging: {
|
||||
enabled: true,
|
||||
logLevel: "debug",
|
||||
},
|
||||
},
|
||||
// Your custom config here (or leave empty for defaults)
|
||||
movement: {
|
||||
speed: 1,
|
||||
},
|
||||
time: {
|
||||
starting: 2,
|
||||
warmingup: 3,
|
||||
stopping: 2,
|
||||
coolingdown: 3,
|
||||
},
|
||||
};
|
||||
|
||||
const machine = new Machine(machineConfig, stateConfig);
|
||||
|
||||
//machine.logger.info(JSON.stringify(curve["machineCurves"]["Hydrostal"]["H05K-S03R+HGM1X-X280KO"]));
|
||||
machine.logger.info(`Registering child...`);
|
||||
machine.childRegistrationUtils.registerChild(PT1, "upstream");
|
||||
machine.childRegistrationUtils.registerChild(PT2, "downstream");
|
||||
|
||||
//feed curve to the machine class
|
||||
//machine.updateCurve(curve["machineCurves"]["Hydrostal"]["H05K-S03R+HGM1X-X280KO"]);
|
||||
|
||||
PT1.logger.info(`Enable sim...`);
|
||||
PT1.toggleSimulation();
|
||||
PT2.logger.info(`Enable sim...`);
|
||||
PT2.toggleSimulation();
|
||||
machine.getOutput();
|
||||
//manual test
|
||||
//machine.handleInput("parent", "execSequence", "startup");
|
||||
|
||||
machine.measurements.type("pressure").variant("measured").position('upstream').value(-200);
|
||||
machine.measurements.type("pressure").variant("measured").position('downstream').value(1000);
|
||||
|
||||
testingSequences();
|
||||
|
||||
const tickLoop = setInterval(changeInput,1000);
|
||||
|
||||
function changeInput(){
|
||||
PT1.logger.info(`tick...`);
|
||||
PT1.tick();
|
||||
PT2.tick();
|
||||
}
|
||||
|
||||
async function testingSequences(){
|
||||
try{
|
||||
console.log(` ********** Testing sequence startup... **********`);
|
||||
await machine.handleInput("parent", "execSequence", "startup");
|
||||
console.log(` ********** Testing movement to 15... **********`);
|
||||
await machine.handleInput("parent", "execMovement", 15);
|
||||
machine.getOutput();
|
||||
console.log(` ********** Testing sequence shutdown... **********`);
|
||||
await machine.handleInput("parent", "execSequence", "shutdown");
|
||||
console.log(`********** Testing moving to setpoint 10... while in idle **********`);
|
||||
await machine.handleInput("parent", "execMovement", 10);
|
||||
console.log(` ********** Testing sequence emergencyStop... **********`);
|
||||
await machine.handleInput("parent", "execSequence", "emergencystop");
|
||||
console.log(`********** Testing sequence boot... **********`);
|
||||
await machine.handleInput("parent", "execSequence", "boot");
|
||||
}catch(error){
|
||||
console.error(`Error: ${error}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//*/
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user