Delete the legacy _convertUnitValue helper on the domain and the duplicate convertUnitValue export on curveNormalizer; both were identical to UnitPolicy.convert. Callers in flowController, the curve normalizer, and buildQHCurve now go through this.unitPolicy. The contract in .claude/refactor/CONTRACTS.md §6 named these as the target migration; this finishes the rollout for rotatingMachine. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
86 lines
2.6 KiB
JavaScript
86 lines
2.6 KiB
JavaScript
/**
|
|
* 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;
|