Files
valve/src/flow/flowController.js
znetsixe e27135bdc4 P6: convert valve to BaseDomain + BaseNodeAdapter + concern split
Refactor of valve to use the platform infrastructure (BaseDomain, BaseNodeAdapter,
ChildRouter, commandRegistry, statusBadge). Extracts concerns into
focused modules per .claude/refactor/MODULE_SPLIT.md generic template.
Tests stay green; CONTRACT.md generated; legacy aliases preserved.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 22:09:22 +02:00

85 lines
2.9 KiB
JavaScript

'use strict';
// Sequence + setpoint execution. Mirrors the pre-refactor Valve.handleInput
// switch but delegates state transitions to host.state. Pre-shutdown ramp-down
// to 0 happens here so the existing test contract holds.
class FlowController {
constructor(host) {
this.host = host;
this.logger = host.logger;
}
isValidSourceForMode(source, mode) {
const allowed = this.host.config.mode.allowedSources[mode] || [];
return allowed.has(source);
}
async handleInput(source, action, parameter) {
if (!this.isValidSourceForMode(source, this.host.currentMode)) {
const msg = `Source '${source}' is not valid for mode '${this.host.currentMode}'.`;
this.logger.warn(msg);
return { status: false, feedback: msg };
}
this.logger.info(`Handling input from source '${source}' with action '${action}' in mode '${this.host.currentMode}'.`);
try {
switch (action) {
case 'execSequence':
await this.executeSequence(parameter);
break;
case 'execMovement':
await this.setpoint(parameter);
break;
case 'emergencyStop':
case 'emergencystop':
this.logger.warn(`Emergency stop activated by '${source}'.`);
await this.executeSequence('emergencystop');
break;
case 'statusCheck':
this.logger.info(`Status Check: Mode = '${this.host.currentMode}', Source = '${source}'.`);
break;
default:
this.logger.warn(`Action '${action}' is not implemented.`);
}
this.logger.debug(`Action '${action}' successfully executed`);
return { status: true, feedback: `Action '${action}' successfully executed.` };
} catch (error) {
this.logger.error(`Error handling input: ${error}`);
}
}
async executeSequence(sequenceName) {
const sequence = this.host.config.sequences[sequenceName];
if (!sequence || sequence.size === 0) {
this.logger.warn(`Sequence '${sequenceName}' not defined.`);
return;
}
if (this.host.state.getCurrentState() === 'operational' && sequenceName === 'shutdown') {
this.logger.info(`Machine will ramp down to position 0 before performing ${sequenceName} sequence`);
await this.setpoint(0);
}
this.logger.info(` --------- Executing sequence: ${sequenceName} -------------`);
for (const stateName of sequence) {
try {
await this.host.state.transitionToState(stateName);
} catch (error) {
this.logger.error(`Error during sequence '${sequenceName}': ${error}`);
break;
}
}
}
async setpoint(value) {
try {
if (typeof value !== 'number' || value < 0) {
throw new Error('Invalid setpoint: Setpoint must be a non-negative number.');
}
await this.host.state.moveTo(value);
} catch (error) {
this.logger.error(`Error setting setpoint: ${error}`);
}
}
}
module.exports = FlowController;