Node-RED custom node for sensor signal conditioning. Takes raw input — either a single scalar (analog mode) or an MQTT-style JSON object with many keys (digital mode) — and produces scaled, smoothed, outlier-filtered measurements. Part of the [EVOLV](https://gitea.wbd-rd.nl/RnD/EVOLV) wastewater-automation platform.
Registers itself on port 2 as a child of a parent equipment (rotatingMachine, pumpingStation, reactor, etc.). The parent consumes measurements via shared `MeasurementContainer` events.
Or pull the whole platform via the superproject. Restart Node-RED and the node appears in the palette under **EVOLV**.
## Two input modes
### Analog mode (default)
One scalar per message — the classic PLC / 4-20mA pattern.
```json
{ "topic": "measurement", "payload": 42 }
```
The node runs one offset → scaling → smoothing → outlier pipeline and emits exactly one MeasurementContainer slot. Every existing flow built before digital mode keeps working unchanged.
Each key maps to its own **channel** with independently-configured scaling, smoothing, outlier detection, type, position, unit, and distance. A single inbound message therefore emits N MeasurementContainer slots — one per channel — so a downstream parent sees everything at once.
Pick the mode in the editor or via `msg.mode`. Analog is the default; digital requires populating `channels` (see *Configuration*).
## Input topics
| Topic | Payload | Effect |
|---|---|---|
| `measurement` | analog mode: `number` or numeric `string` — stored as `inputValue` and consumed on the next tick. digital mode: `object` keyed by channel names. | drives the pipeline |
| 2 | `parent` | `{topic:"registerChild", payload:<nodeId>, positionVsParent, distance}` emitted once ~180ms after deploy |
## Configuration
### Common (both modes)
- **Asset** (menu): supplier, category, `assetType` (measurement type in the container — `pressure`, `flow`, `temperature`, `power`, or any user-defined type like `humidity`), model, unit.
`scaling`, `smoothing`, `outlierDetection` are optional — the node falls back to the top-level analog-mode equivalents when missing. `key` is the JSON field name inside `msg.payload`; `type` is the MeasurementContainer axis (can be any string — unknown types are accepted).
## State and emit contract
Every channel runs the same pipeline: `outlier → offset → scaling → smoothing → min/max tracking → constrain → emit`. Output is rounded to two decimals. MeasurementContainer events follow the pattern `<type>.<variant>.<position>` all lowercase, e.g. `temperature.measured.atequipment`.
Unknown measurement types (anything not in the container's built-in measureMap — `pressure`, `flow`, `power`, `temperature`, `volume`, `length`, `mass`, `energy`) are accepted without unit compatibility checks. Known types still validate strictly.
## Testing
```bash
cd nodes/measurement
npm test
```
71 tests cover every smoothing method, every outlier strategy, scaling, interpolation, constrain, calibration, stability, simulation, output-percent fallback, per-channel pipelines, digital payload dispatch, registration events, and example-flow shape.
## Production status
Last reviewed **2026-04-13**. See the project memory file `node_measurement.md` for the current verdict, benchmarks, and wishlist.
## License
SEE LICENSE. Author: Rene De Ren, Waterschap Brabantse Delta R&D.