Files
EVOLV/examples/pumpingstation-3pumps-dashboard/README.md
znetsixe 7aacee6482
Some checks failed
CI / lint-and-test (push) Has been cancelled
feat(examples): pumpingstation-3pumps-dashboard end-to-end demo + bump generalFunctions
New top-level examples/ folder for end-to-end demos that show how multiple
EVOLV nodes work together (complementing the per-node example flows under
nodes/<name>/examples/). Future end-to-end demos will live as siblings.

First demo: pumpingstation-3pumps-dashboard
- 1 pumpingStation (basin model, manual mode for the demo so it observes
  rather than auto-shutting pumps; safety guards disabled — see README)
- 1 machineGroupControl (optimalcontrol mode, absolute scaling)
- 3 rotatingMachine pumps (hidrostal-H05K-S03R curve)
- 6 measurement nodes (per pump: upstream + downstream pressure mbar,
  simulator mode for continuous activity)
- Process demand input via dashboard slider (0-300 m3/h) AND auto random
  generator (3s tick, [40, 240] m3/h) — both feed PS q_in + MGC Qd
- Auto/Manual mode toggle (broadcasts setMode to all 3 pumps)
- Station-wide Start / Stop / Emergency-Stop buttons
- Per-pump setpoint slider, individual buttons, full status text
- Two trend charts (flow per pump, power per pump)
- FlowFuse dashboard at /dashboard/pumping-station-demo

build_flow.py is the source of truth — it generates flow.json
deterministically and is the right place to extend the demo.

Bumps:
  nodes/generalFunctions  43f6906 -> 29b78a3
    Fix: childRegistrationUtils now aliases the production
    softwareType values (rotatingmachine, machinegroupcontrol) to the
    dispatch keys parent nodes check for (machine, machinegroup). Without
    this, MGC <-> rotatingMachine and pumpingStation <-> MGC wiring
    silently never matched in production even though tests passed.
    Demo confirms: MGC reports '3 machine(s) connected'.

Verified end-to-end on Dockerized Node-RED 2026-04-13: pumps reach
operational ~5s after deploy, MGC distributes random demand across them,
basin tracks net flow direction, all dashboard widgets update each second.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 15:53:47 +02:00

7.3 KiB
Raw Blame History

Pumping Station — 3 Pumps with Dashboard

A complete end-to-end EVOLV stack: a wet-well basin model, a machineGroupControl orchestrating three rotatingMachine pumps (each with upstream/downstream pressure measurements), process-demand input from either a dashboard slider or an auto random generator, individual + auto control modes, and a FlowFuse dashboard with status, gauges, and trend charts.

This is the canonical "make sure everything works together" demo for the platform. Use it after any cross-node refactor to confirm the architecture still hangs together end-to-end.

Quick start

cd /mnt/d/gitea/EVOLV
docker compose up -d
# Wait for http://localhost:1880/nodes to return 200, then:
curl -s -X POST http://localhost:1880/flows \
  -H "Content-Type: application/json" \
  -H "Node-RED-Deployment-Type: full" \
  --data-binary @examples/pumpingstation-3pumps-dashboard/flow.json

Or open Node-RED at http://localhost:1880, Import → drop the flow.json, click Deploy.

Then open the dashboard:

What the flow contains

Layer Node(s) Role
Top pumpingStation "Pumping Station" Wet-well basin model. Tracks inflow (q_in), outflow (from machine-group child predictions), basin level/volume. PS is in manual control mode for the demo so it observes without taking control.
Mid machineGroupControl "MGC — Pump Group" Distributes Qd flow demand across the 3 pumps via optimalcontrol (BEP-driven). Scaling: absolute (Qd is in m³/h directly).
Low rotatingMachine × 3 — Pump A / B / C Hidrostal H05K-S03R curve. auto mode by default so MGC's parent commands are accepted. Manual setpoint slider overrides per-pump when each is in virtualControl.
Sensors measurement × 6 Per pump: upstream + downstream pressure (mbar). Simulator mode — each ticks a random-walk value continuously. Registered as children of their pump.
Demand inject demand_rand_tick + function demand_rand_fn + ui-slider Random generator (3 s tick, [40, 240] m³/h) AND a manual slider. Both feed a router that fans out to PS (q_in in m³/s) and MGC (Qd in m³/h).
Glue setMode fanouts + station-wide buttons Mode toggle broadcasts setMode to all 3 pumps. Station-wide Start / Stop / Emergency-Stop buttons fan out to all 3.
Dashboard FlowFuse ui-page + 6 groups Process Demand · Pumping Station · Pump A · Pump B · Pump C · Trends.

Dashboard map

