/** * Dispatches inbound control actions (execSequence / execMovement / * flowMovement / emergencyStop / enter|exitMaintenance / statusCheck) * to the state machine and motion helpers on the host. * * Behaviour mirrors the original specificClass.handleInput exactly: * - actions are lower-cased * - mode/source gating runs first * - flow-setpoints are unit-converted (output -> canonical) before * calcCtrl + setpoint * - thrown errors are caught + logged (no re-throw) so a misbehaving * parent never crashes the FSM */ class FlowController { constructor(ctx) { if (!ctx || !ctx.host) { throw new Error('FlowController: ctx.host is required'); } this.host = ctx.host; this.logger = ctx.logger || ctx.host.logger; } async handle(source, action, parameter) { const host = this.host; if (typeof action !== 'string') { this.logger.error('Action must be string'); return; } action = action.toLowerCase(); if (!host.isValidActionForMode(action, host.currentMode)) return; if (!host.isValidSourceForMode(source, host.currentMode)) return; this.logger.info( `Handling input from source '${source}' with action '${action}' in mode '${host.currentMode}'.`, ); try { switch (action) { case 'execsequence': return await host.executeSequence(parameter); case 'execmovement': return await host.setpoint(parameter); case 'entermaintenance': case 'exitmaintenance': return await host.executeSequence(parameter); case 'flowmovement': { const canonicalFlowSetpoint = host.unitPolicy.convert( parameter, host.unitPolicy.output.flow, host.unitPolicy.canonical.flow, 'flowmovement setpoint', ); const pos = host.calcCtrl(canonicalFlowSetpoint); return await host.setpoint(pos); } case 'emergencystop': this.logger.warn(`Emergency stop activated by '${source}'.`); return await host.executeSequence('emergencystop'); case 'statuscheck': this.logger.info( `Status Check: Mode = '${host.currentMode}', Source = '${source}'.`, ); break; default: this.logger.warn(`Action '${action}' is not implemented.`); break; } this.logger.debug(`Action '${action}' successfully executed`); return { status: true, feedback: `Action '${action}' successfully executed.` }; } catch (error) { this.logger.error(`Error handling input: ${error}`); } } } module.exports = FlowController;