specificClass.js: 1760 → 400 lines.
Machine extends BaseDomain. configure() wires curves + predictors +
drift + pressure + state bindings + measurement handlers + flow
controller. ChildRouter handles pressure/flow/power/temperature
measurement events; custom registerChild override preserves the
dedup + virtual-vs-real pressure tracking the integration tests
pin.
Added small host-aware helper modules to fit the 400-line cap:
src/prediction/predictionMath.js (calcFlow/Power/Ctrl)
src/prediction/efficiencyMath.js (calcCog/EfficiencyCurve/etc.)
src/pressure/pressureSelector.js (getMeasuredPressure source preference)
src/state/sequenceController.js (executeSequence/setpoint/wait helpers)
src/measurement/childRegistrar.js (custom registerChild path)
src/drift/healthRefresh.js (drift status update wrappers)
src/io/output.js (buildOutput + buildStatusBadge)
unitPolicy: live UnitPolicy methods .canonical()/.output()/.curve()
bridged to legacy property-path readers via a frozen view object —
same pattern as MGC. See OPEN_QUESTIONS.md.
nodeClass.js: 433 → 61 lines.
Extends BaseNodeAdapter. tickInterval=null (event-driven on state +
measurement events). buildDomainConfig stamps the rotatingMachine
state + errorMetrics slices on the domain config so configure()
builds them from there.
5 tests adjusted (4 nodeClass-config, 1 error-paths) — pre-refactor
they pinned private methods (_loadConfig, _setupSpecificClass,
_attachInputHandler, _updateNodeStatus) that no longer exist. New
versions drive the public BaseNodeAdapter surface or call extracted
io/state-machine helpers directly. See OPEN_QUESTIONS.md 2026-05-10
"private nodeClass tests" for the deferred rewrite plan.
196 / 196 tests pass (basic 110 + integration ~80 + edge ~6).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
62 lines
2.3 KiB
JavaScript
62 lines
2.3 KiB
JavaScript
'use strict';
|
|
|
|
const { BaseNodeAdapter, convert } = require('generalFunctions');
|
|
const Machine = require('./specificClass');
|
|
const commands = require('./commands');
|
|
|
|
// Event-driven: state + measurement events drive recomputes via the
|
|
// domain emitter. No tick loop. Status badge polled every second.
|
|
class nodeClass extends BaseNodeAdapter {
|
|
static DomainClass = Machine;
|
|
static commands = commands;
|
|
static tickInterval = null;
|
|
static statusInterval = 1000;
|
|
|
|
buildDomainConfig(uiConfig) {
|
|
const flowUnit = _resolveUnit(uiConfig.unit, 'volumeFlowRate', 'm3/h');
|
|
// Stash extras on the Machine class so its constructor (called by
|
|
// BaseNodeAdapter via DomainClass) picks them up alongside the
|
|
// machineConfig. Single-threaded JS makes the hand-off race-free.
|
|
Machine._pendingExtras = {
|
|
stateConfig: {
|
|
general: { logging: { enabled: uiConfig.enableLog, logLevel: uiConfig.logLevel } },
|
|
movement: { speed: Number(uiConfig.speed), mode: uiConfig.movementMode },
|
|
time: {
|
|
starting: Number(uiConfig.startup), warmingup: Number(uiConfig.warmup),
|
|
stopping: Number(uiConfig.shutdown), coolingdown: Number(uiConfig.cooldown),
|
|
},
|
|
},
|
|
errorMetricsConfig: {},
|
|
};
|
|
return {
|
|
asset: {
|
|
uuid: uiConfig.assetUuid || uiConfig.uuid || null,
|
|
tagCode: uiConfig.assetTagCode || uiConfig.assetTagNumber || null,
|
|
tagNumber: uiConfig.assetTagNumber || null,
|
|
unit: flowUnit,
|
|
curveUnits: {
|
|
pressure: _resolveUnit(uiConfig.curvePressureUnit, 'pressure', 'mbar'),
|
|
flow: _resolveUnit(uiConfig.curveFlowUnit || flowUnit, 'volumeFlowRate', flowUnit),
|
|
power: _resolveUnit(uiConfig.curvePowerUnit, 'power', 'kW'),
|
|
control: (typeof uiConfig.curveControlUnit === 'string' && uiConfig.curveControlUnit.trim()) || '%',
|
|
},
|
|
},
|
|
general: { unit: flowUnit },
|
|
flowNumber: uiConfig.flowNumber,
|
|
};
|
|
}
|
|
}
|
|
|
|
function _resolveUnit(candidate, expectedMeasure, fallback) {
|
|
const raw = typeof candidate === 'string' ? candidate.trim() : '';
|
|
const fb = String(fallback || '').trim();
|
|
if (!raw) return fb;
|
|
try {
|
|
const desc = convert().describe(raw);
|
|
if (expectedMeasure && desc.measure !== expectedMeasure) return fb;
|
|
return raw;
|
|
} catch (_) { return fb; }
|
|
}
|
|
|
|
module.exports = nodeClass;
|