Files
pumpingStation/examples/01-Basic.json
znetsixe fe5fa3577b 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

479 lines
12 KiB
JSON

[
{
"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."
},
{
"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"
}
}
]