# Reference — Examples ![code-ref](https://img.shields.io/badge/code--ref-b884c0f-blue) > [!NOTE] > Every example flow shipped under `nodes/measurement/examples/`, plus how to load them, what they show, and the debug recipes that go with them. Live source: `nodes/measurement/examples/`. > > Pending full node review (2026-05). Tier-1/2/3 visual-first example flows are still TODO (tracked in the superproject `MEMORY.md` "TODO: Example Flows"). The current shipped flows pre-date the refactor; treat them as smoke tests, not as production templates. --- ## Shipped examples | File | Tier | Dependencies | What it shows | Status | |:---|:---:|:---|:---|:---| | `basic.flow.json` | 1 | EVOLV only | Single measurement node driven by inject buttons — analog scalar input, scaling enabled, three debug taps on Port 0/1/2. | Legacy pre-refactor shape, still imports. | | `integration.flow.json` | 2 | EVOLV only | Parent-child wiring — measurement registers as a child of another node and emits its `.measured.` events. | Legacy pre-refactor shape. | | `edge.flow.json` | 3 | EVOLV only | Invalid / edge payload driving for robustness checks (non-numeric strings, object in analog mode, …). | Legacy pre-refactor shape. | The three legacy files predate the AssetResolver refactor and the analog-vs-digital mode flag. They still deploy (the editor will accept the older shape and `nodeClass.buildDomainConfig` reshapes whatever it finds), but the recommended Tier-1/2/3 visual-first replacements are still to be written. > [!IMPORTANT] > **TODO — Tier-1/2/3 visual-first flows.** Replace the three legacy files with: > - `01 - Basic Analog.json` — one measurement, inject + scaling + smoothing + outlier-detection toggle + simulator. > - `02 - Integration with rotatingMachine.json` — measurement registered as a pressure sensor on a `rotatingMachine`, Port 2 auto-register on deploy, parent's prediction updates as the measurement value moves. > - `03 - Digital Multi-Channel.json` — one measurement in `digital` mode with 2–3 channels (e.g. `level-a`, `temp-a`, `flow-a`) fed by a single object-payload inject. --- ## 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/measurement/examples/basic.flow.json \ http://localhost:1880/flows ``` --- ## Example — `basic.flow.json` Single-measurement flow with the minimum kit to exercise scaling. ### Nodes on the tab | Type | Purpose | |:---|:---| | `inject` | One-shot `topic: 'measurement', payload: 42` (legacy alias of `data.measurement`) | | `measurement` | The unit under test — analog mode, scaling enabled (0..100 → 0..10), `mean` smoothing, window 5 | | `debug` × 3 | Port 0 (process), Port 1 (InfluxDB), Port 2 (registration) | ### What to do after deploy 1. Click the inject. Port 0 fires with `mAbs ≈ 4.2` (42 scaled into 0..10), `mPercent ≈ 42`. 2. Send another value via the same inject (edit the inject payload to `60`). `totalMinValue` / `totalMaxValue` start tracking, `mAbs` jumps to ~6.0. 3. Send `topic: 'set.simulator'` (use a second inject). `tick()` starts driving `inputValue` through `Simulator.step()` every 1000 ms; Port 0 updates appear automatically. 4. Send `topic: 'cmd.calibrate'`. If `stdDev <= 0.01` (the default `stabilityThreshold`), `config.scaling.offset` jumps to `inputMin - currentOutput`; if not, a warn appears in the log. 5. Send `topic: 'set.outlier-detection'`, then inject a wildly out-of-band value (e.g. `9999`). With outlier detection on the value is dropped with `Outlier detected. Ignoring value=9999`. > [!IMPORTANT] > **Screenshot needed.** Editor capture of `basic.flow.json` plus the Port 0 debug output. Save as `wiki/_partial-screenshots/measurement/basic-flow.png`. Replace this callout with the image link. --- ## Example — `integration.flow.json` Demonstrates the parent-child handshake: the measurement node's Port 2 auto-fires `child.register` to its parent on deploy, and the parent then receives the `.measured.` event whenever a new reading lands. > [!IMPORTANT] > **Screenshot needed.** Editor capture of `integration.flow.json` showing the wiring. Save as `wiki/_partial-screenshots/measurement/integration-flow.png`. > [!NOTE] > TODO: confirm the integration flow targets a real EVOLV parent (e.g. `rotatingMachine`) versus a mock function node; if it's a mock, the Tier-2 replacement should use a real parent. --- ## Example — `edge.flow.json` Drives the node with malformed inputs to verify the warn paths land cleanly: - Non-numeric string in analog mode → `Invalid numeric measurement payload: `. - Object payload in analog mode → `analog mode received an object payload (keys: …). Switch Input Mode to 'digital' …`. - Numeric scalar in digital mode → `digital mode received a number (…); expected an object …`. - Outlier toggle on/off mid-stream → verifies `analogChannel.outlierDetection.enabled` mirrors `config.outlierDetection.enabled`. > [!IMPORTANT] > **Screenshot needed.** Editor capture of `edge.flow.json` plus the log lines each inject triggers. Save as `wiki/_partial-screenshots/measurement/edge-flow.png`. --- ## Debug recipes | Symptom | First thing to check | Where to look | |:---|:---|:---| | Parent never receives `.measured.` | `asset.type` must match the parent's filter exactly (e.g. `flow` — not `flow-electromagnetic`). Position labels lowercase in the event name. | `config.asset.type` + parent's `childRegistrationUtils` filter. | | Outliers seem to pass through | `outlierDetection.enabled` may be off (default `false`). Toggle with `set.outlier-detection`. With `<2` samples in the buffer, `_isOutlier` returns `false` regardless. | `Channel._isOutlier`. | | `cmd.calibrate` does nothing | Calibrator requires `stdDev <= calibration.stabilityThreshold` over `storedValues`. If `storedValues.length < 2`, `isStable()` returns `false` (legacy shape). | `src/calibration/calibrator.js` `isStable`, `calibrate`. | | Digital payload silently dropped | Unknown channel keys are reported only at `debug` log level (`digital payload contained unmapped keys`). Numeric values that fail `Number.isFinite` warn at `warn`. | `Measurement.handleDigitalPayload`. | | Simulator still running after toggle off | `tick()` reads `config.simulation.enabled` each tick. Confirm the toggle actually mutated the config (the `set.simulator` handler is idempotent — it just flips). | `Measurement.tick`, `toggleSimulation`. | | Port 0 emits nothing after `data.measurement` | Analog: `_writeOutput` only emits when `rounded !== outputAbs`. A repeated identical value is silent by design. | `Channel._writeOutput`. | | `mPercent` is stuck at `0` or unbounded | `processRange <= 0` (i.e. `absMax <= absMin`); percent falls back to `totalMinValue / totalMaxValue` which start at `0` / `0`. Configure `absMin < absMax`. | `Channel._computePercent`. | | Scaling output looks clamped | `_applyScaling` clamps the input to `[inputMin, inputMax]` before mapping. Wide-band sensors need `inputMin / inputMax` set to the full physical range. | `Channel._applyScaling`. | | `mAbs` jumps after `cmd.calibrate` | Expected. Calibration sets `config.scaling.offset = baseline - currentOutputAbs`, which makes the next reading land on the baseline (`inputMin` when scaling enabled, `absMin` otherwise). | `Calibrator.calibrate`. | | Legacy `setpoint` / `simulator` topics work without warning | First fire emits a one-time deprecation warning via `BaseNodeAdapter`'s alias handling. Subsequent fires are silent — the topic still works. | `commands/index.js` `aliases`. | > Never ship `enableLog: 'debug'` in a demo — fills the container log within seconds and obscures real errors. --- ## 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). --- ## Related pages | Page | Why | |:---|:---| | [Home](Home) | Intuitive overview | | [Reference — Contracts](Reference-Contracts) | Topic + config + child registration | | [Reference — Architecture](Reference-Architecture) | Code map + per-`Channel` pipeline + lifecycle | | [Reference — Limitations](Reference-Limitations) | Known issues and open questions | | [rotatingMachine — Examples](https://gitea.wbd-rd.nl/RnD/rotatingMachine/wiki/Reference-Examples) | Most common consumer of measurement | | [EVOLV — Topology Patterns](https://gitea.wbd-rd.nl/RnD/EVOLV/wiki/Topology-Patterns) | Where measurement fits in a larger plant |