The page (/dashboard/pumping-station-demo) is laid out top-to-bottom:

  1. Process Demand
    • Slider 0300 m³/h (manualDemand topic)
    • Random demand toggle (auto cycles every 3 s)
    • Live "current demand" text
  2. Pumping Station
    • Auto/Manual mode toggle (drives all pumps' setMode simultaneously)
    • Station-wide buttons: Start all · Stop all · Emergency stop
    • Basin state, level (m), volume (m³), inflow / pumped-out flow (m³/h)
  3. Pump A / B / C (one group each)
    • Setpoint slider 0100 % (only effective when that pump is in virtualControl)
    • Per-pump Startup + Shutdown buttons
    • Live state, mode, controller %, flow, power, upstream/downstream pressure
  4. Trends
    • Flow per pump chart (m³/h)
    • Power per pump chart (kW)

Control model

  • AUTO — the default. setMode auto → MGC's optimalcontrol decides which pumps run and at what flow. Operator drives only the Process Demand slider (or leaves the random generator on); the per-pump setpoint sliders are ignored.
  • MANUAL — flip the Auto/Manual switch. All 3 pumps go to virtualControl. MGC commands are now ignored. Per-pump setpoint sliders / Start / Stop are the only inputs that affect the pumps.

The Emergency Stop button always works regardless of mode and uses the new interruptible-movement path so it stops a pump mid-ramp.

Notable design choices

  • PS is in manual control mode (controlMode: "manual"). The default levelbased mode would auto-shut all pumps as soon as basin level dips below stopLevel (1 m default), which masks the demo. Manual = observation only.
  • PS safety guards (dry-run / overfill) disabled. With no real inflow the basin will frequently look "empty" — that's expected for a demo, not a fault. In production you'd configure a real q_in source and leave safeties on.
  • MGC scaling = absolute, mode = optimalcontrol. Set via inject at deploy. Demand in m³/h, BEP-driven distribution.
  • demand_router gates Qd ≤ 0. A demand of 0 would shut every running pump (via MGC.turnOffAllMachines). Use the explicit Stop All button to actually take pumps down.
  • Auto-startup on deploy. All three pumps fire execSequence startup 4 s after deploy so the dashboard shows activity immediately.
  • Auto-enable random demand 5 s after deploy so the trends fill in without operator action.
  • Verbose logging is OFF. All EVOLV nodes are at warn. Crank the per-node logLevel to info or debug if you're diagnosing a flow.

Things to try

  • Drag the Process Demand slider with random off — watch MGC distribute that target across pumps and the basin start filling/draining accordingly.
  • Flip to Manual mode and use the per-pump setpoint sliders — note that MGC stops driving them.
  • Hit Emergency Stop while a pump is ramping — confirms the interruptible-movement fix shipped in rotatingMachine v1.0.3.
  • Watch the Trends chart over a few minutes — flow distribution shifts as MGC re-balances around the BEP.

Verification (last green run, 2026-04-13)

Deployed via POST /flows to a Dockerized Node-RED, observed for ~15 s after auto-startup:

  • All 3 measurement nodes per pump tick (6 total): pressure values stream every second.
  • Each pump reaches operational ~5 s after the auto-startup inject (3 s starting + 1 s warmup + 1 s for setpoint=0 settle).
  • MGC reports 3 machine(s) connected with mode optimalcontrol.
  • Pumping Station shows non-zero basin volume + tracks net flow direction (⬆ / ⬇ / ⏸).
  • Random demand cycles between ~40 and ~240 m³/h every 3 s.
  • Per-pump status text + trend chart update on every tick.

Regenerating flow.json

flow.json is generated from build_flow.py. Edit the Python (cleaner diff) and regenerate:

cd examples/pumpingstation-3pumps-dashboard
python3 build_flow.py > flow.json

The build_flow.py is the source of truth — keep it in sync if you tweak the demo.

Wishlist (not in this demo, build separately)

  • Pump failure + MGC re-routing — kill pump 2 mid-run, watch MGC redistribute. Would demonstrate fault-tolerance.
  • Energy-optimal vs equal-flow control — same demand profile run through optimalcontrol and prioritycontrol modes side-by-side, energy comparison chart.
  • Schedule-driven demand — diurnal flow pattern (low at night, peak at 7 am), MGC auto-tuning over 24 simulated hours.
  • PS with real q_in source + safeties on — show the basin auto-shut behaviour as a feature, not a bug.
  • Real flow sensor per pump (vs. relying on rotatingMachine's predicted flow) — would let the demo also show measurement-vs-prediction drift indicators.
  • Reactor or settler downstream — close the loop on a real wastewater scenario.

See the parent examples/README.md for the full follow-up catalogue.