forked from RnD/valveGroupControl
change to new version of code
This commit is contained in:
@@ -59,19 +59,46 @@ class nodeClass {
|
||||
|
||||
_updateNodeStatus() {
|
||||
const vg = this.source;
|
||||
const mode = vg.mode;
|
||||
const mode = vg.currentMode;
|
||||
const scaling = vg.scaling;
|
||||
const totalFlow =
|
||||
Math.round(
|
||||
vg.measurements
|
||||
.type("flow")
|
||||
.variant("measured")
|
||||
.position("downstream")
|
||||
.variant("predicted")
|
||||
.position("atEquipment")
|
||||
.getCurrentValue() * 1
|
||||
) / 1;
|
||||
const maxDeltaP =
|
||||
Math.round(
|
||||
vg.measurements
|
||||
.type("maxDeltaP")
|
||||
.variant("predicted")
|
||||
.position("delta")
|
||||
.getCurrentValue() * 1
|
||||
) / 1;
|
||||
// Verkrijg alle valves uit de geneste structuur:
|
||||
const allValves = [];
|
||||
|
||||
// Voeg alle valve objects toe aan allValves
|
||||
for (const [softwareType, typeData] of Object.entries(vg.child)) {
|
||||
// Filter alleen valves
|
||||
if (softwareType === 'valve') {
|
||||
// Loop door categories (valves, etc.)
|
||||
for (const childrenArray of Object.values(typeData)) {
|
||||
if (Array.isArray(childrenArray)) {
|
||||
allValves.push(...childrenArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate total capacity based on available valves
|
||||
const availableValves = Object.values(vg.valves).filter((valve) => {
|
||||
const availableValves = allValves.filter((valve) => {
|
||||
if (!valve || !valve.state) {
|
||||
console.log('Valve missing state:', valve);
|
||||
return false;
|
||||
}
|
||||
const state = valve.state.getCurrentState();
|
||||
const mode = valve.currentMode;
|
||||
return !(
|
||||
@@ -81,8 +108,8 @@ class nodeClass {
|
||||
);
|
||||
});
|
||||
|
||||
// const totalCapacity = Math.round(vg.dynamicTotals.flow.max * 1) / 1; ADD LATER?
|
||||
|
||||
//const totalCapacity = Math.round(vg.dynamicTotals.flow.max * 1) / 1; //ADD LATER?
|
||||
|
||||
// Determine overall status based on available valves
|
||||
const status =
|
||||
availableValves.length > 0
|
||||
@@ -91,7 +118,7 @@ class nodeClass {
|
||||
|
||||
|
||||
// Generate status text in a single line
|
||||
const text = ` ${mode} | 💨=${totalFlow} | ${status}`;
|
||||
const text = ` ${mode} | 💨=${totalFlow} | maxDeltaP = ${maxDeltaP} | ${status}`;
|
||||
|
||||
return {
|
||||
fill: availableValves.length > 0 ? "green" : "red",
|
||||
@@ -178,6 +205,7 @@ class nodeClass {
|
||||
childObj.source,
|
||||
msg.positionVsParent
|
||||
);
|
||||
//console.log('CHECK HERE NOW', childObj);
|
||||
break;
|
||||
|
||||
case 'setMode':
|
||||
|
||||
@@ -63,9 +63,7 @@ class ValveGroupControl {
|
||||
// Initialize measurements
|
||||
this.measurements = new MeasurementContainer();
|
||||
this.child = {};
|
||||
this.valves = {}; // hold child object so we can get information from its child valves
|
||||
|
||||
|
||||
// this.valves = {}; // this.child; // hold child object so we can get information from its child valves
|
||||
|
||||
// Initialize variables
|
||||
this.maxDeltaP = 0; // max deltaP is 0 als er geen child valves zijn
|
||||
@@ -74,9 +72,66 @@ class ValveGroupControl {
|
||||
|
||||
}
|
||||
|
||||
registerOnChildEvents() {}
|
||||
registerChild(child, softwareType) { //checken welke child er zijn
|
||||
console.log('=== DEBUGGING this.child ===');
|
||||
console.log('Type of this.child:', typeof this.child);
|
||||
console.log('this.child:', this.child);
|
||||
|
||||
if (Object.keys(this.child).length === 0) {
|
||||
console.log('✅ this.child is empty');
|
||||
} else {
|
||||
console.log('✅ this.child contains:', Object.keys(this.child).length, 'items');
|
||||
Object.keys(this.child).forEach(key => {
|
||||
console.log(` - Key: ${key}, Value type: ${typeof this.child[key]}`);
|
||||
});
|
||||
}
|
||||
|
||||
registerChild(child, positionVsParent) {
|
||||
this.addEventListenerForChild(child, softwareType); //subscribe to measurement changes from this specific child
|
||||
}
|
||||
|
||||
//MAAK SPECIFIEKE CHILD EVENT LISTENER - KAN EVT IN REGISTERCHILD FUNCTIE WORDEN BIJGEVOEGD
|
||||
addEventListenerForChild(child, softwareType) {
|
||||
if (child && child.emitter) {
|
||||
child.measurements.emitter.on('change', (data) => {
|
||||
const childName = child.config?.general?.name || `${softwareType}_child`;
|
||||
console.log('🔔 EVENT RECEIVED!', childName, data);
|
||||
this.logger.info(`Received change event from child ${childName}:`, data);
|
||||
this.handleChildChange(child, data);
|
||||
});
|
||||
console.log(`✅ Event listener added for ${softwareType} child`);
|
||||
} else {
|
||||
console.log(`❌ Child or emitter missing:`, {
|
||||
child: !!child,
|
||||
emitter: !!child?.measurements.emitter
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleChildChange(child, data) {
|
||||
switch(data.type) {
|
||||
case 'flow':
|
||||
if (child.source === 'mg') {
|
||||
this.logger.info("Total flow change from machineGroupControl detected by valveGroupControl");
|
||||
// als totalflow van mg veranderd, bereken dan de nieuwe valve flows
|
||||
this.calcValveFlows();
|
||||
};
|
||||
break;
|
||||
case 'pressure':
|
||||
if (data.position === 'delta') {
|
||||
this.logger.info("DeltaP change from child valve detected by valveGroupControl");
|
||||
// als deltaP van een van de childs valves verandert, bereken dan de nieuwe maxDeltaP
|
||||
this.calcMaxDeltaP();
|
||||
};
|
||||
|
||||
// Insert actions this.calcMaxDeltaP();
|
||||
this.logger.info("Kijk ik kom bij handle child change aan!")
|
||||
break;
|
||||
case 'position':
|
||||
// Handle position changes
|
||||
break;
|
||||
default:
|
||||
this.logger.debug(`Unhandled change type: ${data.type}`);
|
||||
}
|
||||
}
|
||||
|
||||
isValidSourceForMode(source, mode) {
|
||||
@@ -99,7 +154,7 @@ class ValveGroupControl {
|
||||
await this.executeSequence(parameter);
|
||||
break;
|
||||
case "totalFlowChange":
|
||||
await this.updateFlow(parameter);
|
||||
await this.updateFlow("predicted", parameter, "atEquipment");
|
||||
break;
|
||||
case "emergencyStop":
|
||||
this.logger.warn(`Emergency stop activated by '${source}'.`);
|
||||
@@ -175,12 +230,13 @@ updateFlow(variant,value,position) {
|
||||
|
||||
default:
|
||||
this.logger.warn(`Unrecognized variant '${variant}' for flow update.`);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
updateMeasurement(variant, subType, value, position) {
|
||||
this.logger.debug(`---------------------- updating ${subType} ------------------ `);
|
||||
this.logger.debug(`---------------------- updating ${subType} ------------------ NOT YET FURTHER DEFINED ------------------`);
|
||||
switch (subType) {
|
||||
case "pressure":
|
||||
// Update pressure measurement
|
||||
@@ -199,52 +255,129 @@ updateFlow(variant,value,position) {
|
||||
}
|
||||
|
||||
calcValveFlows() {
|
||||
const totalFlow = this.measurements.type("flow").variant("measured").position("atEquipment").getCurrentValue(); // get the total flow from the measurement container
|
||||
const totalFlow = this.measurements.type("flow").variant("predicted").position("atEquipment").getCurrentValue(); // get the total flow from the measurement container
|
||||
let totalKv = 0;
|
||||
|
||||
this.logger.debug(`Calculating valve flows... ${totalFlow}`); //Checkpoint
|
||||
|
||||
|
||||
|
||||
for (const key in this.valves){ //bereken sum kv values om verdeling total flow te maken
|
||||
this.logger.info('kv: ' + this.valves[key].kv); //CHECKPOINT
|
||||
if (this.valves[key].state.getCurrentPosition() != null) {
|
||||
totalKv += this.valves[key].kv;
|
||||
this.logger.info('Total Kv = ' + totalKv); //CHECKPOINT
|
||||
}
|
||||
if(totalKv === 0) {
|
||||
this.logger.warn('Total Kv is 0, cannot calculate flow distribution.');
|
||||
return; // Avoid division by zero
|
||||
// for (const key in this.child){ //bereken sum kv values om verdeling total flow te maken
|
||||
// if (this.child[key].state.getCurrentPosition() != null) {
|
||||
// totalKv += this.child[key].kv;
|
||||
// this.logger.info('Total Kv = ' + totalKv); //CHECKPOINT
|
||||
// }
|
||||
// if(totalKv === 0) {
|
||||
// this.logger.warn('Total Kv is 0, cannot calculate flow distribution.');
|
||||
// return; // Avoid division by zero
|
||||
// }
|
||||
// }
|
||||
|
||||
// Loop door de geneste this.child structuur om total kv te berekenen
|
||||
for (const [softwareType, typeData] of Object.entries(this.child)) {
|
||||
// Filter alleen op valves
|
||||
if (softwareType === 'valve') {
|
||||
// Loop door categories (valves, etc.)
|
||||
for (const [category, childrenArray] of Object.entries(typeData)) {
|
||||
if (Array.isArray(childrenArray)) {
|
||||
// Loop door alle valve objecten in deze array
|
||||
childrenArray.forEach((valve, index) => {
|
||||
if (valve && valve.state && valve.state.getCurrentPosition() != null) {
|
||||
totalKv += valve.kv;
|
||||
this.logger.info(`Adding valve ${index} Kv: ${valve.kv}, Total Kv now: ${totalKv}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key in this.valves){
|
||||
const valve = this.valves[key];
|
||||
this.logger.debug(`Calculating ratio for valve total: ${totalKv} valve.kv: ${valve.kv} ratio : ${valve.kv / totalKv}`); //Checkpoint
|
||||
const ratio = valve.kv / totalKv;
|
||||
const flow = ratio * totalFlow; // bereken flow per valve
|
||||
if (totalKv === 0) {
|
||||
this.logger.warn('Total Kv is 0, cannot calculate flow distribution.');
|
||||
return; // Avoid division by zero
|
||||
}
|
||||
|
||||
//update flow per valve in de object zelf wat daar vervolgens weer de nieuwe deltaP berekent
|
||||
valve.updateFlow("predicted", flow, "downstream");
|
||||
this.logger.info(`--> Sending updated flow to valves --> ${flow} `); //Checkpoint
|
||||
// for (const key in this.child){
|
||||
// const valve = this.child[key];
|
||||
// this.logger.debug(`Calculating ratio for valve total: ${totalKv} valve.kv: ${valve.kv} ratio : ${valve.kv / totalKv}`); //Checkpoint
|
||||
// const ratio = valve.kv / totalKv;
|
||||
// const flow = ratio * totalFlow; // bereken flow per valve
|
||||
|
||||
// //update flow per valve in de object zelf wat daar vervolgens weer de nieuwe deltaP berekent
|
||||
// valve.updateFlow("predicted", flow, "downstream");
|
||||
// this.logger.info(`--> Sending updated flow to valves --> ${flow} `); //Checkpoint
|
||||
|
||||
// }
|
||||
|
||||
// Flow verdelen over alle valves
|
||||
for (const [softwareType, typeData] of Object.entries(this.child)) {
|
||||
if (softwareType === 'valve') {
|
||||
for (const [category, childrenArray] of Object.entries(typeData)) {
|
||||
if (Array.isArray(childrenArray)) {
|
||||
childrenArray.forEach((valve, index) => {
|
||||
if (valve && valve.state && valve.state.getCurrentPosition() != null) {
|
||||
const ratio = valve.kv / totalKv;
|
||||
const flow = ratio * totalFlow;
|
||||
|
||||
valve.updateFlow("predicted", flow, "downstream");
|
||||
this.logger.info(`--> Sending updated flow to valve --> Flow: ${flow}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
calcMaxDeltaP() { // bereken de max deltaP van alle child valves
|
||||
let maxDeltaP = 0; //max deltaP is 0 als er geen child valves zijn
|
||||
this.logger.info('Calculating new max deltaP...');
|
||||
for (const key in this.valves) {
|
||||
const valve = this.valves[key]; //haal de child valve object op
|
||||
const deltaP = valve.measurements.type("pressure").variant("predicted").position("delta").getCurrentValue(); //get delta P
|
||||
this.logger.info(`Delta P for valve ${key}: ${deltaP}`);
|
||||
if (deltaP > maxDeltaP) { //als de deltaP van de child valve groter is dan de huidige maxDeltaP, dan update deze
|
||||
maxDeltaP = deltaP;
|
||||
}
|
||||
let maxDeltaP = 0;
|
||||
for (const [softwareType, typeData] of Object.entries(this.child)) {
|
||||
// Filter alleen op valves
|
||||
if (softwareType === 'valve') {
|
||||
// Loop door categories (valves, etc.)
|
||||
for (const [category, childrenArray] of Object.entries(typeData)) {
|
||||
if (Array.isArray(childrenArray)) {
|
||||
// Loop door alle valve objecten in deze array
|
||||
childrenArray.forEach((valve, index) => {
|
||||
try{
|
||||
const deltaP = valve.measurements.type("pressure").variant("predicted").position("delta").getCurrentValue();
|
||||
|
||||
if (deltaP > maxDeltaP) {
|
||||
maxDeltaP = deltaP;
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.error(`Error retrieving deltaP for valve at index ${index}: ${error}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.logger.info('Max Delta P updated to: ' + maxDeltaP);
|
||||
|
||||
this.maxDeltaP = maxDeltaP; //update de max deltaP in de measurement container van de valveGroupControl class
|
||||
this.measurements.type("maxDeltaP").variant("predicted").position("delta").value(maxDeltaP); //update de max deltaP in de measurement container van de valveGroupControl class
|
||||
this.maxDeltaP = maxDeltaP; //update de max deltaP
|
||||
this.logger.info('Max Delta P updated to: ' + maxDeltaP);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// let maxDeltaP = 0; //max deltaP is 0 als er geen child valves zijn
|
||||
// this.logger.info('Calculating new max deltaP...');
|
||||
// for (const key in this.child) {
|
||||
// const valve = this.child[key]; //haal de child valve object op
|
||||
// const deltaP = valve.measurements.type("pressure").variant("predicted").position("delta").getCurrentValue(); //get delta P
|
||||
// this.logger.info(`Delta P for valve ${key}: ${deltaP}`);
|
||||
// if (deltaP > maxDeltaP) { //als de deltaP van de child valve groter is dan de huidige maxDeltaP, dan update deze
|
||||
// maxDeltaP = deltaP;
|
||||
// }
|
||||
// }
|
||||
// this.logger.info('Max Delta P updated to: ' + maxDeltaP);
|
||||
|
||||
// this.measurements.type("maxDeltaP").variant("predicted").position("delta").value(maxDeltaP); //update de max deltaP in de measurement container van de valveGroupControl class
|
||||
// this.maxDeltaP = maxDeltaP; //update de max deltaP
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
getOutput() {
|
||||
@@ -273,7 +406,6 @@ updateFlow(variant,value,position) {
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = ValveGroupControl;
|
||||
@@ -318,23 +450,23 @@ const stateConfig = {
|
||||
}
|
||||
};
|
||||
|
||||
const valve1 = new valve(valveConfig, stateConfig);
|
||||
//const valve1 = new valve(valveConfig, stateConfig);
|
||||
//const valve2 = new valve(valveConfig, stateConfig);
|
||||
//const valve3 = new valve(valveConfig, stateConfig);
|
||||
|
||||
valve1.kv = 10; // Set Kv value for valve1
|
||||
//valve1.kv = 10; // Set Kv value for valve1
|
||||
//valve2.kv = 20; // Set Kv value for valve2
|
||||
//valve3.kv = 30; // Set Kv value for valve3
|
||||
|
||||
valve1.updateMeasurement("measured", "pressure" , 500, "downstream");
|
||||
//valve1.updateMeasurement("measured", "pressure" , 500, "downstream");
|
||||
//valve2.updateMeasurement("measured" , "pressure" , 500, "downstream");
|
||||
//valve3.updateMeasurement("measured" , "pressure" , 500, "downstream");
|
||||
|
||||
const vgc = new ValveGroupControl();
|
||||
//const vgc = new ValveGroupControl();
|
||||
|
||||
vgc.childRegistrationUtils.registerChild(valve1, "atEquipment");
|
||||
//vgc.childRegistrationUtils.registerChild(valve1, "atEquipment");
|
||||
//vgc.childRegistrationUtils.registerChild(valve2, "atEquipment");
|
||||
//vgc.childRegistrationUtils.registerChild(valve3, "atEquipment");
|
||||
|
||||
vgc.updateFlow("measured", 1000, "atEquipment"); // Update total flow to 100 m3/h
|
||||
//vgc.updateFlow("measured", 1000, "atEquipment"); // Update total flow to 100 m3/h
|
||||
|
||||
|
||||
23
vgc.html
23
vgc.html
@@ -1,12 +1,15 @@
|
||||
<!--
|
||||
| S88-niveau | Primair (blokkleur) | Tekstkleur |
|
||||
| ---------------------- | ------------------- | ---------- |
|
||||
| **Area** | `#0f52a5` | wit |
|
||||
| **Process Cell** | `#0c99d9` | wit |
|
||||
| **Unit** | `#50a8d9` | zwart |
|
||||
| **Equipment (Module)** | `#86bbdd` | zwart |
|
||||
| **Control Module** | `#a9daee` | zwart |
|
||||
|
||||
brabantse delta kleuren:
|
||||
#eaf4f1
|
||||
#86bbdd
|
||||
#bad33b
|
||||
#0c99d9
|
||||
#a9daee
|
||||
#0f52a5
|
||||
#50a8d9
|
||||
#cade63
|
||||
#4f8582
|
||||
#c4cce0
|
||||
-->
|
||||
<script src="/valveGroupControl/menu.js"></script> <!-- Load the menu script for dynamic dropdowns -->
|
||||
<script src="/valveGroupControl/configData.js"></script> <!-- Load the config script for node information -->
|
||||
@@ -14,7 +17,7 @@
|
||||
<script>
|
||||
RED.nodes.registerType('valveGroupControl',{
|
||||
category: "EVOLV",
|
||||
color: "#50a8d9",
|
||||
color: "#eaf4f1",
|
||||
defaults: {
|
||||
// Define default properties
|
||||
name: { value: "" },
|
||||
@@ -35,7 +38,7 @@
|
||||
outputs:3,
|
||||
inputLabels: ["Input"],
|
||||
outputLabels: ["process", "dbase", "parent"],
|
||||
icon: "font-awesome/fa-tasks",
|
||||
icon: "font-awesome/fa-tachometer",
|
||||
|
||||
label: function () {
|
||||
return this.positionIcon + " " + "valveGroupControl";
|
||||
|
||||
Reference in New Issue
Block a user