Files
settler/wiki/Reference-Examples.md
znetsixe d54cb66105 docs(wiki): full 5-page wiki matching the rotatingMachine reference format
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>
2026-05-19 09:42:12 +02:00

8.1 KiB
Raw Blame History

Reference — Examples

code-ref

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

  1. Open the Node-RED editor at http://localhost:1880.
  2. Menu → Import → drag the JSON file.
  3. 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:

  1. Deploy the flow.

  2. Send data.influent with 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 = 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 refers to.
    • F_eff = 0. The clarified-effluent envelope carries zero flow but still has its C vector (with species 712 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:

# 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.


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