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
#!/usr/bin/env python3
"""
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
Generate the multi - tab Node - RED flow for the
' pumpingstation-3pumps-dashboard ' end - to - end demo .
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
Layout philosophy
- - - - - - - - - - - - - - - - -
Every node gets a home tab based on its CONCERN , not the data it touches :
Tab 1 Process Plant only EVOLV nodes ( pumps , MGC , PS , measurements )
+ small per - node output formatters . NO UI , NO
demo drivers , NO setup logic . This is the
deployable plant model in isolation .
Tab 2 Dashboard UI only ui - * widgets . NO routing logic beyond
topic - tagging for the chart legends .
Tab 3 Demo Drivers auto random demand generator + station - wide
command fan - outs . Only here so the demo " lives "
without an operator . Removable in production .
Tab 4 Setup & Init one - shot deploy - time injects ( mode , scaling ,
auto - startup ) . Easy to disable for production .
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
Cross - tab wiring is via NAMED link - out / link - in pairs , not direct
wires . The channel names are the contract — see CHANNELS below .
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
Spacing
- - - - - - -
Five lanes per tab , x in [ 120 , 380 , 640 , 900 , 1160 ] . Row pitch 80 px .
Major sections separated by 200 px y - shift + a comment header .
To regenerate :
python3 build_flow . py > flow . json
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
"""
import json
import sys
# ---------------------------------------------------------------------------
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Tab IDs
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
# ---------------------------------------------------------------------------
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
TAB_PROCESS = " tab_process "
TAB_UI = " tab_ui "
TAB_DRIVERS = " tab_drivers "
TAB_SETUP = " tab_setup "
# ---------------------------------------------------------------------------
# Spacing constants
# ---------------------------------------------------------------------------
LANE_X = [ 120 , 380 , 640 , 900 , 1160 , 1420 ]
ROW = 80 # standard inter-row pitch
SECTION_GAP = 200 # additional shift between major sections
# ---------------------------------------------------------------------------
# Cross-tab link channel names (the wiring contract)
# ---------------------------------------------------------------------------
# command channels: dashboard or drivers -> process
CH_DEMAND = " cmd:demand " # numeric demand (m3/h)
CH_RANDOM_TOGGLE = " cmd:randomToggle " # 'on' / 'off'
CH_MODE = " cmd:mode " # 'auto' / 'virtualControl' setMode broadcast
CH_STATION_START = " cmd:station-startup "
CH_STATION_STOP = " cmd:station-shutdown "
CH_STATION_ESTOP = " cmd:station-estop "
CH_PUMP_SETPOINT = { " pump_a " : " cmd:setpoint-A " ,
" pump_b " : " cmd:setpoint-B " ,
" pump_c " : " cmd:setpoint-C " }
CH_PUMP_SEQUENCE = { " pump_a " : " cmd:pump-A-seq " , # carries startup/shutdown
" pump_b " : " cmd:pump-B-seq " ,
" pump_c " : " cmd:pump-C-seq " }
# event channels: process -> dashboard
CH_PUMP_EVT = { " pump_a " : " evt:pump-A " ,
" pump_b " : " evt:pump-B " ,
" pump_c " : " evt:pump-C " }
CH_MGC_EVT = " evt:mgc "
CH_PS_EVT = " evt:ps "
PUMPS = [ " pump_a " , " pump_b " , " pump_c " ]
PUMP_LABELS = { " pump_a " : " Pump A " , " pump_b " : " Pump B " , " pump_c " : " Pump C " }
# ---------------------------------------------------------------------------
# Generic node-builder helpers
# ---------------------------------------------------------------------------
def comment ( node_id , tab , x , y , name , info = " " ) :
return { " id " : node_id , " type " : " comment " , " z " : tab , " name " : name ,
" info " : info , " x " : x , " y " : y , " wires " : [ ] }
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def inject ( node_id , tab , x , y , name , topic , payload , payload_type = " str " ,
once = False , repeat = " " , once_delay = " 0.5 " , wires = None ) :
""" Inject node using the per-prop v/vt form so payload_type=json works. """
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " inject " , " z " : tab , " name " : name ,
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
" props " : [
{ " p " : " topic " , " vt " : " str " } ,
{ " p " : " payload " , " v " : str ( payload ) , " vt " : payload_type } ,
] ,
" topic " : topic , " payload " : str ( payload ) , " payloadType " : payload_type ,
" repeat " : repeat , " crontab " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" once " : once , " onceDelay " : once_delay ,
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
" x " : x , " y " : y , " wires " : [ wires or [ ] ] ,
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def function_node ( node_id , tab , x , y , name , code , outputs = 1 , wires = None ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " function " , " z " : tab , " name " : name ,
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
" func " : code , " outputs " : outputs ,
" noerr " : 0 , " initialize " : " " , " finalize " : " " , " libs " : [ ] ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : x , " y " : y , " wires " : wires if wires is not None else [ [ ] for _ in range ( outputs ) ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def link_out ( node_id , tab , x , y , channel_name , target_in_ids ) :
""" Mode ' link ' — fires the named link-in nodes (by id). """
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " link out " , " z " : tab , " name " : channel_name ,
" mode " : " link " , " links " : list ( target_in_ids ) ,
" x " : x , " y " : y , " wires " : [ ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def link_in ( node_id , tab , x , y , channel_name , source_out_ids , downstream ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " link in " , " z " : tab , " name " : channel_name ,
" links " : list ( source_out_ids ) ,
" x " : x , " y " : y , " wires " : [ downstream or [ ] ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def debug_node ( node_id , tab , x , y , name , target = " payload " ,
target_type = " msg " , active = False ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " debug " , " z " : tab , " name " : name ,
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
" active " : active , " tosidebar " : True , " console " : False , " tostatus " : False ,
" complete " : target , " targetType " : target_type ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : x , " y " : y , " wires " : [ ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
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
# ---------------------------------------------------------------------------
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Dashboard scaffolding (ui-base / ui-theme / ui-page / ui-group)
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
# ---------------------------------------------------------------------------
def dashboard_scaffold ( ) :
base = {
" id " : " ui_base_ps_demo " , " type " : " ui-base " , " name " : " EVOLV Demo " ,
" path " : " /dashboard " , " appIcon " : " " ,
" includeClientData " : True ,
" acceptsClientConfig " : [ " ui-notification " , " ui-control " ] ,
" showPathInSidebar " : True , " headerContent " : " page " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" navigationStyle " : " default " , " titleBarStyle " : " default " ,
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
}
theme = {
" id " : " ui_theme_ps_demo " , " type " : " ui-theme " , " name " : " EVOLV Theme " ,
" colors " : {
" surface " : " #ffffff " , " primary " : " #0f52a5 " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" bgPage " : " #f4f6fa " , " groupBg " : " #ffffff " , " groupOutline " : " #cccccc " ,
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
} ,
" sizes " : {
" density " : " default " , " pagePadding " : " 12px " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" groupGap " : " 12px " , " groupBorderRadius " : " 6px " , " widgetGap " : " 8px " ,
} ,
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
}
2026-04-14 07:46:51 +02:00
page_control = {
" id " : " ui_page_control " , " type " : " ui-page " ,
" name " : " Control " , " ui " : " ui_base_ps_demo " ,
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
" path " : " /pumping-station-demo " , " icon " : " water_pump " ,
" layout " : " grid " , " theme " : " ui_theme_ps_demo " ,
" breakpoints " : [ { " name " : " Default " , " px " : " 0 " , " cols " : " 12 " } ] ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" order " : 1 , " className " : " " ,
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
}
2026-04-14 07:46:51 +02:00
page_short = {
" id " : " ui_page_short_trends " , " type " : " ui-page " ,
" name " : " Trends — 10 min " , " ui " : " ui_base_ps_demo " ,
" path " : " /pumping-station-demo/trends-short " , " icon " : " show_chart " ,
" layout " : " grid " , " theme " : " ui_theme_ps_demo " ,
" breakpoints " : [ { " name " : " Default " , " px " : " 0 " , " cols " : " 12 " } ] ,
" order " : 2 , " className " : " " ,
}
page_long = {
" id " : " ui_page_long_trends " , " type " : " ui-page " ,
" name " : " Trends — 1 hour " , " ui " : " ui_base_ps_demo " ,
" path " : " /pumping-station-demo/trends-long " , " icon " : " timeline " ,
" layout " : " grid " , " theme " : " ui_theme_ps_demo " ,
" breakpoints " : [ { " name " : " Default " , " px " : " 0 " , " cols " : " 12 " } ] ,
" order " : 3 , " className " : " " ,
}
return [ base , theme , page_control , page_short , page_long ]
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
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
def ui_group ( group_id , name , page_id , width = 6 , order = 1 ) :
return {
" id " : group_id , " type " : " ui-group " , " name " : name , " page " : page_id ,
" width " : str ( width ) , " height " : " 1 " , " order " : order ,
" showTitle " : True , " className " : " " , " groupType " : " default " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" disabled " : False , " visible " : True ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def ui_text ( node_id , tab , x , y , group , name , label , fmt , layout = " row-left " ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " ui-text " , " z " : tab , " group " : group ,
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
" order " : 1 , " width " : " 0 " , " height " : " 0 " , " name " : name , " label " : label ,
" format " : fmt , " layout " : layout , " style " : False , " font " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" fontSize " : 14 , " color " : " #000000 " ,
" x " : x , " y " : y , # editor canvas position — without these
# Node-RED dumps every ui-text at (0,0)
# and you get a pile in the top-left corner
" wires " : [ ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def ui_button ( node_id , tab , x , y , group , name , label , payload , payload_type ,
topic , color = " #0f52a5 " , icon = " play_arrow " , wires = None ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " ui-button " , " z " : tab , " group " : group ,
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
" name " : name , " label " : label , " order " : 1 , " width " : " 0 " , " height " : " 0 " ,
" tooltip " : " " , " color " : " #ffffff " , " bgcolor " : color ,
" className " : " " , " icon " : icon , " iconPosition " : " left " ,
" payload " : payload , " payloadType " : payload_type ,
" topic " : topic , " topicType " : " str " , " buttonType " : " default " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : x , " y " : y , " wires " : [ wires or [ ] ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def ui_slider ( node_id , tab , x , y , group , name , label , mn , mx , step = 1.0 ,
topic = " " , wires = None ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " ui-slider " , " z " : tab , " group " : group ,
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
" name " : name , " label " : label , " tooltip " : " " , " order " : 1 ,
" width " : " 0 " , " height " : " 0 " , " passthru " : True , " outs " : " end " ,
" topic " : topic , " topicType " : " str " ,
" min " : str ( mn ) , " max " : str ( mx ) , " step " : str ( step ) ,
" showLabel " : True , " showValue " : True , " labelPosition " : " top " ,
" valuePosition " : " left " , " thumbLabel " : False , " iconStart " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" iconEnd " : " " , " x " : x , " y " : y , " wires " : [ wires or [ ] ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def ui_switch ( node_id , tab , x , y , group , name , label , on_value , off_value ,
topic , wires = None ) :
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " ui-switch " , " z " : tab , " group " : group ,
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
" name " : name , " label " : label , " tooltip " : " " , " order " : 1 ,
" width " : " 0 " , " height " : " 0 " , " passthru " : True , " decouple " : " false " ,
" topic " : topic , " topicType " : " str " ,
" style " : " " , " className " : " " , " evaluate " : " true " ,
" onvalue " : on_value , " onvalueType " : " str " ,
" onicon " : " auto_mode " , " oncolor " : " #0f52a5 " ,
" offvalue " : off_value , " offvalueType " : " str " ,
" officon " : " back_hand " , " offcolor " : " #888888 " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : x , " y " : y , " wires " : [ wires or [ ] ] ,
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
}
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
2026-04-14 07:46:51 +02:00
def ui_chart ( node_id , tab , x , y , group , name , label ,
width = " 12 " , height = " 6 " ,
remove_older = " 10 " , remove_older_unit = " 60 " ,
remove_older_points = " 200 " ,
ymin = None , ymax = None , order = 1 ) :
"""
FlowFuse ui - chart . Dimensions are in grid units :
width = " 12 " = full group width
height = " 6 " = about 300 px tall
` remove_older ` + ` remove_older_unit ` define the rolling window
( e . g . " 10 " + " 60 " = 10 minutes ) . ` remove_older_points ` caps points
per series .
"""
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
return {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : node_id , " type " : " ui-chart " , " z " : tab , " group " : group ,
2026-04-14 07:46:51 +02:00
" name " : name , " label " : label , " order " : order , " chartType " : " line " ,
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
" category " : " topic " , " categoryType " : " msg " ,
" xAxisLabel " : " " , " xAxisType " : " time " , " xAxisTimeFormat " : " auto " ,
" yAxisLabel " : " " , " ymin " : " " if ymin is None else str ( ymin ) ,
" ymax " : " " if ymax is None else str ( ymax ) ,
" action " : " append " , " pointShape " : " circle " , " pointRadius " : 2 ,
2026-04-14 07:46:51 +02:00
" showLegend " : True ,
" removeOlder " : str ( remove_older ) ,
" removeOlderUnit " : str ( remove_older_unit ) ,
" removeOlderPoints " : str ( remove_older_points ) ,
" colors " : [ ] , " textColor " : [ ] , " textColorDefault " : True ,
" width " : str ( width ) , " height " : str ( height ) , " className " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : x , " y " : y ,
" wires " : [ [ ] ] ,
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
}
# ---------------------------------------------------------------------------
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Tab 1 — PROCESS PLANT
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
# ---------------------------------------------------------------------------
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
def build_process_tab ( ) :
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
nodes = [ ]
nodes . append ( {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : TAB_PROCESS , " type " : " tab " ,
" label " : " 🏭 Process Plant " ,
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
" disabled " : False ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" info " : " EVOLV plant model: pumpingStation + machineGroupControl + 3 rotatingMachines, each with upstream and downstream pressure measurements. \n \n Receives commands via link-in nodes from the Dashboard / Demo Drivers tabs. Emits per-pump status via link-out per pump. \n \n No UI, no demo drivers, no one-shot setup logic on this tab — those live on their own tabs so this layer can be lifted into production unchanged. " ,
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
} )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( comment ( " c_process_title " , TAB_PROCESS , LANE_X [ 2 ] , 20 ,
" 🏭 PROCESS PLANT — EVOLV nodes only " ,
" Per pump: 2 measurement sensors → rotatingMachine → output formatter → link-out to dashboard. \n "
" MGC orchestrates 3 pumps. PS observes basin (manual mode for the demo). \n "
" All cross-tab wires are link-in / link-out by named channel. "
) )
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# ---------------- Per-pump rows ----------------
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
for i , pump in enumerate ( PUMPS ) :
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
label = PUMP_LABELS [ pump ]
# Each pump occupies a 4-row block, separated by SECTION_GAP from the next.
y_section = 100 + i * SECTION_GAP
nodes . append ( comment ( f " c_ { pump } " , TAB_PROCESS , LANE_X [ 2 ] , y_section ,
f " ── { label } ── " ,
" Up + Dn pressure sensors register as children. "
" rotatingMachine emits state on port 0 (formatted then link-out to UI). "
" Port 2 emits registerChild → MGC. "
) )
# Two measurement sensors (upstream + downstream)
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
for j , pos in enumerate ( ( " upstream " , " downstream " ) ) :
mid = f " meas_ { pump } _ { pos [ 0 ] } "
absmin , absmax = ( 50 , 400 ) if pos == " upstream " else ( 800 , 2200 )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
mid_label = f " PT- { label . split ( ) [ 1 ] } - { ' Up ' if pos == ' upstream ' else ' Dn ' } "
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
nodes . append ( {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : mid , " type " : " measurement " , " z " : TAB_PROCESS ,
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
" name " : mid_label ,
" mode " : " analog " , " channels " : " [] " ,
" scaling " : False ,
" i_min " : 0 , " i_max " : 1 , " i_offset " : 0 ,
" o_min " : absmin , " o_max " : absmax ,
" simulator " : True ,
" smooth_method " : " mean " , " count " : " 5 " ,
" processOutputFormat " : " process " , " dbaseOutputFormat " : " influxdb " ,
" uuid " : f " sensor- { pump } - { pos } " ,
" supplier " : " vega " , " category " : " sensor " ,
" assetType " : " pressure " , " model " : " vega-pressure-10 " ,
" unit " : " mbar " , " assetTagNumber " : f " PT- { i + 1 } - { pos [ 0 ] . upper ( ) } " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" enableLog " : False , " logLevel " : " warn " ,
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
" positionVsParent " : pos , " positionIcon " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" hasDistance " : False , " distance " : 0 , " distanceUnit " : " m " ,
" distanceDescription " : " " ,
" x " : LANE_X [ 1 ] , " y " : y_section + 40 + j * 50 ,
# Port 2 -> pump (registerChild). Ports 0/1 unused for now.
" wires " : [ [ ] , [ ] , [ pump ] ] ,
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
} )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# link-in for setpoint slider (from dashboard)
nodes . append ( link_in (
f " lin_setpoint_ { pump } " , TAB_PROCESS , LANE_X [ 0 ] , y_section + 60 ,
CH_PUMP_SETPOINT [ pump ] ,
source_out_ids = [ f " lout_setpoint_ { pump } _dash " ] ,
downstream = [ f " build_setpoint_ { pump } " ] ,
) )
nodes . append ( function_node (
f " build_setpoint_ { pump } " , TAB_PROCESS , LANE_X [ 1 ] + 220 , y_section + 60 ,
f " build setpoint cmd ( { label } ) " ,
" msg.topic = ' execMovement ' ; \n "
" msg.payload = { source: ' GUI ' , action: ' execMovement ' , "
" setpoint: Number(msg.payload) }; \n "
" return msg; " ,
outputs = 1 , wires = [ [ pump ] ] ,
) )
# link-in for per-pump sequence (start/stop) commands
nodes . append ( link_in (
f " lin_seq_ { pump } " , TAB_PROCESS , LANE_X [ 0 ] , y_section + 110 ,
CH_PUMP_SEQUENCE [ pump ] ,
source_out_ids = [ f " lout_seq_ { pump } _dash " ] ,
downstream = [ pump ] ,
) )
# The pump itself
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
nodes . append ( {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : pump , " type " : " rotatingMachine " , " z " : TAB_PROCESS ,
" name " : label ,
" speed " : " 10 " ,
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
" startup " : " 2 " , " warmup " : " 1 " , " shutdown " : " 2 " , " cooldown " : " 1 " ,
" movementMode " : " staticspeed " ,
" machineCurve " : " " ,
" uuid " : f " pump- { pump } " ,
" supplier " : " hidrostal " , " category " : " pump " ,
" assetType " : " pump-centrifugal " ,
" model " : " hidrostal-H05K-S03R " ,
" unit " : " m3/h " ,
" curvePressureUnit " : " mbar " , " curveFlowUnit " : " m3/h " ,
" curvePowerUnit " : " kW " , " curveControlUnit " : " % " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" enableLog " : False , " logLevel " : " warn " ,
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
" positionVsParent " : " atEquipment " , " positionIcon " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" hasDistance " : False , " distance " : 0 , " distanceUnit " : " m " ,
" distanceDescription " : " " ,
" x " : LANE_X [ 3 ] , " y " : y_section + 80 ,
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
" wires " : [
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
[ f " format_ { pump } " ] , # port 0 process -> formatter
[ ] , # port 1 dbase
[ MGC_ID ] , # port 2 -> MGC for registerChild
] ,
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
} )
2026-04-14 07:54:02 +02:00
# Per-pump output formatter: builds a fat object with all fields.
# The dashboard dispatcher (on the UI tab) then splits it into
# plain-string payloads per ui-text widget. One link-out per pump.
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( function_node (
f " format_ { pump } " , TAB_PROCESS , LANE_X [ 4 ] , y_section + 80 ,
f " format { label } port 0 " ,
" const p = msg.payload || {} ; \n "
" const c = context.get( ' c ' ) || {} ; \n "
" Object.assign(c, p); \n "
" context.set( ' c ' , c); \n "
" function find(prefix) { \n "
" for (const k in c) { if (k.indexOf(prefix) === 0) return c[k]; } \n "
" return null; \n "
" } \n "
" const flow = find( ' flow.predicted.downstream. ' ); \n "
" const power = find( ' power.predicted.atequipment. ' ); \n "
" const pU = find( ' pressure.measured.upstream. ' ); \n "
" const pD = find( ' pressure.measured.downstream. ' ); \n "
" msg.payload = { \n "
" state: c.state || ' idle ' , \n "
" mode: c.mode || ' auto ' , \n "
" ctrl: c.ctrl != null ? Number(c.ctrl).toFixed(1) + ' % ' : ' n/a ' , \n "
2026-04-14 07:54:02 +02:00
" flow: flow != null ? Number(flow).toFixed(1) + ' m³/h ' : ' n/a ' , \n "
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" power: power != null ? Number(power).toFixed(2) + ' kW ' : ' n/a ' , \n "
2026-04-14 07:54:02 +02:00
" pUp: pU != null ? Number(pU).toFixed(0) + ' mbar ' : ' n/a ' , \n "
" pDn: pD != null ? Number(pD).toFixed(0) + ' mbar ' : ' n/a ' , \n "
" flowNum: flow != null ? Number(flow) : null, \n "
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" powerNum: power != null ? Number(power) : null, \n "
" }; \n "
" return msg; " ,
outputs = 1 , wires = [ [ f " lout_evt_ { pump } " ] ] ,
) )
2026-04-14 07:54:02 +02:00
# link-out: one per pump → dashboard dispatcher
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_out (
f " lout_evt_ { pump } " , TAB_PROCESS , LANE_X [ 5 ] , y_section + 80 ,
CH_PUMP_EVT [ pump ] ,
target_in_ids = [ f " lin_evt_ { pump } _dash " ] ,
) )
# ---------------- MGC ----------------
y_mgc = 100 + 3 * SECTION_GAP
nodes . append ( comment ( " c_mgc " , TAB_PROCESS , LANE_X [ 2 ] , y_mgc ,
" ── MGC ── (orchestrates the 3 pumps via optimalcontrol) " ,
" Receives Qd from cmd:demand link-in. Distributes flow across pumps. "
) )
nodes . append ( link_in (
" lin_demand_to_mgc " , TAB_PROCESS , LANE_X [ 0 ] , y_mgc + 60 ,
CH_DEMAND ,
source_out_ids = [ f " lout_demand_drivers " , f " lout_demand_dash " ] ,
downstream = [ " demand_fanout_mgc_ps " ] ,
) )
# Single fanout: one demand value → MGC (Qd) + PS (q_in).
# Skips when v <= 0 to avoid auto-shutdown.
nodes . append ( function_node (
" demand_fanout_mgc_ps " , TAB_PROCESS , LANE_X [ 1 ] + 220 , y_mgc + 60 ,
" demand → MGC + PS " ,
" const v = Number(msg.payload); \n "
" if (!Number.isFinite(v) || v <= 0) return null; \n "
" // MGC accepts Qd in m3/h directly when scaling=absolute. \n "
" const qd = { topic: ' Qd ' , payload: v }; \n "
" // PS accepts q_in in m3/s (canonical) via the ' unit ' field. \n "
" const qin = { topic: ' q_in ' , payload: v / 3600, unit: ' m3/s ' }; \n "
" return [qd, qin]; " ,
outputs = 2 , wires = [ [ MGC_ID ] , [ PS_ID ] ] ,
) )
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
nodes . append ( {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : MGC_ID , " type " : " machineGroupControl " , " z " : TAB_PROCESS ,
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
" name " : " MGC — Pump Group " ,
" uuid " : " mgc-pump-group " ,
" category " : " controller " ,
" assetType " : " machinegroupcontrol " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" model " : " default " , " unit " : " m3/h " , " supplier " : " evolv " ,
" enableLog " : False , " logLevel " : " warn " ,
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
" positionVsParent " : " atEquipment " , " positionIcon " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" hasDistance " : False , " distance " : 0 , " distanceUnit " : " m " ,
" distanceDescription " : " " ,
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
" processOutputFormat " : " process " , " dbaseOutputFormat " : " influxdb " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : LANE_X [ 3 ] , " y " : y_mgc + 80 ,
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
" wires " : [
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
[ " format_mgc " ] , # port 0 → formatter
[ ] , # port 1 dbase
[ PS_ID ] , # port 2 → PS for registerChild
] ,
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
} )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( function_node (
" format_mgc " , TAB_PROCESS , LANE_X [ 4 ] , y_mgc + 80 ,
" format MGC port 0 " ,
" const p = msg.payload || {} ; \n "
" const c = context.get( ' c ' ) || {} ; \n "
" Object.assign(c, p); \n "
" context.set( ' c ' , c); \n "
" function find(prefix) { \n "
" for (const k in c) { if (k.indexOf(prefix) === 0) return c[k]; } \n "
" return null; \n "
" } \n "
" const totalFlow = find( ' flow.predicted.atequipment. ' ) ?? find( ' downstream_predicted_flow ' ); \n "
" const totalPower = find( ' power.predicted.atequipment. ' ) ?? find( ' atEquipment_predicted_power ' ); \n "
" const eff = find( ' efficiency.predicted.atequipment. ' ); \n "
" msg.payload = { \n "
" totalFlow: totalFlow != null ? Number(totalFlow).toFixed(1) + ' m³/h ' : ' n/a ' , \n "
" totalPower: totalPower != null ? Number(totalPower).toFixed(2) + ' kW ' : ' n/a ' , \n "
" efficiency: eff != null ? Number(eff).toFixed(3) : ' n/a ' , \n "
" totalFlowNum: totalFlow != null ? Number(totalFlow) : null, \n "
" totalPowerNum: totalPower != null ? Number(totalPower) : null, \n "
" }; \n "
" return msg; " ,
outputs = 1 , wires = [ [ " lout_evt_mgc " ] ] ,
) )
nodes . append ( link_out (
" lout_evt_mgc " , TAB_PROCESS , LANE_X [ 5 ] , y_mgc + 80 ,
CH_MGC_EVT , target_in_ids = [ " lin_evt_mgc_dash " ] ,
) )
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# ---------------- PS ----------------
y_ps = 100 + 4 * SECTION_GAP
nodes . append ( comment ( " c_ps " , TAB_PROCESS , LANE_X [ 2 ] , y_ps ,
" ── Pumping Station ── (basin model, manual control mode) " ,
" Receives q_in from demand fanout. Emits formatted basin state. "
) )
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
nodes . append ( {
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" id " : PS_ID , " type " : " pumpingStation " , " z " : TAB_PROCESS ,
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
" name " : " Pumping Station " ,
" uuid " : " ps-basin-1 " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" category " : " station " , " assetType " : " pumpingstation " ,
" model " : " default " , " unit " : " m3/s " , " supplier " : " evolv " ,
" enableLog " : False , " logLevel " : " warn " ,
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
" positionVsParent " : " atEquipment " , " positionIcon " : " " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" hasDistance " : False , " distance " : 0 , " distanceUnit " : " m " ,
" distanceDescription " : " " ,
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
" processOutputFormat " : " process " , " dbaseOutputFormat " : " influxdb " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# PS in manual mode + safeties off — see top-level README for why.
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
" controlMode " : " manual " ,
" basinVolume " : 50 , " basinHeight " : 4 ,
" enableDryRunProtection " : False ,
" enableOverfillProtection " : False ,
" dryRunThresholdPercent " : 0 ,
" overfillThresholdPercent " : 100 ,
" timeleftToFullOrEmptyThresholdSeconds " : 0 ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" x " : LANE_X [ 3 ] , " y " : y_ps + 80 ,
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
" wires " : [
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
[ " format_ps " ] ,
[ ] ,
] ,
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
} )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( function_node (
" format_ps " , TAB_PROCESS , LANE_X [ 4 ] , y_ps + 80 ,
" format PS port 0 " ,
" const p = msg.payload || {} ; \n "
" const c = context.get( ' c ' ) || {} ; \n "
" Object.assign(c, p); \n "
" context.set( ' c ' , c); \n "
" function find(prefix) { \n "
" for (const k in c) { if (k.indexOf(prefix) === 0) return c[k]; } \n "
" return null; \n "
" } \n "
" const lvl = find( ' level.predicted. ' ); \n "
" const vol = find( ' volume.predicted. ' ); \n "
" const qIn = find( ' flow.measured.upstream. ' ) || find( ' flow.measured.in. ' ); \n "
" const qOut = find( ' flow.measured.downstream. ' ) || find( ' flow.measured.out. ' ); \n "
" msg.payload = { \n "
" level: lvl != null ? Number(lvl).toFixed(2) + ' m ' : ' n/a ' , \n "
" volume: vol != null ? Number(vol).toFixed(1) + ' m³ ' : ' n/a ' , \n "
" qIn: qIn != null ? (Number(qIn) * 3600).toFixed(0) + ' m³/h ' : ' n/a ' , \n "
" qOut: qOut != null ? (Number(qOut) * 3600).toFixed(0) + ' m³/h ' : ' n/a ' , \n "
" state: c.state || c.direction || ' idle ' , \n "
" levelNum: lvl != null ? Number(lvl) : null, \n "
" volumeNum: vol != null ? Number(vol) : null, \n "
" }; \n "
" return msg; " ,
outputs = 1 , wires = [ [ " lout_evt_ps " ] ] ,
) )
nodes . append ( link_out (
" lout_evt_ps " , TAB_PROCESS , LANE_X [ 5 ] , y_ps + 80 ,
CH_PS_EVT , target_in_ids = [ " lin_evt_ps_dash " ] ,
) )
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# ---------------- Mode broadcast (Auto/Manual to all pumps) ----------------
y_mode = 100 + 5 * SECTION_GAP
nodes . append ( comment ( " c_mode_bcast " , TAB_PROCESS , LANE_X [ 2 ] , y_mode ,
" ── Mode broadcast ── " ,
" Single ' auto ' / ' virtualControl ' value fans out as setMode to all 3 pumps. "
) )
nodes . append ( link_in (
" lin_mode " , TAB_PROCESS , LANE_X [ 0 ] , y_mode + 60 ,
CH_MODE ,
source_out_ids = [ " lout_mode_dash " ] ,
downstream = [ " fanout_mode " ] ,
) )
nodes . append ( function_node (
" fanout_mode " , TAB_PROCESS , LANE_X [ 1 ] + 220 , y_mode + 60 ,
" fan setMode → 3 pumps " ,
" msg.topic = ' setMode ' ; \n "
" return [msg, msg, msg]; " ,
outputs = 3 , wires = [ [ " pump_a " ] , [ " pump_b " ] , [ " pump_c " ] ] ,
) )
# ---------------- Station-wide commands (start/stop/estop) ----------------
y_station = 100 + 6 * SECTION_GAP
nodes . append ( comment ( " c_station_cmds " , TAB_PROCESS , LANE_X [ 2 ] , y_station ,
" ── Station-wide commands ── (Start All / Stop All / Emergency) " ,
" Each link-in carries a fully-built msg ready for handleInput; we just fan out 3-way. "
) )
for k , ( chan , link_id , fn_name , label_suffix ) in enumerate ( [
( CH_STATION_START , " lin_station_start " , " fan_station_start " , " startup " ) ,
( CH_STATION_STOP , " lin_station_stop " , " fan_station_stop " , " shutdown " ) ,
( CH_STATION_ESTOP , " lin_station_estop " , " fan_station_estop " , " emergency stop " ) ,
] ) :
y = y_station + 60 + k * 60
nodes . append ( link_in (
link_id , TAB_PROCESS , LANE_X [ 0 ] , y , chan ,
source_out_ids = [ f " lout_ { chan . replace ( ' : ' , ' _ ' ) . replace ( ' - ' , ' _ ' ) } _dash " ] ,
downstream = [ fn_name ] ,
) )
nodes . append ( function_node (
fn_name , TAB_PROCESS , LANE_X [ 1 ] + 220 , y ,
f " fan { label_suffix } → 3 pumps " ,
" return [msg, msg, msg]; " ,
outputs = 3 , wires = [ [ " pump_a " ] , [ " pump_b " ] , [ " pump_c " ] ] ,
) )
return nodes
MGC_ID = " mgc_pumps "
PS_ID = " ps_basin "
# ---------------------------------------------------------------------------
# Tab 2 — DASHBOARD UI
# ---------------------------------------------------------------------------
def build_ui_tab ( ) :
nodes = [ ]
nodes . append ( {
" id " : TAB_UI , " type " : " tab " ,
" label " : " 📊 Dashboard UI " ,
" disabled " : False ,
" info " : " Every ui-* widget lives here. Inputs (sliders/switches/buttons) emit "
" via link-out; status text + charts receive via link-in. No business "
" logic on this tab. " ,
} )
# Dashboard scaffold (page + theme + base) + groups
nodes + = dashboard_scaffold ( )
2026-04-14 07:46:51 +02:00
PG = " ui_page_control " # control page is the main page
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
g_demand = " ui_grp_demand "
g_station = " ui_grp_station "
g_pump_a = " ui_grp_pump_a "
g_pump_b = " ui_grp_pump_b "
g_pump_c = " ui_grp_pump_c "
2026-04-14 07:46:51 +02:00
# Trend groups live on separate pages, not the control page.
PG_SHORT = " ui_page_short_trends "
PG_LONG = " ui_page_long_trends "
g_trend_short_flow = " ui_grp_trend_short_flow "
g_trend_short_power = " ui_grp_trend_short_power "
g_trend_long_flow = " ui_grp_trend_long_flow "
g_trend_long_power = " ui_grp_trend_long_power "
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
g_mgc = " ui_grp_mgc "
g_ps = " ui_grp_ps "
nodes + = [
ui_group ( g_demand , " 1. Process Demand " , PG , width = 12 , order = 1 ) ,
ui_group ( g_station , " 2. Station Controls " , PG , width = 12 , order = 2 ) ,
ui_group ( g_mgc , " 3a. MGC Status " , PG , width = 6 , order = 3 ) ,
ui_group ( g_ps , " 3b. Basin Status " , PG , width = 6 , order = 4 ) ,
ui_group ( g_pump_a , " 4a. Pump A " , PG , width = 4 , order = 5 ) ,
ui_group ( g_pump_b , " 4b. Pump B " , PG , width = 4 , order = 6 ) ,
ui_group ( g_pump_c , " 4c. Pump C " , PG , width = 4 , order = 7 ) ,
2026-04-14 07:46:51 +02:00
# Trends on separate pages
ui_group ( g_trend_short_flow , " Flow (10 min) " , PG_SHORT , width = 12 , order = 1 ) ,
ui_group ( g_trend_short_power , " Power (10 min) " , PG_SHORT , width = 12 , order = 2 ) ,
ui_group ( g_trend_long_flow , " Flow (1 hour) " , PG_LONG , width = 12 , order = 1 ) ,
ui_group ( g_trend_long_power , " Power (1 hour) " , PG_LONG , width = 12 , order = 2 ) ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
]
nodes . append ( comment ( " c_ui_title " , TAB_UI , LANE_X [ 2 ] , 20 ,
" 📊 DASHBOARD UI — only ui-* widgets here " ,
" Layout: column 1 = inputs (sliders/switches/buttons) → link-outs. \n "
" Column 2 = link-ins from process → routed to text/gauge/chart widgets. "
) )
# ===== SECTION: Process Demand =====
y = 100
nodes . append ( comment ( " c_ui_demand " , TAB_UI , LANE_X [ 2 ] , y ,
" ── Process Demand ── " , " " ) )
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
nodes . append ( ui_slider (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" ui_demand_slider " , TAB_UI , LANE_X [ 0 ] , y + 40 , g_demand ,
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
" Process demand slider " , " Process Demand (m³/h) " ,
0 , 300 , 5.0 , " manualDemand " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
wires = [ " lout_demand_dash " ]
) )
nodes . append ( link_out (
" lout_demand_dash " , TAB_UI , LANE_X [ 1 ] , y + 40 ,
CH_DEMAND , target_in_ids = [ " lin_demand_to_mgc " , " lin_demand_to_text " ]
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
) )
nodes . append ( ui_switch (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" ui_random_toggle " , TAB_UI , LANE_X [ 0 ] , y + 100 , g_demand ,
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
" Random demand " , " Random demand generator (auto) " ,
on_value = " on " , off_value = " off " , topic = " randomToggle " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
wires = [ " lout_random_dash " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_out (
" lout_random_dash " , TAB_UI , LANE_X [ 1 ] , y + 100 ,
CH_RANDOM_TOGGLE , target_in_ids = [ " lin_random_to_drivers " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( ui_text (
" ui_demand_text " , TAB_UI , LANE_X [ 3 ] , y + 40 , g_demand ,
" Current demand " , " Current demand " , " {{ msg.payload}} m³/h "
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Echo the demand back for the text widget
nodes . append ( link_in (
" lin_demand_to_text " , TAB_UI , LANE_X [ 2 ] , y + 40 ,
CH_DEMAND , source_out_ids = [ " lout_demand_dash " , " lout_demand_drivers " ] ,
downstream = [ " ui_demand_text " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# ===== SECTION: Mode + Station Buttons =====
y = 320
nodes . append ( comment ( " c_ui_station " , TAB_UI , LANE_X [ 2 ] , y ,
" ── Mode + Station-wide buttons ── " , " " ) )
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
nodes . append ( ui_switch (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" ui_mode_toggle " , TAB_UI , LANE_X [ 0 ] , y + 40 , g_station ,
" Auto/Manual mode " ,
" Mode (Auto = MGC orchestrates · Manual = dashboard per-pump) " ,
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
on_value = " auto " , off_value = " virtualControl " , topic = " setMode " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
wires = [ " lout_mode_dash " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_out (
" lout_mode_dash " , TAB_UI , LANE_X [ 1 ] , y + 40 ,
CH_MODE , target_in_ids = [ " lin_mode " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
for k , ( text , payload , color , icon , lout_id , channel ) in enumerate ( [
( " Start all pumps " , ' { " topic " : " execSequence " , " payload " : { " source " : " GUI " , " action " : " execSequence " , " parameter " : " startup " }} ' ,
" #16a34a " , " play_arrow " , " lout_cmd_station_startup_dash " , CH_STATION_START ) ,
( " Stop all pumps " , ' { " topic " : " execSequence " , " payload " : { " source " : " GUI " , " action " : " execSequence " , " parameter " : " shutdown " }} ' ,
" #ea580c " , " stop " , " lout_cmd_station_shutdown_dash " , CH_STATION_STOP ) ,
( " EMERGENCY STOP " , ' { " topic " : " emergencystop " , " payload " : { " source " : " GUI " , " action " : " emergencystop " }} ' ,
" #dc2626 " , " stop_circle " , " lout_cmd_station_estop_dash " , CH_STATION_ESTOP ) ,
] ) :
yk = y + 100 + k * 60
# The ui-button payload becomes msg.payload; we want the button to send
# a fully-formed {topic, payload} for the per-pump nodeClass to dispatch.
# ui-button can't set msg.topic from a constant payload that's an
# object directly — easier path: a small function in front of the
# link-out that wraps the button's plain payload string into the
# right shape per channel.
btn_id = f " btn_station_ { k } "
wrap_id = f " wrap_station_ { k } "
# Use simple payload (just the button text) and let the wrapper build
# the real msg shape.
if k == 0 : # startup
wrap_code = (
" msg.topic = ' execSequence ' ; \n "
" msg.payload = { source: ' GUI ' , action: ' execSequence ' , parameter: ' startup ' }; \n "
" return msg; "
)
elif k == 1 : # shutdown
wrap_code = (
" msg.topic = ' execSequence ' ; \n "
" msg.payload = { source: ' GUI ' , action: ' execSequence ' , parameter: ' shutdown ' }; \n "
" return msg; "
)
else : # estop
wrap_code = (
" msg.topic = ' emergencystop ' ; \n "
" msg.payload = { source: ' GUI ' , action: ' emergencystop ' }; \n "
" return msg; "
)
nodes . append ( ui_button (
btn_id , TAB_UI , LANE_X [ 0 ] , yk , g_station ,
text , text , " fired " , " str " ,
topic = f " station_ { k } " , color = color , icon = icon ,
wires = [ wrap_id ]
) )
nodes . append ( function_node (
wrap_id , TAB_UI , LANE_X [ 1 ] + 100 , yk , f " build cmd ( { text } ) " ,
wrap_code , outputs = 1 , wires = [ [ lout_id ] ]
) )
nodes . append ( link_out (
lout_id , TAB_UI , LANE_X [ 2 ] , yk ,
channel ,
target_in_ids = [ {
CH_STATION_START : " lin_station_start " ,
CH_STATION_STOP : " lin_station_stop " ,
CH_STATION_ESTOP : " lin_station_estop " ,
} [ channel ] ]
) )
# ===== SECTION: MGC + PS overview =====
y = 600
nodes . append ( comment ( " c_ui_mgc_ps " , TAB_UI , LANE_X [ 2 ] , y ,
" ── MGC + Basin overview ── " , " " ) )
nodes . append ( link_in (
" lin_evt_mgc_dash " , TAB_UI , LANE_X [ 0 ] , y + 40 ,
CH_MGC_EVT , source_out_ids = [ " lout_evt_mgc " ] ,
2026-04-14 07:54:02 +02:00
downstream = [ " dispatch_mgc " ]
) )
nodes . append ( function_node (
" dispatch_mgc " , TAB_UI , LANE_X [ 1 ] , y + 40 ,
" dispatch MGC " ,
" const p = msg.payload || {} ; \n "
" return [ \n "
" { payload: String(p.totalFlow || ' n/a ' )}, \n "
" { payload: String(p.totalPower || ' n/a ' )}, \n "
" { payload: String(p.efficiency || ' n/a ' )}, \n "
" ]; " ,
outputs = 3 ,
wires = [ [ " ui_mgc_total_flow " ] , [ " ui_mgc_total_power " ] , [ " ui_mgc_eff " ] ] ,
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( ui_text ( " ui_mgc_total_flow " , TAB_UI , LANE_X [ 2 ] , y + 40 , g_mgc ,
2026-04-14 07:54:02 +02:00
" MGC total flow " , " Total flow " , " {{ msg.payload}} " ) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( ui_text ( " ui_mgc_total_power " , TAB_UI , LANE_X [ 2 ] , y + 70 , g_mgc ,
2026-04-14 07:54:02 +02:00
" MGC total power " , " Total power " , " {{ msg.payload}} " ) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( ui_text ( " ui_mgc_eff " , TAB_UI , LANE_X [ 2 ] , y + 100 , g_mgc ,
2026-04-14 07:54:02 +02:00
" MGC efficiency " , " Group efficiency " , " {{ msg.payload}} " ) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_in (
" lin_evt_ps_dash " , TAB_UI , LANE_X [ 0 ] , y + 160 ,
CH_PS_EVT , source_out_ids = [ " lout_evt_ps " ] ,
2026-04-14 07:54:02 +02:00
downstream = [ " dispatch_ps " ]
) )
nodes . append ( function_node (
" dispatch_ps " , TAB_UI , LANE_X [ 1 ] , y + 160 ,
" dispatch PS " ,
" const p = msg.payload || {} ; \n "
" return [ \n "
" { payload: String(p.state || ' idle ' )}, \n "
" { payload: String(p.level || ' n/a ' )}, \n "
" { payload: String(p.volume || ' n/a ' )}, \n "
" { payload: String(p.qIn || ' n/a ' )}, \n "
" { payload: String(p.qOut || ' n/a ' )}, \n "
" ]; " ,
outputs = 5 ,
wires = [ [ " ui_ps_state " ] , [ " ui_ps_level " ] , [ " ui_ps_volume " ] , [ " ui_ps_qin " ] , [ " ui_ps_qout " ] ] ,
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( ui_text ( " ui_ps_state " , TAB_UI , LANE_X [ 2 ] , y + 160 , g_ps ,
2026-04-14 07:54:02 +02:00
" PS state " , " Basin state " , " {{ msg.payload}} " ) )
nodes . append ( ui_text ( " ui_ps_level " , TAB_UI , LANE_X [ 2 ] , y + 200 , g_ps ,
" PS level " , " Basin level " , " {{ msg.payload}} " ) )
nodes . append ( ui_text ( " ui_ps_volume " , TAB_UI , LANE_X [ 2 ] , y + 240 , g_ps ,
" PS volume " , " Basin volume " , " {{ msg.payload}} " ) )
nodes . append ( ui_text ( " ui_ps_qin " , TAB_UI , LANE_X [ 2 ] , y + 280 , g_ps ,
" PS Qin " , " Inflow " , " {{ msg.payload}} " ) )
nodes . append ( ui_text ( " ui_ps_qout " , TAB_UI , LANE_X [ 2 ] , y + 320 , g_ps ,
" PS Qout " , " Pumped out " , " {{ msg.payload}} " ) )
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# ===== SECTION: Per-pump panels =====
y_pumps_start = 1000
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
for i , pump in enumerate ( PUMPS ) :
label = PUMP_LABELS [ pump ]
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
g = { " pump_a " : g_pump_a , " pump_b " : g_pump_b , " pump_c " : g_pump_c } [ pump ]
y_p = y_pumps_start + i * SECTION_GAP * 2
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
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( comment ( f " c_ui_ { pump } " , TAB_UI , LANE_X [ 2 ] , y_p ,
f " ── { label } ── " , " " ) )
2026-04-14 07:54:02 +02:00
# link-in: one fat object per pump → dispatcher splits into
# plain-string payloads per ui-text widget + numeric payloads
# for trend charts. 9 outputs total.
DISPLAY_FIELDS = [
( " State " , " state " ) ,
( " Mode " , " mode " ) ,
( " Controller % " , " ctrl " ) ,
( " Flow " , " flow " ) ,
( " Power " , " power " ) ,
( " p Upstream " , " pUp " ) ,
( " p Downstream " , " pDn " ) ,
]
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_in (
f " lin_evt_ { pump } _dash " , TAB_UI , LANE_X [ 0 ] , y_p + 40 ,
CH_PUMP_EVT [ pump ] , source_out_ids = [ f " lout_evt_ { pump } " ] ,
2026-04-14 07:54:02 +02:00
downstream = [ f " dispatch_ { pump } " ] ,
) )
# Dispatcher: takes the fat object and returns 9 outputs, each
# with a plain payload ready for a ui-text or trend chart.
nodes . append ( function_node (
f " dispatch_ { pump } " , TAB_UI , LANE_X [ 1 ] , y_p + 40 ,
f " dispatch { label } " ,
" const p = msg.payload || {} ; \n "
2026-04-14 07:59:04 +02:00
" const ts = Date.now(); \n "
2026-04-14 07:54:02 +02:00
" return [ \n "
" { payload: String(p.state || ' idle ' )}, \n "
" { payload: String(p.mode || ' auto ' )}, \n "
" { payload: String(p.ctrl || ' n/a ' )}, \n "
" { payload: String(p.flow || ' n/a ' )}, \n "
" { payload: String(p.power || ' n/a ' )}, \n "
" { payload: String(p.pUp || ' n/a ' )}, \n "
" { payload: String(p.pDn || ' n/a ' )}, \n "
2026-04-14 07:59:04 +02:00
" p.flowNum != null ? { topic: ' " + label + " ' , payload: p.flowNum, timestamp: ts} : null, \n "
" p.powerNum != null ? { topic: ' " + label + " ' , payload: p.powerNum, timestamp: ts} : null, \n "
2026-04-14 07:54:02 +02:00
" ]; " ,
outputs = 9 ,
wires = [
[ f " ui_ { pump } _ { f } " ] for _ , f in DISPLAY_FIELDS
] + [
[ " trend_short_flow " , " trend_long_flow " ] , # output 7: flowNum → both flow charts
[ " trend_short_power " , " trend_long_power " ] , # output 8: powerNum → both power charts
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
] ,
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
) )
2026-04-14 07:54:02 +02:00
# ui-text widgets
for k , ( label_txt , field ) in enumerate ( DISPLAY_FIELDS ) :
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( ui_text (
2026-04-14 07:54:02 +02:00
f " ui_ { pump } _ { field } " , TAB_UI , LANE_X [ 2 ] , y_p + 40 + k * 40 , g ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
f " { label } { label_txt } " , label_txt ,
2026-04-14 07:54:02 +02:00
" {{ msg.payload}} " # plain string — FlowFuse-safe
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
) )
# Setpoint slider → wrapper → link-out → process pump (cmd:setpoint-X)
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
nodes . append ( ui_slider (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
f " ui_ { pump } _setpoint " , TAB_UI , LANE_X [ 0 ] , y_p + 280 , g ,
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
f " { label } setpoint " , " Setpoint % (manual mode) " ,
0 , 100 , 5.0 , f " setpoint_ { pump } " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
wires = [ f " lout_setpoint_ { pump } _dash " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_out (
f " lout_setpoint_ { pump } _dash " , TAB_UI , LANE_X [ 1 ] , y_p + 280 ,
CH_PUMP_SETPOINT [ pump ] ,
target_in_ids = [ f " lin_setpoint_ { pump } " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Per-pump start/stop buttons → link-out
# We need wrappers because ui-button payload must be string-typed.
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
nodes . append ( ui_button (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
f " btn_ { pump } _start " , TAB_UI , LANE_X [ 0 ] , y_p + 330 , g ,
f " { label } startup " , " Startup " , " fired " , " str " ,
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
topic = f " start_ { pump } " , color = " #16a34a " , icon = " play_arrow " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
wires = [ f " wrap_ { pump } _start " ]
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
) )
nodes . append ( function_node (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
f " wrap_ { pump } _start " , TAB_UI , LANE_X [ 1 ] + 100 , y_p + 330 ,
f " build start ( { label } ) " ,
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
" msg.topic = ' execSequence ' ; \n "
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" msg.payload = { source: ' GUI ' , action: ' execSequence ' , parameter: ' startup ' }; \n "
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
" return msg; " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
outputs = 1 , wires = [ [ f " lout_seq_ { pump } _dash " ] ]
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
) )
nodes . append ( ui_button (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
f " btn_ { pump } _stop " , TAB_UI , LANE_X [ 0 ] , y_p + 380 , g ,
f " { label } shutdown " , " Shutdown " , " fired " , " str " ,
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
topic = f " stop_ { pump } " , color = " #ea580c " , icon = " stop " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
wires = [ f " wrap_ { pump } _stop " ]
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
) )
nodes . append ( function_node (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
f " wrap_ { pump } _stop " , TAB_UI , LANE_X [ 1 ] + 100 , y_p + 380 ,
f " build stop ( { label } ) " ,
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
" msg.topic = ' execSequence ' ; \n "
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" msg.payload = { source: ' GUI ' , action: ' execSequence ' , parameter: ' shutdown ' }; \n "
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
" return msg; " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
outputs = 1 , wires = [ [ f " lout_seq_ { pump } _dash " ] ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Both start and stop wrappers feed one shared link-out
nodes . append ( link_out (
f " lout_seq_ { pump } _dash " , TAB_UI , LANE_X [ 2 ] , y_p + 355 ,
CH_PUMP_SEQUENCE [ pump ] ,
target_in_ids = [ f " lin_seq_ { pump } " ]
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
) )
2026-04-14 07:54:02 +02:00
# (Trend feed is handled by dispatcher outputs 7+8 above — no separate
# trend_split function needed.)
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
2026-04-14 07:46:51 +02:00
# ===== Trend charts — two pages, two charts per page =====
# Short-term (10 min rolling window) and long-term (1 hour).
# Same data feed; different removeOlder settings.
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
y_charts = y_pumps_start + len ( PUMPS ) * SECTION_GAP * 2 + 80
nodes . append ( comment ( " c_ui_trends " , TAB_UI , LANE_X [ 2 ] , y_charts ,
2026-04-14 07:46:51 +02:00
" ── Trend charts ── (feed to 4 charts on 2 pages) " ,
" Short-term (10 min) and long-term (1 h) trends share the same feed. \n "
" Each chart on its own page. "
) )
# Short-term (10 min)
nodes . append ( ui_chart (
" trend_short_flow " , TAB_UI , LANE_X [ 3 ] , y_charts + 40 ,
g_trend_short_flow ,
" Flow per pump — 10 min " , " Flow per pump (m³/h) " ,
width = " 12 " , height = " 8 " ,
remove_older = " 10 " , remove_older_unit = " 60 " , remove_older_points = " 300 " ,
order = 1 ,
) )
nodes . append ( ui_chart (
" trend_short_power " , TAB_UI , LANE_X [ 3 ] , y_charts + 120 ,
g_trend_short_power ,
" Power per pump — 10 min " , " Power per pump (kW) " ,
width = " 12 " , height = " 8 " ,
remove_older = " 10 " , remove_older_unit = " 60 " , remove_older_points = " 300 " ,
order = 1 ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
) )
2026-04-14 07:46:51 +02:00
# Long-term (1 hour)
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
nodes . append ( ui_chart (
2026-04-14 07:46:51 +02:00
" trend_long_flow " , TAB_UI , LANE_X [ 3 ] , y_charts + 200 ,
g_trend_long_flow ,
" Flow per pump — 1 hour " , " Flow per pump (m³/h) " ,
width = " 12 " , height = " 8 " ,
remove_older = " 60 " , remove_older_unit = " 60 " , remove_older_points = " 1800 " ,
order = 1 ,
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
) )
nodes . append ( ui_chart (
2026-04-14 07:46:51 +02:00
" trend_long_power " , TAB_UI , LANE_X [ 3 ] , y_charts + 280 ,
g_trend_long_power ,
" Power per pump — 1 hour " , " Power per pump (kW) " ,
width = " 12 " , height = " 8 " ,
remove_older = " 60 " , remove_older_unit = " 60 " , remove_older_points = " 1800 " ,
order = 1 ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
) )
return nodes
# ---------------------------------------------------------------------------
# Tab 3 — DEMO DRIVERS
# ---------------------------------------------------------------------------
def build_drivers_tab ( ) :
nodes = [ ]
nodes . append ( {
" id " : TAB_DRIVERS , " type " : " tab " ,
" label " : " 🎛️ Demo Drivers " ,
" disabled " : False ,
" info " : " Auto stimulus for the demo. Random demand generator + state holder "
" for the dashboard ' s randomToggle switch. In production, delete this "
" tab and feed cmd:demand from your real demand source. " ,
} )
nodes . append ( comment ( " c_drv_title " , TAB_DRIVERS , LANE_X [ 2 ] , 20 ,
" 🎛️ DEMO DRIVERS — auto stimulus only " ,
" Removable: in production, replace this tab with the real demand source. "
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# Random toggle state holder (set by the dashboard switch)
y = 100
nodes . append ( comment ( " c_drv_state " , TAB_DRIVERS , LANE_X [ 2 ] , y ,
" ── Random toggle state ── " , " " ) )
nodes . append ( link_in (
" lin_random_to_drivers " , TAB_DRIVERS , LANE_X [ 0 ] , y + 40 ,
CH_RANDOM_TOGGLE , source_out_ids = [ " lout_random_dash " ] ,
downstream = [ " random_state " ]
) )
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
nodes . append ( function_node (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" random_state " , TAB_DRIVERS , LANE_X [ 1 ] , y + 40 ,
" store random on/off " ,
" flow.set( ' randomOn ' , msg.payload === ' on ' ); \n "
" return null; " ,
outputs = 1 , wires = [ [ ] ]
) )
# Random demand generator: every 3s pick a value in [40, 240] m³/h
y = 250
nodes . append ( comment ( " c_drv_random " , TAB_DRIVERS , LANE_X [ 2 ] , y ,
" ── Random demand generator ── (every 3 s) " , " " ) )
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
nodes . append ( inject (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" rand_tick " , TAB_DRIVERS , LANE_X [ 0 ] , y + 40 ,
" tick (random demand) " ,
topic = " randomTick " , payload = " " , payload_type = " date " ,
repeat = " 3 " , wires = [ " random_demand_fn " ]
) )
nodes . append ( function_node (
" random_demand_fn " , TAB_DRIVERS , LANE_X [ 1 ] + 220 , y + 40 ,
" random demand " ,
" if (!flow.get( ' randomOn ' )) return null; \n "
" const v = Math.round(40 + Math.random() * 200); \n "
" return { topic: ' manualDemand ' , payload: v }; " ,
outputs = 1 , wires = [ [ " lout_demand_drivers " ] ]
) )
nodes . append ( link_out (
" lout_demand_drivers " , TAB_DRIVERS , LANE_X [ 3 ] , y + 40 ,
CH_DEMAND , target_in_ids = [ " lin_demand_to_mgc " , " lin_demand_to_text " ]
) )
return nodes
# ---------------------------------------------------------------------------
# Tab 4 — SETUP & INIT
# ---------------------------------------------------------------------------
def build_setup_tab ( ) :
nodes = [ ]
nodes . append ( {
" id " : TAB_SETUP , " type " : " tab " ,
" label " : " ⚙️ Setup & Init " ,
" disabled " : False ,
" info " : " One-shot deploy-time injects. Sets MGC scaling/mode, broadcasts "
" pumps mode = auto, and auto-starts the pumps + random demand. " ,
} )
nodes . append ( comment ( " c_setup_title " , TAB_SETUP , LANE_X [ 2 ] , 20 ,
" ⚙️ SETUP & INIT — one-shot deploy-time injects " ,
" Disable this tab in production — the runtime should be persistent. "
) )
# Setup wires DIRECTLY to the process nodes (cross-tab via link is cleaner
# but for one-shot setups direct wiring keeps the intent obvious).
y = 100
nodes . append ( inject (
" setup_mgc_scaling " , TAB_SETUP , LANE_X [ 0 ] , y ,
" MGC scaling = absolute " ,
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
topic = " setScaling " , payload = " absolute " , payload_type = " str " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
once = True , once_delay = " 1.5 " ,
wires = [ " lout_setup_to_mgc " ]
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
) )
nodes . append ( inject (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" setup_mgc_mode " , TAB_SETUP , LANE_X [ 0 ] , y + 60 ,
" MGC mode = optimalcontrol " ,
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
topic = " setMode " , payload = " optimalcontrol " , payload_type = " str " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
once = True , once_delay = " 1.7 " ,
wires = [ " lout_setup_to_mgc " ]
) )
nodes . append ( link_out (
" lout_setup_to_mgc " , TAB_SETUP , LANE_X [ 1 ] , y + 30 ,
" setup:to-mgc " , target_in_ids = [ " lin_setup_at_mgc " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
y = 250
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
nodes . append ( inject (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" setup_pumps_mode " , TAB_SETUP , LANE_X [ 0 ] , y ,
" pumps mode = auto " ,
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
topic = " setMode " , payload = " auto " , payload_type = " str " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
once = True , once_delay = " 2.0 " ,
wires = [ " lout_mode_setup " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_out (
" lout_mode_setup " , TAB_SETUP , LANE_X [ 1 ] , y ,
CH_MODE , target_in_ids = [ " lin_mode " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
y = 350
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
nodes . append ( inject (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" setup_pumps_startup " , TAB_SETUP , LANE_X [ 0 ] , y ,
" auto-startup all pumps " ,
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
topic = " execSequence " ,
payload = ' { " source " : " GUI " , " action " : " execSequence " , " parameter " : " startup " } ' ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
payload_type = " json " , once = True , once_delay = " 4 " ,
wires = [ " lout_setup_station_start " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
nodes . append ( link_out (
" lout_setup_station_start " , TAB_SETUP , LANE_X [ 1 ] , y ,
CH_STATION_START , target_in_ids = [ " lin_station_start " ]
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
) )
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
y = 450
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
nodes . append ( inject (
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
" setup_random_on " , TAB_SETUP , LANE_X [ 0 ] , y ,
" auto-enable random demand " ,
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
topic = " randomToggle " , payload = " on " , payload_type = " str " ,
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
once = True , once_delay = " 5 " ,
wires = [ " lout_setup_random " ]
) )
nodes . append ( link_out (
" lout_setup_random " , TAB_SETUP , LANE_X [ 1 ] , y ,
CH_RANDOM_TOGGLE , target_in_ids = [ " lin_random_to_drivers " ]
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
) )
return nodes
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
# ---------------------------------------------------------------------------
# Process tab additions: setup link-in feeding MGC
# ---------------------------------------------------------------------------
def add_setup_link_to_process ( process_nodes ) :
""" Inject a link-in on the process tab that funnels setup msgs to MGC. """
y = 100 + 7 * SECTION_GAP
process_nodes . append ( comment (
" c_setup_at_mgc " , TAB_PROCESS , LANE_X [ 2 ] , y ,
" ── Setup feeders ── " ,
" Cross-tab link from Setup tab → MGC scaling/mode init. "
) )
process_nodes . append ( link_in (
" lin_setup_at_mgc " , TAB_PROCESS , LANE_X [ 0 ] , y + 60 ,
" setup:to-mgc " ,
source_out_ids = [ " lout_setup_to_mgc " ] ,
downstream = [ MGC_ID ]
) )
# ---------------------------------------------------------------------------
# Assemble + emit
# ---------------------------------------------------------------------------
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
def main ( ) :
refactor(examples): split pumpingstation demo across 4 concern-based tabs + add layout rule set
The demo was a single 96-node tab with everything wired directly. Now
4 tabs wired only through named link-out / link-in pairs, and a
permanent rule set for future Claude sessions to follow.
Tabs (by concern, not by data flow):
🏭 Process Plant only EVOLV nodes (3 pumps + MGC + PS + 6 measurements)
+ per-node output formatters
📊 Dashboard UI only ui-* widgets, button/setpoint wrappers, trend
splitters
🎛️ Demo Drivers random demand generator + state holder. Removable
in production
⚙️ Setup & Init one-shot deploy-time injects (mode, scaling,
auto-startup, random-on)
Cross-tab wiring uses a fixed named-channel contract (cmd:demand,
cmd:mode, cmd:setpoint-A, evt:pump-A, etc.) — multiple emitters can
target a single link-in for fan-in, e.g. both the slider and the random
generator feed cmd:demand.
Bug fixes folded in:
1. Trend chart was empty / scrambled. Root cause: the trend-feeder
function had ONE output that wired to BOTH flow and power charts,
so each chart received both flow and power msgs and the legend
garbled. Now: 2 outputs (flow → flow chart, power → power chart),
one msg per output.
2. Every ui-text and ui-chart fell on the (0, 0) corner of the editor
canvas. Root cause: the helper functions accepted x/y parameters
but never assigned them on the returned node dict — Node-RED
defaulted every widget to (0, 0) and they piled on top of each
other. The dashboard render was unaffected (it lays out by group/
order), but the editor was unreadable. Fixed both helpers and added
a verification step ("no node should be at (0, 0)") to the rule set.
Spacing convention (now codified):
- 6 lanes per tab at x = [120, 380, 640, 900, 1160, 1420]
- 80 px standard row pitch, 30-40 px for tight ui-text stacks
- 200 px gap between sections, with a comment header per section
New rule set: .claude/rules/node-red-flow-layout.md
- Tab boundaries by concern
- Link-channel naming convention (cmd:/evt:/setup: prefixes)
- Spacing constants
- Trend-split chart pattern
- Inject node payload typing pitfall (per-prop v/vt)
- Dashboard widget rules (every ui-* needs x/y!)
- Do/don't checklist
- Link-out/link-in JSON cheat sheet
- 5-step layout verification before declaring a flow done
CLAUDE.md updated to point at the new rule set.
Verified end-to-end on Dockerized Node-RED 2026-04-13: 168 nodes across
4 tabs, all wired via 22 link-out / 19 link-in pairs, no nodes at
(0, 0), pumps reach operational ~5 s after deploy, MGC distributes
random demand, trends populate per pump.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 16:13:27 +02:00
process_nodes = build_process_tab ( )
add_setup_link_to_process ( process_nodes )
nodes = process_nodes + build_ui_tab ( ) + build_drivers_tab ( ) + build_setup_tab ( )
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
json . dump ( nodes , sys . stdout , indent = 2 )
sys . stdout . write ( " \n " )
if __name__ == " __main__ " :
main ( )