Splits pumpingStation/src/ into focused concern modules. specificClass.js
will be slimmed to an orchestrator in P2.9 (integration); for now both
the inlined logic AND the new modules coexist so tests stay green
throughout.
src/basin/ BasinGeometry + thresholdValidator (pure)
src/measurement/ flowAggregator + measurementRouter + calibration
src/control/ levelBased + flowBased(stub) + manual + index dispatcher
src/safety/ safetyController split into dryRun + overfill rules
src/commands/ registry array + handlers (canonical names from start)
src/editor.js 260 lines of SVG basin-diagram redraw, was inline in .html
examples/standalone-demo.js was if(require.main===module) at bottom of specificClass.js
CONTRACT.md canonical inputs + outputs + emitted events
Modified:
src/specificClass.js removed the 170-line standalone demo block
pumpingStation.html oneditprepare/oneditsave delegate to editor.{init,save}
pumpingStation.js added admin endpoint serving src/editor.js
102 basic tests pass (60 new + 42 existing).
specificClass.js itself is unchanged in behaviour — integration is P2.9.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.4 KiB
pumpingStation — Contract
Hand-maintained for Phase 2; the ## Inputs table is generated from
src/commands/index.js (see Phase 9 generator). Keep ≤ 80 lines.
Inputs (msg.topic on Port 0)
| Canonical | Aliases (deprecated) | Payload | Effect |
|---|---|---|---|
set.mode |
changemode |
string — one of manual, levelbased, flowbased, none |
Switches the control strategy. |
child.register |
registerChild |
string — the child node's Node-RED id |
Resolves the child via RED.nodes.getNode and registers it through childRegistrationUtils at the supplied msg.positionVsParent. |
cmd.calibrate.volume |
calibratePredictedVolume |
numeric (number or numeric string) — m³ | Resets the predicted-volume series and seeds it with the supplied value; recomputes level. |
cmd.calibrate.level |
calibratePredictedLevel |
numeric — metres | Resets the predicted-level series and seeds it with the supplied value; recomputes volume. |
set.inflow |
q_in |
number, numeric string, or { value, unit, timestamp } |
Pushes a manual inflow measurement onto the predicted-flow series. unit may be on the message (msg.unit) or inside the object payload. |
set.demand |
Qd |
numeric — child setpoint demand | Forwards the demand to direct children (machineGroups / machines / stations). Only honoured in manual mode; in other modes the call is logged at debug and discarded. |
Aliases log a one-time deprecation warning the first time they fire.
Outputs (msg.topic on Port 0/1/2)
- Port 0 (process):
msg.topic = config.general.name. Payload built byoutputUtils.formatMsg(..., 'process')fromgetOutput()— delta-compressed (only changed fields are emitted). - Port 1 (InfluxDB telemetry): same shape as Port 0, formatted with the
'influxdb'formatter. - Port 2 (registration): at startup the node sends one
{ topic: 'registerChild', payload: <node.id>, positionVsParent, distance }to the upstream parent.
Events emitted by source.measurements.emitter
The MeasurementContainer fires <type>.<variant>.<position> whenever
the corresponding series receives a new value. Parents subscribe via the
generic child.measurements.emitter.on(eventName, ...) handshake.
pumpingStation publishes:
volume.predicted.atequipment— basin volume integrator output (m³).level.predicted.atequipment— basin level (m), recomputed from volume.flow.predicted.in(childedmanual-qin) — manual inflow injections.volume.measured.atequipment,level.measured.<position>,pressure.measured.<position>,temperature.measured.atequipment,flow.predicted.<in|out>(childed by upstream child id) — when a matching child measurement arrives.
The exact set is data-driven by which children register and what they publish; downstream consumers should subscribe by event name, not assume a fixed catalogue.
Children registered by this node
pumpingStation acts as a parent for measurement, machine, machinegroup,
and pumpingstation software types. Position labels accepted from
children are upstream, downstream, atequipment (and the synonyms
in / out for predicted-flow children). Child-registration plumbing is
documented in MODULE_SPLIT.md; this node does not receive children
through Port 0 input — registration arrives on Port 2 from the child via
the standard childRegistrationUtils handshake.