> **Reflects code as of `e27135b` · regenerated `2026-05-11` via `npm run wiki:all`**
> If this banner is stale, the page may be out of date. Treat as informative, not authoritative.
## 1. What this node is
**valve** models a single throttling valve. It loads a supplier characteristic curve (Kv-vs-position), drives an FSM-style move sequence for opening/closing, and recomputes pressure drop across the valve from current flow + Kv. Used standalone or as a child of `valveGroupControl` when grouped.
valve overrides BaseDomain's default `registerChild` with `FluidCompatibility.registerChild` so upstream-source contracts feed the fluid aggregator. Measurement children attach through the generic measurement handshake.
What lands on Port 0. Composed in `io/output.buildOutput`, then delta-compressed by `outputUtils.formatMsg`.
<!-- BEGIN AUTOGEN: data-model -->
| Key | Type | Unit | Sample |
|---|---|---|---|
| `state` | string | — | `"operational"` |
| `percentageOpen` | number | % | `0` |
| `moveTimeleft` | number | s | `0` |
| `mode` | string | — | `"auto"` |
| `downstream_predicted_flow` | number | m3/h | `0` |
| `downstream_measured_flow` | number | m3/h | _(emitted when measurement child present)_ |
| `downstream_predicted_pressure` | number | mbar | _(emitted when upstream pressure present)_ |
| `downstream_measured_pressure` | number | mbar | _(emitted when measurement child present)_ |
| `delta_predicted_pressure` | number | mbar | `0` |
<!-- END AUTOGEN: data-model -->
Measurement-derived keys follow the legacy `<position>_<variant>_<type>` shape (e.g. `downstream_predicted_flow`, `delta_predicted_pressure`) and are emitted only when the container holds a finite value.
## 9. Configuration — editor form ↔ config keys
```mermaid
flowchart TB
subgraph editor["Node-RED editor form"]
f1[Mode]
f2[Asset model]
f3[Service type]
f4[Diameter]
f5[Fluid density / temperature]
f6[Inline valveCurve override]
end
subgraph config["Domain config slice"]
c1[mode.current]
c2[asset.model]
c3[asset.serviceType]
c4[asset.valveDiameter]
c5[asset.fluidDensity / fluidTemperatureK]
c6[asset.valveCurve]
end
f1 --> c1
f2 --> c2
f3 --> c3
f4 --> c4
f5 --> c5
f6 --> c6
```
| Form field | Config key | Default | Range | Where used |
| Fluid density | `asset.fluidDensity` | model default | > 0 (kg/m³) | hydraulic formula |
| Fluid temperature | `asset.fluidTemperatureK` | model default | > 0 (K) | hydraulic formula |
| Choked-flow cap | `asset.gasChokedRatioLimit` | per asset | 0–1 | gas formula clamp |
## 10. State chart
```mermaid
stateDiagram-v2
[*] --> off
off --> idle: cmd.startup
idle --> opening: set.position > 0
opening --> operational: position reached
operational --> opening: set.position changed
operational --> closing: set.position < current
closing --> closed: position == 0
closed --> opening: set.position > 0
operational --> stopping: cmd.shutdown (ramps to 0)
stopping --> idle: cooldown elapsed
operational --> emergencystop: cmd.estop
emergencystop --> off: cmd.reset
```
The `opening` / `closing` states cover the move-in-progress window; `positionChange` ticks fire until the setpoint is reached, then the FSM lands on `operational`. Pre-shutdown ramp to 0 is enforced by `FlowController.executeSequence('shutdown')`.
Screenshots under `wiki/_partial-screenshots/valve/` when produced. Docker compose snippet under `examples/README.md`.
## 12. Debug recipes
| Symptom | First thing to check | Where to look |
|---|---|---|
| Status badge shows `⚠ no input` | Did any pressure / flow measurement register? Watch Port 2. | Editor debug tap on Port 2 |
| `delta_predicted_pressure` stuck at zero | Is `kv > 0`? FSM may be in `off` / `closed`. | `state.getCurrentState()` |
| Gas mismatch warning on status badge | `fluidCompatibility.status` is `mismatch` / `conflict`. | `getFluidCompatibility()` |
| `query.curve` returns empty curve | Asset model not found by `loadModel`; fallback to `config.asset.valveCurve`. | `SupplierCurvePredictor.snapshot()` |
| deltaP non-finite | Downstream gauge pressure absolute term ≤ 0, or choked ratio reached. | `hydraulicDiagnostics` |
> Never ship `enableLog: 'debug'` in a demo — fills the container log within seconds and obscures real errors. Use only for live debugging.
## 13. When you would NOT use this node
- Use valve for a **throttling element** with a known Kv curve. For a fixed-restriction orifice with no actuator, model the deltaP externally.
- Don't use valve to model a non-return / check valve — no position control or curve fitting is exposed.
- Skip valve when an upstream source provides flow directly and no pressure-drop estimate is needed; just wire the source straight to the parent.
## 14. Known limitations / current issues
| # | Issue | Tracked in |
|---|---|---|
| 1 | Gas-choke detection is a hard cap, not a smooth transition — chart traces show a step at the choked-ratio limit. | `hydraulicModel.js` |
| 2 | Multi-parent registration is allowed but not exercised in production tests. | CONTRACT.md `## Children registered by this node` |
| 3 | `set.position` move sequences are interruptible but tests cover happy-path only. | P10 test-suite refactor |