# Reference — Examples ![code-ref](https://img.shields.io/badge/code--ref-a3583a3-blue) > [!NOTE] > Pending full node review (2026-05). The shipped example flows are **stub level**: each is a 4-node skeleton (tab + node + inject + debug) that proves the node loads in Node-RED but does **not** exercise the reactor → settler → return-pump chain or the TSS mass-balance math. Production-grade examples are TODO. See [Reference — Limitations — Example flows](Reference-Limitations#example-flows-are-stub-level). --- ## Shipped examples | File | Tier | Dependencies | What it shows | |:---|:---:|:---|:---| | `basic.flow.json` | 1 (stub) | EVOLV only | Loads a single settler node, wires a `ping` inject to its input, taps Port 0 (only) to a debug node. Inject payload is the string `"1"` — will be rejected by `data.influent`'s payload validator (warn logged). Useful only to verify the node type registers. | | `integration.flow.json` | 2 (stub) | EVOLV only | Same shape; inject sends `topic = registerChild`, payload `example-child-id`. The lookup will fail (no such node) and log a warn. Does **not** exercise reactor or pump wiring. | | `edge.flow.json` | 3 (stub) | EVOLV only | Same shape; inject sends `topic = doesNotExist`. Verifies the registry rejects unknown topics. | ### Status | Aspect | State | |:---|:---| | Loads in Node-RED on deploy | yes | | Drives `data.influent` with a valid payload | no | | Drives the reactor → settler → return-pump chain | no | | Shows the 3-stream Fluent split on Port 0 | no | | Has a dashboard tier | no | | Validated against a live Node-RED instance | no | --- ## Loading a flow ### Via the editor 1. Open the Node-RED editor at `http://localhost:1880`. 2. Menu → Import → drag the JSON file. 3. Click Deploy. ### Via the Admin API ```bash curl -X POST -H 'Content-Type: application/json' \ --data @nodes/settler/examples/basic.flow.json \ http://localhost:1880/flows ``` --- ## TODO — production-grade example set The matching `rotatingMachine` repo ships three tiers; settler needs the same. Tracking placeholder: | Tier | Proposed filename | What it should show | |:---|:---|:---| | 1 | `01 - Basic Manual Influent.json` | Single settler + inject sending `data.influent` with a realistic `{F, C}` payload. Three debug taps (one per Port 0 stream by `payload.inlet`). Operator can vary F and watch the split rebalance. | | 2 | `02 - Reactor and Return Pump.json` | One `reactor` (upstream) + one `settler` + one `rotatingMachine` (return pump, downstream). Auto-registration via Port 2. Drive the reactor with an inject; settler should re-split on every reactor `stateChange`. | | 3 | `03 - Dashboard Visualization.json` | FlowFuse Dashboard 2.0 page: F_in / F_eff / F_surplus / F_return trend chart, C_TS gauge, status badges per stream. Required: `@flowfuse/node-red-dashboard` installed. | > [!IMPORTANT] > **Screenshots needed** once the production-grade examples land. Save as `wiki/_partial-screenshots/settler/01-basic-editor.png`, `02-reactor-pump-editor.png`, `03-dashboard-rendered.png`, ≤ 200 KB each. --- ## What the basic example would do (sketch — not yet shipped) Operator workflow once a real Tier-1 ships: 1. Deploy the flow. 2. Send `data.influent` with payload: ```json { "F": 1000, "C": [0,0,0,0,0,0,0,30,80,400,200,80,3000] } ``` Twelve soluble species at low concentrations + index 12 `X_TS = 3000` mg/L. 3. Observe three Port-0 messages arrive simultaneously, each with `topic = "Fluent"` and `payload.inlet` ∈ {0, 1, 2}. 4. With default `C_TS = 2500` mg/L: - `F_s = 1000 * 3000 / 2500 = 1200` — but clamped to `F_in = 1000`. **The clamp fires** — this is the input edge case [Reference — Limitations — no-flow-balance warning](Reference-Limitations#no-flow-balance-warning) refers to. - `F_eff = 0`. The clarified-effluent envelope carries zero flow but still has its `C` vector (with species 7–12 zeroed). - `F_sr` is 0 (no pump wired) → `F_surplus = 1000`, `F_return = 0`. 5. Send `data.influent` with `X_TS = 1500` mg/L instead. Now `F_s = 600`, `F_eff = 400`, `F_surplus = 600`, `F_return = 0`. Realistic split. > [!NOTE] > Pending full node review (2026-05). The clamp-fires behaviour above is intended (per code comment in `getEffluent`) but produces no operator-visible warning. Tracked. --- ## Docker compose snippet To bring up Node-RED + InfluxDB with EVOLV nodes pre-loaded: ```yaml # docker-compose.yml (extract) services: nodered: build: ./docker/nodered ports: ['1880:1880'] volumes: - ./docker/nodered/data:/data/evolv influxdb: image: influxdb:2.7 ports: ['8086:8086'] ``` Full file: [EVOLV/docker-compose.yml](https://gitea.wbd-rd.nl/RnD/EVOLV/src/branch/development/docker-compose.yml). --- ## Debug recipes > [!NOTE] > Pending full node review (2026-05). Recipes below are grounded in the source; the symptom-side has not been confirmed against a live deployment. | Symptom | First thing to check | Where to look | |:---|:---|:---| | `F_eff` negative or `NaN` | `C_TS` is zero or `Cs_in[12]` is huge. The `F_s` clamp should prevent negatives — confirm the clamp `min(..., F_in)` is present. Likely the clamp fires but masks a deeper input problem. | `src/specificClass.js#getEffluent` line `const F_s = Math.min(...)`. | | Settler never updates after reactor changes | Reactor child is not on `'upstream'` position (warn logged but registration proceeds), or the listener is attached to the wrong emitter. | `_connectReactor` — listens on `reactor.emitter`, **NOT** `reactor.measurements.emitter`. | | Return-sludge flow stays at 0 | `returnPump.measurements.type('flow').variant('measured').position('atEquipment')` has no current value. Wire a flow measurement child on the pump (with `asset.type='flow'`, `positionVsParent='atEquipment'`). | `_connectMachine`, pump's MeasurementContainer chain. | | Three Fluent envelopes do not arrive at the downstream consumer | `payload.inlet` selector on the downstream reactor / pump mismatches (0 = effluent, 1 = surplus, 2 = return). | The downstream consumer's inlet routing. | | `quantity (tss)` updates don't change `C_TS` | Measurement child's `asset.type` must be the literal string `"quantity (tss)"` (with the space + parenthesised "tss"). | `src/specificClass.js#_updateMeasurement` switch case. | | `data.influent` inject is silently dropped | Payload must be an object `{F, C}`. A string, number, or array logs a warn (`data.influent expects an object {F, C}; got `) and short-circuits. | `src/commands/handlers.js#dataInfluent`. | | Settler logs an `error` `Type '' not recognized for measured update.` | A measurement child has registered with an `asset.type` settler doesn't recognise. The re-emit still happened — the error is about the absence of a `_updateMeasurement` switch case. Currently only `quantity (tss)` mutates state. | `_updateMeasurement`. | | `child.register` topic logs `child.register skipped: missing child/source for id=` | The given node id doesn't resolve to a Node-RED node with a `.source` (i.e. an EVOLV domain). Verify the id is correct and the target node has already been deployed. | `src/commands/handlers.js#childRegister`. | | Status badge stuck on `idle: no influent` | `F_in <= 0`. Either no reactor has fired `stateChange` yet, or `data.influent` has not been sent with a positive `F`. | `src/specificClass.js#getStatusBadge`. | > Never ship `enableLog: 'debug'` in a demo — fills the container log within seconds and obscures real errors. --- ## Related pages | Page | Why | |:---|:---| | [Home](Home) | Intuitive overview | | [Reference — Contracts](Reference-Contracts) | Topic + config + child filters | | [Reference — Architecture](Reference-Architecture) | Code map, reactor ↔ settler wiring, mass-balance math | | [Reference — Limitations](Reference-Limitations) | Known issues and open questions | | [reactor — Examples](https://gitea.wbd-rd.nl/RnD/reactor/wiki/Reference-Examples) | The upstream parent — how to drive `stateChange` | | [EVOLV — Topology Patterns](https://gitea.wbd-rd.nl/RnD/EVOLV/wiki/Topology-Patterns) | Where settler fits in a larger plant |