Editor + schema defaults - pumpingStation.html: drag-in defaults now reflect a realistic basin (volume=50 m³, height=4 m, inflowLevel=1.5, outflowLevel=0.2, overflowLevel=3.8, startLevel=1, stopLevel=0.5, minLevel=0.3, maxLevel=3.8). Old defaults left every level field null. Visual bug fix - src/editor/mode-preview.js: the level-based ramp curve in the editor was being drawn with foot=startLevel via buildPath(start, start, max). The runtime in control/levelBased.js has always used inflowLevel as the ramp foot. Pass buildPath(start, upFoot, max) where upFoot falls back to start when inflowLevel is missing, matching the runtime. Manual mode observability - src/specificClass.js: store last forwarded demand on this._manualDemand; surface as `mode` and `manualDemand` in getOutput(); call notifyOutputChanged() on forwardDemandToChildren and on changeMode so Port 0/1 emit even with no children registered. Status badge compacted to `mode | dir% | net m³/h` + `Qd=X m³/h` in manual mode. Examples cleanup - Drop stale 02-Integration.json, 03-Dashboard.json, basic-dashboard.flow.json, standalone-demo.js. - 01-Basic.json: numbered driver groups (1. Control mode … 4. Calibration), Debug-outputs group, fixed typos and HOW-TO-USE; Port 1 debug now active. - New 02-Dashboard.json: FlowFuse Dashboard 2.0 with Controls (7 buttons), Status (7 ui-text rows), Trends (4 ui-charts: level / volume / volume% / flow in-out-net), Raw output (ui-template dumping every Port 0 field). Fan-out function pattern-matches the 4-segment measurement keys by prefix instead of hardcoding childId, converts flow m³/s → m³/h, and caches last-known values so deltas never blank a row. - examples/README.md realigned to the two-file set. Wiki - Home.md: 5 image placeholders replaced with the provided screenshots (01-node-and-editor, 02-basic-flow, 03-wiring-standalone, 04-wiring-integrated) and the demo GIF (01-basic-demo). - Reference-Examples.md: shipped-files table reduced to 01-Basic + 02-Dashboard, Example-01 section uses the screenshot + GIF, Example-02 rewritten as Dashboard (kept screenshot/GIF callouts open for those captures), Example-03/Integration sections + their debug-recipes row removed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5.4 KiB
pumpingStation
A pumpingStation models a wet-well lift station: one basin with sensors, and one or more pumps that move water against an elevation difference. It integrates basin volume each tick, picks a control mode (level-based by default), and sends a demand setpoint to its pumps so the basin level stays inside its safe operating band.
At a glance
| Thing | Value |
|---|---|
| What it represents | A wet-well lift station: a basin + N pumps |
| S88 level | Process Cell |
| Use it when | You need to lift water from a low point to a higher one, with sensors driving demand |
| Don't use it for | Pressurised distribution networks (use a pumpingStation cascade or VGC instead), or a single pump with no basin (parent a rotatingMachine directly) |
| Children it accepts | measurement, machine, machinegroup, pumpingstation |
How it looks in Node-RED
What it models
A rectangular basin with measured inflow, measured (or pump-summed) outflow, and a level sensor. The diagram below is the live source; open it in draw.io to edit.
The basin has five horizontal reference lines that matter to the controller:
| Line | Role |
|---|---|
overflowLevel |
Physical weir crest. Above this level the basin is spilling. |
maxLevel |
Demand saturates at 100 % at or above this level. |
startLevel |
Falling-ramp returns to 0 % demand here; deadband upper bound. |
minLevel |
Below this level the controller commands all pumps off. |
dryRunLevel |
Pump-protection cutoff (safety layer, mode-independent). |
Try it — 3-minute demo
Import the basic example flow, deploy, and watch the basin react to inject buttons.
curl -X POST -H 'Content-Type: application/json' \
--data @nodes/pumpingStation/examples/01-Basic.json \
http://localhost:1880/flow
What to click in the dashboard after deploy:
set.mode = levelbased→ the controller switches to level-based mode.set.inflow = 60 m³/h→ inflow is now feeding the basin.cmd.calibrate.level = 1.5 m→ the volume integrator syncs to a known level.- Watch Port 0 in the debug pane: level rises, predicted volume integrates, demand follows the curve.
Typical wiring
The two patterns you'll see most.
Standalone (01-Basic.json)
With a measurement child and an MGC parent
The five things you'll send
| Topic | Payload | What it does |
|---|---|---|
set.mode |
"levelbased" or "manual" |
Switches control strategy. Manual exposes set.demand as the direct setpoint. |
set.demand |
number, m³/h | Operator outflow setpoint. Honoured in manual mode. |
set.inflow |
number, m³/h | Push a measured inflow into the basin balance (if you don't have a measurement child for inflow). |
cmd.calibrate.level |
number, m | Sync the volume integrator to a known level reading. Useful at startup. |
cmd.calibrate.volume |
number, m³ | Sync the volume integrator to a known volume reading. |
What you'll see come out
Sample Port 0 message (delta-compressed — only changed fields each tick):
{
"topic": "pumpingStation#PS1",
"payload": {
"level": 1.62,
"volume": 32.4,
"direction": "filling",
"demand": 38,
"safety": { "blocked": false },
"etaSeconds": 412
}
}
| Field | Meaning |
|---|---|
level |
Current basin level (m). Measured if a level measurement is registered; predicted otherwise. |
volume |
Integrated predicted volume (m³). |
direction |
filling / draining / steady based on the flow dead-band. |
demand |
What the station is asking its pumps to do (0–100 %). |
safety.blocked |
True when the safety layer is overriding the control loop. |
etaSeconds |
Predicted time to full (if filling) or empty (if draining). |
Need more?
| Page | What you'll find |
|---|---|
| Reference — Contracts | Full topic contract, config schema, child registration filters |
| Reference — Architecture | Code map, state chart, lifecycle sequence, output ports |
| Reference — Examples | All shipped example flows + Docker compose snippet + debug recipes |
| Reference — Limitations | When not to use this node, known limitations, open questions |




