merging
This commit is contained in:
@@ -114,8 +114,8 @@ class nodeClass {
|
|||||||
try {
|
try {
|
||||||
const mode = m.currentMode;
|
const mode = m.currentMode;
|
||||||
const state = m.state.getCurrentState();
|
const state = m.state.getCurrentState();
|
||||||
const flow = Math.round(m.measurements.type("flow").variant("predicted").position('downstream').getCurrentValue());
|
const flow = Math.round(m.measurements.type("flow").variant("predicted").position('downstream').getCurrentValue('m3/h'));
|
||||||
const power = Math.round(m.measurements.type("power").variant("predicted").position('atEquipment').getCurrentValue());
|
const power = Math.round(m.measurements.type("power").variant("predicted").position('atequipment').getCurrentValue('kW'));
|
||||||
let symbolState;
|
let symbolState;
|
||||||
switch(state){
|
switch(state){
|
||||||
case "off":
|
case "off":
|
||||||
@@ -145,6 +145,9 @@ class nodeClass {
|
|||||||
case "decelerating":
|
case "decelerating":
|
||||||
symbolState = "⏪";
|
symbolState = "⏪";
|
||||||
break;
|
break;
|
||||||
|
case "maintenance":
|
||||||
|
symbolState = "🔧";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
const position = m.state.getCurrentPosition();
|
const position = m.state.getCurrentPosition();
|
||||||
const roundedPosition = Math.round(position * 100) / 100;
|
const roundedPosition = Math.round(position * 100) / 100;
|
||||||
|
|||||||
@@ -48,7 +48,17 @@ class Machine {
|
|||||||
this.errorMetrics = new nrmse(errorMetricsConfig, this.logger);
|
this.errorMetrics = new nrmse(errorMetricsConfig, this.logger);
|
||||||
|
|
||||||
// Initialize measurements
|
// Initialize measurements
|
||||||
this.measurements = new MeasurementContainer();
|
this.measurements = new MeasurementContainer({
|
||||||
|
autoConvert: true,
|
||||||
|
windowSize: 50,
|
||||||
|
defaultUnits: {
|
||||||
|
pressure: 'mbar',
|
||||||
|
flow: this.config.general.unit,
|
||||||
|
power: 'kW',
|
||||||
|
temperature: 'C'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.interpolation = new interpolation();
|
this.interpolation = new interpolation();
|
||||||
|
|
||||||
this.flowDrift = null;
|
this.flowDrift = null;
|
||||||
@@ -68,6 +78,12 @@ class Machine {
|
|||||||
this.updatePosition();
|
this.updatePosition();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//When state changes look if we need to do other updates
|
||||||
|
this.state.emitter.on("stateChange", (newState) => {
|
||||||
|
this.logger.debug(`State change detected: ${newState}`);
|
||||||
|
this._updateState();
|
||||||
|
});
|
||||||
|
|
||||||
this.child = {}; // object to hold child information so we know on what to subscribe
|
this.child = {}; // object to hold child information so we know on what to subscribe
|
||||||
this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility
|
this.childRegistrationUtils = new childRegistrationUtils(this); // Child registration utility
|
||||||
|
|
||||||
@@ -102,6 +118,53 @@ class Machine {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// --- KPI tracking ---
|
||||||
|
this.kpi = {
|
||||||
|
failures: 0,
|
||||||
|
totalRuntimeHours: 0,
|
||||||
|
totalDowntimeHours: 0,
|
||||||
|
lastFailureTime: null,
|
||||||
|
lastRepairTime: null,
|
||||||
|
MTBF: 0,
|
||||||
|
MTTR: 0,
|
||||||
|
availability: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
this.assetHealth = {
|
||||||
|
index: 0 // 0 = optimal, 5 = failure
|
||||||
|
};
|
||||||
|
|
||||||
|
this.state.emitter.on('stateChange', (payload) => {
|
||||||
|
|
||||||
|
const stateStr = typeof payload === 'string'
|
||||||
|
? payload
|
||||||
|
: (payload?.state ?? payload?.newState ?? payload);
|
||||||
|
|
||||||
|
if (typeof stateStr !== 'string') {
|
||||||
|
this.logger.warn(`stateChange event without parsable state: ${JSON.stringify(payload)}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._handleStateChangeForKPI(stateStr);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateState(){
|
||||||
|
const isOperational = this._isOperationalState();
|
||||||
|
if(!isOperational){
|
||||||
|
//overrule the last prediction this should be 0 now
|
||||||
|
this.measurements.type("flow").variant("predicted").position("downstream").value(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateState(){
|
||||||
|
const isOperational = this._isOperationalState();
|
||||||
|
if(!isOperational){
|
||||||
|
//overrule the last prediction this should be 0 now
|
||||||
|
this.measurements.type("flow").variant("predicted").position("downstream").value(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*------------------- Register child events -------------------*/
|
/*------------------- Register child events -------------------*/
|
||||||
@@ -192,43 +255,68 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
|||||||
// -------- Mode and Input Management -------- //
|
// -------- Mode and Input Management -------- //
|
||||||
isValidSourceForMode(source, mode) {
|
isValidSourceForMode(source, mode) {
|
||||||
const allowedSourcesSet = this.config.mode.allowedSources[mode] || [];
|
const allowedSourcesSet = this.config.mode.allowedSources[mode] || [];
|
||||||
return allowedSourcesSet.has(source);
|
const allowed = allowedSourcesSet.has(source);
|
||||||
|
allowed?
|
||||||
|
this.logger.debug(`source is allowed proceeding with ${source} for mode ${mode}`) :
|
||||||
|
this.logger.warn(`${source} is not allowed in mode ${mode}`);
|
||||||
|
|
||||||
|
return allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
isValidActionForMode(action, mode) {
|
isValidActionForMode(action, mode) {
|
||||||
const allowedActionsSet = this.config.mode.allowedActions[mode] || [];
|
const allowedActionsSet = this.config.mode.allowedActions[mode] || [];
|
||||||
return allowedActionsSet.has(action);
|
const allowed = allowedActionsSet.has(action);
|
||||||
|
allowed ?
|
||||||
|
this.logger.debug(`Action is allowed proceeding with ${action} for mode ${mode}`) :
|
||||||
|
this.logger.warn(`${action} is not allowed in mode ${mode}`);
|
||||||
|
|
||||||
|
return allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleInput(source, action, parameter) {
|
async handleInput(source, action, parameter) {
|
||||||
|
|
||||||
if (!this.isValidSourceForMode(source, this.currentMode)) {
|
this.logger.debug("hello");
|
||||||
let warningTxt = `Source '${source}' is not valid for mode '${this.currentMode}'.`;
|
//sanitize input
|
||||||
this.logger.warn(warningTxt);
|
if( typeof action !== 'string'){this.logger.error(`Action must be string`); return;}
|
||||||
return {status : false , feedback: warningTxt};
|
//convert to lower case to avoid to many mistakes in commands
|
||||||
}
|
action = action.toLowerCase();
|
||||||
|
|
||||||
|
// check for validity of the request
|
||||||
|
if(!this.isValidActionForMode(action,this.currentMode)){return ;}
|
||||||
|
if (!this.isValidSourceForMode(source, this.currentMode)) {return ;}
|
||||||
|
|
||||||
|
this.logger.debug("hello2");
|
||||||
|
|
||||||
this.logger.info(`Handling input from source '${source}' with action '${action}' in mode '${this.currentMode}'.`);
|
this.logger.info(`Handling input from source '${source}' with action '${action}' in mode '${this.currentMode}'.`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "execSequence":
|
|
||||||
|
case "execsequence":
|
||||||
return await this.executeSequence(parameter);
|
return await this.executeSequence(parameter);
|
||||||
|
|
||||||
case "execMovement":
|
case "execmovement":
|
||||||
return await this.setpoint(parameter);
|
return await this.setpoint(parameter);
|
||||||
|
|
||||||
case "flowMovement":
|
case "entermaintenance":
|
||||||
|
|
||||||
|
return await this.executeSequence(parameter);
|
||||||
|
|
||||||
|
|
||||||
|
case "exitmaintenance":
|
||||||
|
return await this.executeSequence(parameter);
|
||||||
|
|
||||||
|
case "flowmovement":
|
||||||
// Calculate the control value for a desired flow
|
// Calculate the control value for a desired flow
|
||||||
const pos = this.calcCtrl(parameter);
|
const pos = this.calcCtrl(parameter);
|
||||||
// Move to the desired setpoint
|
// Move to the desired setpoint
|
||||||
return await this.setpoint(pos);
|
return await this.setpoint(pos);
|
||||||
|
|
||||||
case "emergencyStop":
|
case "emergencystop":
|
||||||
this.logger.warn(`Emergency stop activated by '${source}'.`);
|
this.logger.warn(`Emergency stop activated by '${source}'.`);
|
||||||
return await this.executeSequence("emergencyStop");
|
return await this.executeSequence("emergencyStop");
|
||||||
|
|
||||||
case "statusCheck":
|
case "statuscheck":
|
||||||
this.logger.info(`Status Check: Mode = '${this.currentMode}', Source = '${source}'.`);
|
this.logger.info(`Status Check: Mode = '${this.currentMode}', Source = '${source}'.`);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -528,13 +616,14 @@ _callMeasurementHandler(measurementType, value, position, context) {
|
|||||||
|
|
||||||
// Update predicted flow if you have prediction capability
|
// Update predicted flow if you have prediction capability
|
||||||
if (this.predictFlow) {
|
if (this.predictFlow) {
|
||||||
this.measurements.type("flow").variant("predicted").position("atEquipment").value(this.predictFlow.outputY || 0);
|
this.measurements.type("flow").variant("predicted").position("downstream").value(this.predictFlow.outputY || 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method for operational state check
|
// Helper method for operational state check
|
||||||
_isOperationalState() {
|
_isOperationalState() {
|
||||||
const state = this.state.getCurrentState();
|
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);
|
return ["operational", "accelerating", "decelerating"].includes(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -718,7 +807,6 @@ _handleStateChangeForKPI(newState) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Calculate the center of gravity for current pressure
|
// Calculate the center of gravity for current pressure
|
||||||
calcCog() {
|
calcCog() {
|
||||||
|
|
||||||
@@ -834,23 +922,12 @@ _handleStateChangeForKPI(newState) {
|
|||||||
|
|
||||||
// Improved output object generation
|
// Improved output object generation
|
||||||
const output = {};
|
const output = {};
|
||||||
//build the output object
|
|
||||||
this.measurements.getTypes().forEach(type => {
|
|
||||||
this.measurements.getVariants(type).forEach(variant => {
|
|
||||||
|
|
||||||
const downstreamVal = this.measurements.type(type).variant(variant).position("downstream").getCurrentValue();
|
Object.entries(this.measurements.measurements).forEach(([type, variants]) => {
|
||||||
const upstreamVal = this.measurements.type(type).variant(variant).position("upstream").getCurrentValue();
|
Object.entries(variants).forEach(([variant, positions]) => {
|
||||||
|
Object.entries(positions).forEach(([position, measurement]) => {
|
||||||
if (downstreamVal != null) {
|
output[`${type}.${variant}.${position}`] = measurement.getCurrentValue();
|
||||||
output[`downstream_${variant}_${type}`] = downstreamVal;
|
});
|
||||||
}
|
|
||||||
if (upstreamVal != null) {
|
|
||||||
output[`upstream_${variant}_${type}`] = upstreamVal;
|
|
||||||
}
|
|
||||||
if (downstreamVal != null && upstreamVal != null) {
|
|
||||||
const diffVal = this.measurements.type(type).variant(variant).difference().value;
|
|
||||||
output[`differential_${variant}_${type}`] = diffVal;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -870,6 +947,7 @@ _handleStateChangeForKPI(newState) {
|
|||||||
output["asset_tag_number"] = 'L001';
|
output["asset_tag_number"] = 'L001';
|
||||||
|
|
||||||
// output["asset_tag_number"] = this.assetTagNumber;
|
// output["asset_tag_number"] = this.assetTagNumber;
|
||||||
|
output["maintenanceTime"] = this.state.getMaintenanceTimeHours();
|
||||||
|
|
||||||
if(this.flowDrift != null){
|
if(this.flowDrift != null){
|
||||||
const flowDrift = this.flowDrift;
|
const flowDrift = this.flowDrift;
|
||||||
|
|||||||
Reference in New Issue
Block a user