Complete general functions

This commit is contained in:
znetsixe
2025-05-26 17:09:18 +02:00
parent 47dfe3850f
commit 2e57034f14
44 changed files with 6776 additions and 0 deletions

131
helper/state/state.js Normal file
View File

@@ -0,0 +1,131 @@
//load local dependencies
const EventEmitter = require('events');
const StateManager = require('./stateManager');
const MovementManager = require('./movementManager');
//load all config modules
const defaultConfig = require('./stateConfig.json');
const ConfigUtils = require('../../../generalFunctions/helper/configUtils');
class state{
constructor(config = {}, logger) {
this.emitter = new EventEmitter(); // Own EventEmitter
this.configUtils = new ConfigUtils(defaultConfig);
this.config = this.configUtils.initConfig(config);
this.abortController = null; // new abort controller for aborting async tasks
// Init after config is set
this.logger = logger;
// Initialize StateManager for state handling
this.stateManager = new StateManager(this.config,this.logger);
this.movementManager = new MovementManager(this.config, this.logger, this.emitter);
this.delayedMove = null;
this.mode = this.config.mode.current;
// Log initialization
this.logger.info("State class initialized.");
}
// -------- Delegate State Management -------- //
getMoveTimeLeft() {
return this.movementManager.timeleft;
}
getCurrentState() {
return this.stateManager.currentState;
}
getStateDescription() {
return this.stateManager.getStateDescription();
}
// -------- Movement Methods -------- //
getCurrentPosition() {
return this.movementManager.getCurrentPosition();
}
getRunTimeHours() {
return this.stateManager.getRunTimeHours();
}
async moveTo(targetPosition) {
// Check for invalid conditions and throw errors
if (targetPosition === this.getCurrentPosition()) {
this.logger.warn(`Target position=${targetPosition} is the same as the current position ${this.getCurrentPosition()}. Not executing move.`);
return;
}
if (this.stateManager.getCurrentState() !== "operational") {
if (this.config.mode.current === "auto") {
this.delayedMove = targetPosition;
this.logger.warn(`Saving setpoint=${targetPosition} to execute once back in 'operational' state.`);
}
else{
this.logger.warn(`Not able to accept setpoint=${targetPosition} while not in ${this.stateManager.getCurrentState()} state`);
}
//return early
return;
}
this.abortController = new AbortController();
const { signal } = this.abortController;
try {
const newState = targetPosition < this.getCurrentPosition() ? "decelerating" : "accelerating";
await this.transitionToState(newState,signal); // awaits transition
await this.movementManager.moveTo(targetPosition,signal); // awaits moving
this.emitter.emit("movementComplete", { position: targetPosition });
await this.transitionToState("operational");
} catch (error) {
this.logger.error(error);
}
}
// -------- State Transition Methods -------- //
async transitionToState(targetState, signal) {
const fromState = this.getCurrentState();
const position = this.getCurrentPosition();
try {
this.logger.debug(`Starting transition from ${fromState} to ${targetState}.`);
const feedback = await this.stateManager.transitionTo(targetState,signal);
this.logger.info(`Statemanager: ${feedback}`);
/* -- Auto pick setpoints in auto mode when operational--*/
if (
targetState === "operational" &&
this.config.mode.current === "auto" &&
this.delayedMove !== position &&
this.delayedMove
) {
this.logger.info(`Automatically picking up on last requested setpoint ${this.delayedMove}`);
//trigger move
await this.moveTo(this.delayedMove,signal);
this.delayedMove = null;
this.logger.info(`moveTo : ${feedback} `);
}
this.logger.info(`State change to ${targetState} completed.`);
this.emitter.emit('stateChange', targetState); // <-- Implement Here
} catch (error) {
if (
error.message === "Transition aborted" ||
error.message === "Movement aborted"
) {
throw error;
}
this.logger.error(error);
}
}
}
module.exports = state;