Replaces the prior stub/partial wiki with a Home + Reference-{Architecture,
Contracts,Examples,Limitations} + _Sidebar structure. Topic-contract and
data-model sections wrapped in AUTOGEN markers for the future wiki-gen tool.
Source-vs-spec contradictions surfaced and flagged inline (not silently
fixed). Pending-review notes mark sections that need a full node review.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8.1 KiB
Reference — Examples
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.
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
- Open the Node-RED editor at
http://localhost:1880. - Menu → Import → drag the JSON file.
- Click Deploy.
Via the Admin API
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:
-
Deploy the flow.
-
Send
data.influentwith payload:{ "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 = 3000mg/L. -
Observe three Port-0 messages arrive simultaneously, each with
topic = "Fluent"andpayload.inlet∈ {0, 1, 2}. -
With default
C_TS = 2500mg/L:F_s = 1000 * 3000 / 2500 = 1200— but clamped toF_in = 1000. The clamp fires — this is the input edge case Reference — Limitations — no-flow-balance warning refers to.F_eff = 0. The clarified-effluent envelope carries zero flow but still has itsCvector (with species 7–12 zeroed).F_sris 0 (no pump wired) →F_surplus = 1000,F_return = 0.
-
Send
data.influentwithX_TS = 1500mg/L instead. NowF_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:
# 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.
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 <type>) and short-circuits. |
src/commands/handlers.js#dataInfluent. |
Settler logs an error Type '<x>' 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=<x> |
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 | Intuitive overview |
| Reference — Contracts | Topic + config + child filters |
| Reference — Architecture | Code map, reactor ↔ settler wiring, mass-balance math |
| Reference — Limitations | Known issues and open questions |
| reactor — Examples | The upstream parent — how to drive stateChange |
| EVOLV — Topology Patterns | Where settler fits in a larger plant |