P9.3 + examples: fresh 3-tier flows + pilot wiki Home.md
examples/ (new — was empty except standalone-demo.js):
01-Basic.json 14 nodes, inject + dashboard, no parent
02-Integration.json 32 nodes, 2 tabs, measurement + MGC + 2 pumps,
link-out/link-in channels per node-red-flow-layout.md
03-Dashboard.json 63 nodes, 3 tabs (process + UI + setup),
FlowFuse charts + sliders, trend-split pattern
README.md load instructions
tools/build-examples.js regenerator
All canonical topic names only (set.*, cmd.*, data.*, child.*). No
legacy aliases. Every ui-* widget has x/y. Every chart has the full
mandatory key set from node-red-flow-layout.md §4.
wiki/Home.md (new) — pilot page for the 14-section visual-first template.
Sections 5 (topic-contract) + 9 (data-model) are auto-generated via the
new npm run wiki:* scripts; everything else hand-written following
.claude/refactor/WIKI_TEMPLATE.md.
package.json — added wiki:contract / wiki:datamodel / wiki:all scripts
wired to ../generalFunctions/scripts/wikiGen.js.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:50:45 +02:00
[
feat(pumpingStation): realistic defaults, ramp-foot visual fix, manual-mode visibility, dashboard example
Editor + schema defaults
- pumpingStation.html: drag-in defaults now reflect a realistic basin
(volume=50 m³, height=4 m, inflowLevel=1.5, outflowLevel=0.2,
overflowLevel=3.8, startLevel=1, stopLevel=0.5, minLevel=0.3,
maxLevel=3.8). Old defaults left every level field null.
Visual bug fix
- src/editor/mode-preview.js: the level-based ramp curve in the editor
was being drawn with foot=startLevel via buildPath(start, start, max).
The runtime in control/levelBased.js has always used inflowLevel as
the ramp foot. Pass buildPath(start, upFoot, max) where upFoot falls
back to start when inflowLevel is missing, matching the runtime.
Manual mode observability
- src/specificClass.js: store last forwarded demand on this._manualDemand;
surface as `mode` and `manualDemand` in getOutput(); call
notifyOutputChanged() on forwardDemandToChildren and on changeMode so
Port 0/1 emit even with no children registered. Status badge compacted
to `mode | dir% | net m³/h` + `Qd=X m³/h` in manual mode.
Examples cleanup
- Drop stale 02-Integration.json, 03-Dashboard.json, basic-dashboard.flow.json,
standalone-demo.js.
- 01-Basic.json: numbered driver groups (1. Control mode … 4. Calibration),
Debug-outputs group, fixed typos and HOW-TO-USE; Port 1 debug now active.
- New 02-Dashboard.json: FlowFuse Dashboard 2.0 with Controls (7 buttons),
Status (7 ui-text rows), Trends (4 ui-charts: level / volume / volume% /
flow in-out-net), Raw output (ui-template dumping every Port 0 field).
Fan-out function pattern-matches the 4-segment measurement keys by
prefix instead of hardcoding childId, converts flow m³/s → m³/h, and
caches last-known values so deltas never blank a row.
- examples/README.md realigned to the two-file set.
Wiki
- Home.md: 5 image placeholders replaced with the provided screenshots
(01-node-and-editor, 02-basic-flow, 03-wiring-standalone,
04-wiring-integrated) and the demo GIF (01-basic-demo).
- Reference-Examples.md: shipped-files table reduced to 01-Basic +
02-Dashboard, Example-01 section uses the screenshot + GIF, Example-02
rewritten as Dashboard (kept screenshot/GIF callouts open for those
captures), Example-03/Integration sections + their debug-recipes row
removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:52:00 +02:00
{
"id" : "77f00aef1c966167" ,
"type" : "tab" ,
"label" : "PumpingStation - Basic" ,
"disabled" : false ,
"info" : "Tier 1: single pumpingStation node driven by inject nodes only. Demonstrates the canonical Phase-2 topic API: set.mode, set.inflow, set.demand."
P9.3 + examples: fresh 3-tier flows + pilot wiki Home.md
examples/ (new — was empty except standalone-demo.js):
01-Basic.json 14 nodes, inject + dashboard, no parent
02-Integration.json 32 nodes, 2 tabs, measurement + MGC + 2 pumps,
link-out/link-in channels per node-red-flow-layout.md
03-Dashboard.json 63 nodes, 3 tabs (process + UI + setup),
FlowFuse charts + sliders, trend-split pattern
README.md load instructions
tools/build-examples.js regenerator
All canonical topic names only (set.*, cmd.*, data.*, child.*). No
legacy aliases. Every ui-* widget has x/y. Every chart has the full
mandatory key set from node-red-flow-layout.md §4.
wiki/Home.md (new) — pilot page for the 14-section visual-first template.
Sections 5 (topic-contract) + 9 (data-model) are auto-generated via the
new npm run wiki:* scripts; everything else hand-written following
.claude/refactor/WIKI_TEMPLATE.md.
package.json — added wiki:contract / wiki:datamodel / wiki:all scripts
wired to ../generalFunctions/scripts/wikiGen.js.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:50:45 +02:00
} ,
feat(pumpingStation): realistic defaults, ramp-foot visual fix, manual-mode visibility, dashboard example
Editor + schema defaults
- pumpingStation.html: drag-in defaults now reflect a realistic basin
(volume=50 m³, height=4 m, inflowLevel=1.5, outflowLevel=0.2,
overflowLevel=3.8, startLevel=1, stopLevel=0.5, minLevel=0.3,
maxLevel=3.8). Old defaults left every level field null.
Visual bug fix
- src/editor/mode-preview.js: the level-based ramp curve in the editor
was being drawn with foot=startLevel via buildPath(start, start, max).
The runtime in control/levelBased.js has always used inflowLevel as
the ramp foot. Pass buildPath(start, upFoot, max) where upFoot falls
back to start when inflowLevel is missing, matching the runtime.
Manual mode observability
- src/specificClass.js: store last forwarded demand on this._manualDemand;
surface as `mode` and `manualDemand` in getOutput(); call
notifyOutputChanged() on forwardDemandToChildren and on changeMode so
Port 0/1 emit even with no children registered. Status badge compacted
to `mode | dir% | net m³/h` + `Qd=X m³/h` in manual mode.
Examples cleanup
- Drop stale 02-Integration.json, 03-Dashboard.json, basic-dashboard.flow.json,
standalone-demo.js.
- 01-Basic.json: numbered driver groups (1. Control mode … 4. Calibration),
Debug-outputs group, fixed typos and HOW-TO-USE; Port 1 debug now active.
- New 02-Dashboard.json: FlowFuse Dashboard 2.0 with Controls (7 buttons),
Status (7 ui-text rows), Trends (4 ui-charts: level / volume / volume% /
flow in-out-net), Raw output (ui-template dumping every Port 0 field).
Fan-out function pattern-matches the 4-segment measurement keys by
prefix instead of hardcoding childId, converts flow m³/s → m³/h, and
caches last-known values so deltas never blank a row.
- examples/README.md realigned to the two-file set.
Wiki
- Home.md: 5 image placeholders replaced with the provided screenshots
(01-node-and-editor, 02-basic-flow, 03-wiring-standalone,
04-wiring-integrated) and the demo GIF (01-basic-demo).
- Reference-Examples.md: shipped-files table reduced to 01-Basic +
02-Dashboard, Example-01 section uses the screenshot + GIF, Example-02
rewritten as Dashboard (kept screenshot/GIF callouts open for those
captures), Example-03/Integration sections + their debug-recipes row
removed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 14:52:00 +02:00
{
"id" : "aa3381b896eb2cfb" ,
"type" : "group" ,
"z" : "77f00aef1c966167" ,
"name" : "Pumping Station (Process Cell)" ,
"style" : {
"label" : true ,
"stroke" : "#000000" ,
"fill" : "#0c99d9" ,
"fill-opacity" : "0.10"
} ,
"nodes" : [
"8e78b6607deb33a7"
] ,
"x" : 534 ,
"y" : 351.5 ,
"w" : 232 ,
"h" : 97
} ,
{
"id" : "4996420d47442fad" ,
"type" : "group" ,
"z" : "77f00aef1c966167" ,
"name" : "1. Control mode" ,
"style" : {
"stroke" : "#666666" ,
"fill" : "#ffdf7f" ,
"fill-opacity" : "0.15" ,
"label" : true ,
"color" : "#333333"
} ,
"nodes" : [
"1155bbbde7c65363" ,
"e9bea0f95b557f5d"
] ,
"x" : 94 ,
"y" : 119 ,
"w" : 272 ,
"h" : 122
} ,
{
"id" : "a9f9b38b0e00c1d7" ,
"type" : "group" ,
"z" : "77f00aef1c966167" ,
"name" : "2. Flow signals (inflow / outflow)" ,
"style" : {
"stroke" : "#666666" ,
"fill" : "#ffdf7f" ,
"fill-opacity" : "0.15" ,
"label" : true ,
"color" : "#333333"
} ,
"nodes" : [
"7b2b5eb919b1ab15" ,
"3350187815774b95"
] ,
"x" : 94 ,
"y" : 279 ,
"w" : 262 ,
"h" : 122
} ,
{
"id" : "42bf82c87d05f498" ,
"type" : "group" ,
"z" : "77f00aef1c966167" ,
"name" : "3. Operator demand (manual mode only)" ,
"style" : {
"stroke" : "#666666" ,
"fill" : "#ffdf7f" ,
"fill-opacity" : "0.15" ,
"label" : true ,
"color" : "#333333"
} ,
"nodes" : [
"48c2262c345c46b9"
] ,
"x" : 94 ,
"y" : 479 ,
"w" : 261 ,
"h" : 82
} ,
{
"id" : "234bdce20170061a" ,
"type" : "group" ,
"z" : "77f00aef1c966167" ,
"name" : "4. Calibration" ,
"style" : {
"stroke" : "#666666" ,
"fill" : "#ffdf7f" ,
"fill-opacity" : "0.15" ,
"label" : true ,
"color" : "#333333"
} ,
"nodes" : [
"463eefdd54df89a5" ,
"2e0642275899fc79"
] ,
"x" : 94 ,
"y" : 599 ,
"w" : 272 ,
"h" : 122
} ,
{
"id" : "f4ba4542514ed853" ,
"type" : "group" ,
"z" : "77f00aef1c966167" ,
"name" : "Expected outputs" ,
"style" : {
"stroke" : "#666666" ,
"fill" : "#d1d1d1" ,
"fill-opacity" : "0.2" ,
"label" : true ,
"color" : "#333333"
} ,
"nodes" : [
"b2450e5ee2eebfaa" ,
"386af1ad8aa8ed12" ,
"c27c2655f199b530"
] ,
"x" : 874 ,
"y" : 299 ,
"w" : 252 ,
"h" : 202
} ,
{
"id" : "b30af582f935bcb7" ,
"type" : "comment" ,
"z" : "77f00aef1c966167" ,
"name" : "PumpingStation — Basic (Tier 1)" ,
"info" : "Single pumpingStation node driven by inject buttons. Shows the canonical msg.topic command surface.\n\nDefault controlMode = levelbased. Switch to manual to honour set.demand.\n\nHOW TO USE\n1. Deploy the flow.\n2. (optional) Click \"set.mode = manual\" if you want set.demand to forward; otherwise leave it on levelbased and the ramp drives demand from level.\n3. Click \"set.inflow = 60 m³/h\" to push wastewater into the basin.\n4. Watch the basin fill on Port 0 (level, volume rise) and Port 1 (InfluxDB-shaped payload).\n5. In manual mode: click \"set.demand = 40\" — the value surfaces as `manualDemand` on Port 0/1 and in the node status badge.\n6. Click \"calibrate volume 25 m³\" or \"calibrate level 1.5 m\" to snap the predicted-volume integrator.\n\nPORTS\n- Port 0: process output (changed fields only)\n- Port 1: InfluxDB-shaped {measurement, fields, tags, timestamp}\n- Port 2: parent registration (child handshake)" ,
"x" : 650 ,
"y" : 300 ,
"wires" : [ ]
} ,
{
"id" : "1155bbbde7c65363" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "4996420d47442fad" ,
"name" : "set.mode = manual" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"v" : "manual" ,
"vt" : "str"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "set.mode" ,
"x" : 230 ,
"y" : 160 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "e9bea0f95b557f5d" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "4996420d47442fad" ,
"name" : "set.mode = levelbased" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"v" : "levelbased" ,
"vt" : "str"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "set.mode" ,
"x" : 240 ,
"y" : 200 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "7b2b5eb919b1ab15" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "a9f9b38b0e00c1d7" ,
"name" : "set.inflow = 60 m3/h" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"v" : "60" ,
"vt" : "num"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "set.inflow" ,
"x" : 240 ,
"y" : 360 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "48c2262c345c46b9" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "42bf82c87d05f498" ,
"name" : "set.demand = 40 %" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"v" : "40" ,
"vt" : "num"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "set.demand" ,
"x" : 230 ,
"y" : 520 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "463eefdd54df89a5" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "234bdce20170061a" ,
"name" : "calibrate volume 25 m3" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"v" : "25" ,
"vt" : "num"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "cmd.calibrate.volume" ,
"x" : 240 ,
"y" : 640 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "2e0642275899fc79" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "234bdce20170061a" ,
"name" : "calibrate level 1.5 m" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload" ,
"v" : "1.5" ,
"vt" : "num"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "cmd.calibrate.level" ,
"x" : 240 ,
"y" : 680 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "b2450e5ee2eebfaa" ,
"type" : "debug" ,
"z" : "77f00aef1c966167" ,
"g" : "f4ba4542514ed853" ,
"name" : "Port 0: Process" ,
"active" : true ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "payload" ,
"targetType" : "msg" ,
"x" : 980 ,
"y" : 340 ,
"wires" : [ ]
} ,
{
"id" : "386af1ad8aa8ed12" ,
"type" : "debug" ,
"z" : "77f00aef1c966167" ,
"g" : "f4ba4542514ed853" ,
"name" : "Port 1: InfluxDB" ,
"active" : true ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 980 ,
"y" : 400 ,
"wires" : [ ]
} ,
{
"id" : "c27c2655f199b530" ,
"type" : "debug" ,
"z" : "77f00aef1c966167" ,
"g" : "f4ba4542514ed853" ,
"name" : "Port 2: Parent reg" ,
"active" : true ,
"tosidebar" : true ,
"console" : false ,
"tostatus" : false ,
"complete" : "true" ,
"targetType" : "full" ,
"x" : 990 ,
"y" : 460 ,
"wires" : [ ]
} ,
{
"id" : "8e78b6607deb33a7" ,
"type" : "pumpingStation" ,
"z" : "77f00aef1c966167" ,
"g" : "aa3381b896eb2cfb" ,
"name" : "" ,
"simulator" : false ,
"basinVolume" : 50 ,
"basinHeight" : 4 ,
"inflowLevel" : 1.5 ,
"outflowLevel" : 0.2 ,
"overflowLevel" : 3.8 ,
"defaultFluid" : "wastewater" ,
"inletPipeDiameter" : 0.3 ,
"outletPipeDiameter" : 0.3 ,
"pipelineLength" : 80 ,
"maxDischargeHead" : 24 ,
"staticHead" : 12 ,
"maxInflowRate" : 200 ,
"temperatureReferenceDegC" : 15 ,
"timeleftToFullOrEmptyThresholdSeconds" : 0 ,
"enableDryRunProtection" : true ,
"enableHighVolumeSafety" : true ,
"enableOverfillProtection" : true ,
"dryRunThresholdPercent" : 2 ,
"highVolumeSafetyThresholdPercent" : 98 ,
"overfillThresholdPercent" : 98 ,
"minHeightBasedOn" : "outlet" ,
"processOutputFormat" : "process" ,
"dbaseOutputFormat" : "influxdb" ,
"refHeight" : "NAP" ,
"basinBottomRef" : 1 ,
"uuid" : "" ,
"supplier" : "" ,
"category" : "" ,
"assetType" : "" ,
"model" : "" ,
"unit" : "" ,
"enableLog" : false ,
"logLevel" : "error" ,
"positionVsParent" : "atEquipment" ,
"positionIcon" : "⊥" ,
"hasDistance" : false ,
"distance" : "" ,
"controlMode" : "levelbased" ,
"levelCurveType" : "linear" ,
"logCurveFactor" : 9 ,
"enableShiftedRamp" : false ,
"shiftLevel" : 0 ,
"shiftArmPercent" : 95 ,
"startLevel" : 1 ,
"stopLevel" : 0.5 ,
"minLevel" : 0.20400000000000001 ,
"maxLevel" : 3.8 ,
"flowSetpoint" : null ,
"flowDeadband" : null ,
"x" : 650 ,
"y" : 400 ,
"wires" : [
[
"b2450e5ee2eebfaa"
] ,
[
"386af1ad8aa8ed12"
] ,
[
"c27c2655f199b530"
]
]
} ,
{
"id" : "3350187815774b95" ,
"type" : "inject" ,
"z" : "77f00aef1c966167" ,
"g" : "a9f9b38b0e00c1d7" ,
"name" : "set.outflow= 80 m3/h" ,
"props" : [
{
"p" : "topic" ,
"vt" : "str"
} ,
{
"p" : "payload"
}
] ,
"repeat" : "" ,
"crontab" : "" ,
"once" : false ,
"onceDelay" : "" ,
"topic" : "set.outflow" ,
"payload" : "80" ,
"payloadType" : "num" ,
"x" : 230 ,
"y" : 320 ,
"wires" : [
[
"8e78b6607deb33a7"
]
]
} ,
{
"id" : "ef77c1819422a098" ,
"type" : "global-config" ,
"env" : [ ] ,
"modules" : {
"EVOLV" : "1.0.29"
}
}
]