From 53705a6bd497d661873d62da37913da65d2266c5 Mon Sep 17 00:00:00 2001 From: znetsixe Date: Tue, 12 May 2026 15:24:33 +0200 Subject: [PATCH] =?UTF-8?q?Home=20=C2=A711:=20replace=20stub-flow=20table?= =?UTF-8?q?=20with=2001-Basic=20+=2002-Dashboard;=20=C2=A714=20update?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - §11 Examples: shipped-files table reduced to the two real flows (basic with 3 pumps + dashboard with FlowFuse 2.0 widgets + charts); links to examples/README.md. Adds a placeholder for editor + rendered screenshots to drop in once captured. - §14 #4: TODO "example flows not yet written" replaced with the genuine current limitation — Port 0 only exposes group aggregates, no per-pump flow / power series. Co-Authored-By: Claude Opus 4.7 (1M context) --- Home.md | 43 +++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/Home.md b/Home.md index abcf383..3671548 100644 --- a/Home.md +++ b/Home.md @@ -1,6 +1,6 @@ # machineGroupControl -> **Reflects code as of `afc304b` · regenerated `2026-05-11` via `npm run wiki:all`** +> **Reflects code as of `7d19fc1` · regenerated `2026-05-11` via `npm run wiki:all`** > If this banner is stale, the page may be out of date. Treat as informative, not authoritative. ## 1. What this node is @@ -41,7 +41,7 @@ S88 colours: Process Cell `#0c99d9`, Unit `#50a8d9`, Equipment `#86bbdd`, Contro | Optimal control | ✅ | `mode='optimalcontrol'`. | | Group efficiency + BEP distance | ✅ | `GroupEfficiency`. | | Header-pressure equalisation | ✅ | `operatingPoint.equalize()`. | -| Demand serialisation (latest-wins) | ✅ | Inline gate; deferred call drains on completion. | +| Demand serialisation (latest-wins) | ✅ | `DemandDispatcher` / `LatestWinsGate.fireAndWait`. | | Forced shutdown on `Qd ≤ 0` | ✅ | `turnOffAllMachines()`. | ## 4. Code map @@ -60,7 +60,8 @@ flowchart TB combi["combinatorics/
validPumpCombinations"] opt["optimizer/
BEP-Grav / NCog selectors"] efficiency["efficiency/
GroupEfficiency + BEP dist"] - dispatch["control/
strategies (equalFlow / prioPct)"] + ctrl["control/
strategies (equalFlow / prioPct)"] + dispatch["dispatch/
DemandDispatcher (LatestWinsGate)"] io["io/
output + status"] commands["commands/
topic registry + handlers"] end @@ -70,6 +71,7 @@ flowchart TB sc --> combi sc --> opt sc --> efficiency + sc --> ctrl sc --> dispatch sc --> io nc --> commands @@ -83,7 +85,7 @@ flowchart TB | `optimizer/` | Best-combination selectors | Optimiser selection method, scoring math. | | `efficiency/` | Group efficiency, BEP distance | BEP gravitation tuning, peak math. | | `control/strategies.js` | Per-mode dispatch (priority, prioPct) | Mode behaviour, priorityList usage. | -| `dispatch/` | Demand fan-out helpers (legacy alongside inline gate) | Serialisation, mid-flight overrides. | +| `dispatch/` | `DemandDispatcher` wrapping `LatestWinsGate.fireAndWait` | Demand serialisation, mid-flight overrides. | | `commands/` | Input-topic registry and handlers | New input topics, payload validation. | | `io/` | `getOutput`, `getStatusBadge` | Output shape, dashboard badge. | @@ -175,16 +177,17 @@ What lands on Port 0. Composed in `io/output.js → getOutput(this)` and delta-c { "mode": "optimalcontrol", "scaling": "normalized", - "flow.predicted.atequipment.": 0.0125, - "flow.predicted.downstream.": 0.0125, - "power.predicted.atequipment.": 1800, - "efficiency.predicted.atequipment.": 0.65, + "atEquipment_predicted_flow": 42.5, + "downstream_predicted_flow": 42.5, + "atEquipment_predicted_power": 18.0, + "atEquipment_predicted_efficiency": 0.65, + "atEquipment_predicted_Ncog": 1.23, "absDistFromPeak": 0.02, "relDistFromPeak": 0.10 } ~~~ -The `` segment is the Node-RED node id assigned at deploy time. +Key format from `io/output.js`: `__` (e.g. `atEquipment_predicted_flow`). Output units: flow in `m3/h`, power in `kW`, pressure in `mbar`. ## 9. Configuration — editor form ↔ config keys @@ -236,17 +239,19 @@ stateDiagram-v2 turning_off --> idle_disp: all machines acknowledged shutdown ``` -While `dispatching`, additional `handleInput` calls overwrite `_delayedCall` (latest-wins); the gate drains the latest one on completion. `turnOffAllMachines()` clears `_delayedCall` to make turn-off the final intent. +While `dispatching`, additional `handleInput` calls are absorbed by `DemandDispatcher` (latest-wins). A superseded call resolves with `{ superseded: true }`. `turnOffAllMachines()` calls `cancelPending()` so turn-off is always the final intent. ## 11. Examples -| Tier | File | What it shows | Status | -|---|---|---|---| -| Basic | `examples/basic.flow.json` | Single MGC + 2 pumps, manual setDemand | ⚠️ legacy shape, pre-refactor | -| Integration | `examples/integration.flow.json` | MGC wired under pumpingStation | ⚠️ legacy shape, pre-refactor | -| Edge | `examples/edge.flow.json` | Mid-flight demand override + abort | ⚠️ legacy shape, pre-refactor | +| Tier | File | What it shows | +|---|---|---| +| 1 | `examples/01-Basic.json` | One MGC + three `rotatingMachine` pumps driven by inject buttons. Setup auto-fires `virtualControl` + `cmd.startup` on all three pumps; numbered driver groups for mode / scaling / demand. | +| 2 | `examples/02-Dashboard.json` | Same command surface driven by a FlowFuse Dashboard 2.0 page — Mode + Scaling buttons, Demand slider, live Status rows (mode / scaling / total flow / total power / capacity / active machines / BEP %), three trend charts, and a raw-output table. | -Tier 1/2/3 visual-first example flows are still TODO (see `MEMORY.md` "TODO: Example Flows"). Screenshots will land under `wiki/_partial-screenshots/machineGroupControl/` when the new flows ship. +See [`examples/README.md`](https://gitea.wbd-rd.nl/RnD/machineGroupControl/src/branch/development/examples/README.md) for the canonical command surface table and step-by-step "what to try" recipes. + +> [!IMPORTANT] +> **Screenshots needed.** Capture both flows in the editor + the rendered dashboard. Save under `wiki/_partial-screenshots/machineGroupControl/` as `01-basic-flow.png`, `02-dashboard-editor.png`, `03-dashboard-rendered.png`. Replace this callout with the image links. ## 12. Debug recipes @@ -255,7 +260,7 @@ Tier 1/2/3 visual-first example flows are still TODO (see `MEMORY.md` "TODO: Exa | No combination selected | Demand outside `[dynamicTotals.flow.min, max]` — clamped on entry; `_optimalControl` returns early if combinations empty. | `validPumpCombinations` + warn log. | | Group flow stuck at zero | Machines never reach an `ACTIVE_STATE` — check per-pump startup logs. | `isMachineActive`. | | Priority-percentage mode warns and exits | Mode requires `scaling='normalized'`. Set both. | `_runDispatch` switch. | -| Stale flow setpoints on chained calls | Dispatch gate may have collapsed multiple calls — confirm `_delayedCall` was honoured. | `handleInput` finally block. | +| Stale flow setpoints on chained calls | Dispatch gate may have superseded intermediate calls — callers should check `result.superseded`. | `DemandDispatcher` / `LatestWinsGate`. | | Header pressure not equalising | Pressure children must register with `asset.type='pressure'` and a matching position. | `operatingPoint.equalize`. | | Optimiser picks unexpected combo | Verify `optimization.method` and per-method scoring (NCog vs BEP-Grav). | `optimizer/`. | @@ -274,4 +279,6 @@ Tier 1/2/3 visual-first example flows are still TODO (see `MEMORY.md` "TODO: Exa | 1 | `optimalControl` requires every machine to expose a curve — null-curve members silently exclude themselves from combinations. | `combinatorics/pumpCombinations`. | | 2 | Mid-flight setpoint overrides on `accelerating` / `decelerating` rely on `abortActiveMovements` per dispatch — a sequence with no awaitable `abortMovement` will warn but proceed. | `abortActiveMovements`. | | 3 | Power-cap parameter exposed but not surfaced as a topic input — only programmatic via `handleInput(source, demand, powerCap)`. | `commands/index.js` — no canonical topic. | -| 4 | Tier 1/2/3 visual-first example flows not yet written. | P9 follow-up. | +| 4 | Per-pump fan-out for dashboard charts (per-machine flow / power series) not surfaced from MGC's Port 0 — only group aggregates appear. Subscribe to each rotatingMachine's Port 0 if you need per-pump trends. | `io/output.js` aggregates only. | +| 5 | **`maxEfficiency` naming bug** — `GroupEfficiency.calcGroupEfficiency` returns `{ maxEfficiency, lowestEfficiency }` but `maxEfficiency` is actually the **mean cog** across all machines (not the maximum). The name is deliberately preserved for behavioural parity; callers using it as "the peak" will over-estimate the BEP target. | `efficiency/groupEfficiency.js` comment + `OPEN_QUESTIONS.md` 2026-05-10. | +| 6 | **`calcAbsoluteTotals` implicit pressure-key coupling** — iterates `machine.predictFlow.inputCurve` and re-uses the same pressure key to index `machine.predictPower.inputCurve[pressure]`. If the two curves were sampled at different pressures the lookup is `undefined` and the call throws. Enforcement or defensive skip deferred to P5 (rotatingMachine curveLoader). | `totals/totalsCalculator.js` + `OPEN_QUESTIONS.md` 2026-05-10. |