From 9ada6e2acd15e78cd20025653b447188020e585f Mon Sep 17 00:00:00 2001 From: znetsixe <73483679+znetsixe@users.noreply.github.com> Date: Wed, 5 Nov 2025 15:47:05 +0100 Subject: [PATCH] Added support for maintenance tracking in hours. "getMaintenanceTimeHours" default in output of machine now --- src/configs/rotatingMachine.json | 36 +++++++++++++------------ src/state/state.js | 4 +++ src/state/stateConfig.json | 18 ++++++++++--- src/state/stateManager.js | 45 ++++++++++++++++++++++++++++---- 4 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/configs/rotatingMachine.json b/src/configs/rotatingMachine.json index 2c83be7..1baa685 100644 --- a/src/configs/rotatingMachine.json +++ b/src/configs/rotatingMachine.json @@ -245,10 +245,6 @@ { "value": "fysicalControl", "description": "Controlled via physical buttons or switches; ignores external automated commands." - }, - { - "value": "maintenance", - "description": "No active control from auto, virtual, or fysical sources." } ], "description": "The operational mode of the machine." @@ -260,7 +256,7 @@ "type": "object", "schema":{ "auto": { - "default": ["statusCheck", "execMovement", "execSequence", "emergencyStop"], + "default": ["statusCheck", "execMovement", "execSequence", "emergencyStop","enterMaintenance"], "rules": { "type": "set", "itemType": "string", @@ -268,7 +264,7 @@ } }, "virtualControl": { - "default": ["statusCheck", "execMovement", "execSequence", "emergencyStop"], + "default": ["statusCheck", "execMovement", "execSequence", "emergencyStop","exitMaintenance"], "rules": { "type": "set", "itemType": "string", @@ -276,20 +272,13 @@ } }, "fysicalControl": { - "default": ["statusCheck", "emergencyStop"], + "default": ["statusCheck", "emergencyStop","enterMaintenance","exitMaintenance"], "rules": { "type": "set", "itemType": "string", "description": "Actions allowed in fysicalControl mode." } - }, - "maintenance": { - "default": ["statusCheck"], - "rules": { - "type": "set", - "itemType": "string", - "description": "Actions allowed in maintenance mode." - } + } } }, "description": "Information about valid command sources recognized by the machine." @@ -327,7 +316,6 @@ }, "description": "Information about valid command sources recognized by the machine." } - } }, "source": { "default": "parent", @@ -386,6 +374,22 @@ "itemType": "string", "description": "Sequence of states for booting up the machine." } + }, + "entermaintenance":{ + "default": ["stopping","coolingdown","idle","maintenance"], + "rules": { + "type": "set", + "itemType": "string", + "description": "Sequence of states if the machine is running to put it in maintenance state" + } + }, + "exitmaintenance":{ + "default": ["off","idle"], + "rules": { + "type": "set", + "itemType": "string", + "description": "Sequence of states if the machine is running to put it in maintenance state" + } } } }, diff --git a/src/state/state.js b/src/state/state.js index 2ad0229..abe7508 100644 --- a/src/state/state.js +++ b/src/state/state.js @@ -52,7 +52,11 @@ class state{ return this.stateManager.getRunTimeHours(); } + getMaintenanceTimeHours(){ + return this.stateManager.getMaintenanceTimeHours(); + } + async moveTo(targetPosition) { // Check for invalid conditions and throw errors diff --git a/src/state/stateConfig.json b/src/state/stateConfig.json index 99d398f..8a0b39b 100644 --- a/src/state/stateConfig.json +++ b/src/state/stateConfig.json @@ -205,6 +205,10 @@ { "value": "off", "description": "Machine is off." + }, + { + "value": "maintenance", + "description": "Machine locked for inspection or repair; automatic control disabled." } ], "description": "Current state of the machine." @@ -216,7 +220,7 @@ "type": "object", "schema": { "idle": { - "default": ["starting", "off","emergencystop"], + "default": ["starting", "off","emergencystop","maintenance"], "rules":{ "type": "set", "itemType": "string", @@ -280,7 +284,7 @@ } }, "off": { - "default": ["idle","emergencystop"], + "default": ["idle","emergencystop","maintenance"], "rules":{ "type": "set", "itemType": "string", @@ -288,12 +292,20 @@ } }, "emergencystop": { - "default": ["idle","off"], + "default": ["idle","off","maintenance"], "rules":{ "type": "set", "itemType": "string", "description": "Allowed transitions from emergency stop state." } + }, + "maintenance": { + "default": ["maintenance","idle","off"], + "rules":{ + "type": "set", + "itemType": "string", + "description": "Allowed transitions for maintenance mode" + } } }, "description": "Allowed transitions between states." diff --git a/src/state/stateManager.js b/src/state/stateManager.js index 4549308..9b3139f 100644 --- a/src/state/stateManager.js +++ b/src/state/stateManager.js @@ -48,10 +48,14 @@ class stateManager { // Define valid transitions (can be extended dynamically if needed) this.validTransitions = config.state.allowedTransitions; - // NEW: Initialize runtime tracking + //runtime tracking this.runTimeHours = 0; // cumulative runtime in hours this.runTimeStart = null; // timestamp when active state began + //maintenance tracking + this.maintenanceTimeStart = null; //timestamp when active state began + this.maintenanceTimeHours = 0; //cumulative + // Define active states (runtime counts only in these states) this.activeStates = config.state.activeStates; } @@ -59,7 +63,7 @@ class stateManager { getCurrentState() { return this.currentState; } - + transitionTo(newState,signal) { return new Promise((resolve, reject) => { if (signal && signal.aborted) { @@ -73,8 +77,9 @@ class stateManager { ); //go back early and reject promise } - // NEW: Handle runtime tracking based on active states + //Time tracking based on active states this.handleRuntimeTracking(newState); + this.handleMaintenancetimeTracking(newState); const transitionDuration = this.transitionTimes[this.currentState] || 0; // Default to 0 if no transition time this.logger.debug( @@ -100,7 +105,7 @@ class stateManager { } handleRuntimeTracking(newState) { - // NEW: Handle runtime tracking based on active states + //Handle runtime tracking based on active states const wasActive = this.activeStates.has(this.currentState); const willBeActive = this.activeStates.has(newState); if (wasActive && !willBeActive && this.runTimeStart) { @@ -120,6 +125,28 @@ class stateManager { } } + handleMaintenancetimeTracking(newState) { + //is this maintenance time ? + const wasActive = (this.currentState == "maintenance"? true:false); + const willBeActive = ( newState == "maintenance" ? true:false ); + + if (wasActive && this.maintenanceTimeStart) { + // stop runtime timer and accumulate elapsed time + const elapsed = (Date.now() - this.maintenanceTimeStart) / 3600000; // hours + this.maintenanceTimeHours += elapsed; + this.maintenanceTimeStart = null; + this.logger.debug( + `Maintenance timer stopped; elapsed=${elapsed.toFixed( + 3 + )}h, total=${this.maintenanceTimeHours.toFixed(3)}h.` + ); + } else if (willBeActive && !this.runTimeStart) { + // starting new runtime + this.maintenanceTimeStart = Date.now(); + this.logger.debug("Runtime timer started."); + } + } + isValidTransition(newState) { this.logger.debug( `Check 1 Transition valid ? From ${ @@ -150,7 +177,6 @@ class stateManager { return this.descriptions[state] || "No description available."; } - // NEW: Getter to retrieve current cumulative runtime (active time) in hours. getRunTimeHours() { // If currently active add the ongoing duration. let currentElapsed = 0; @@ -159,6 +185,15 @@ class stateManager { } return this.runTimeHours + currentElapsed; } + + getMaintenanceTimeHours() { + // If currently active add the ongoing duration. + let currentElapsed = 0; + if (this.maintenanceTimeStart) { + currentElapsed = (Date.now() - this.maintenanceTimeStart) / 3600000; + } + return this.maintenanceTimeHours + currentElapsed; + } } module.exports = stateManager;