Clone
3
Home
vps1_gitea_admin edited this page 2026-05-11 18:30:15 +00:00
This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

valve

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.

2. Position in the platform

flowchart LR
    vgc[valveGroupControl<br/>Unit]:::unit -->|set.position| this[valve<br/>Equipment]:::equip
    src[machine / MGC / PS<br/>upstream source]:::unit -->|child.register| this
    meas[measurement<br/>type=pressure / flow]:::ctrl -.data.-> this
    this -->|child.register| vgc
    this -->|evt.deltaPChange| vgc
    classDef unit fill:#50a8d9,color:#000
    classDef equip fill:#86bbdd,color:#000
    classDef ctrl fill:#a9daee,color:#000

S88 colours: Unit #50a8d9, Equipment #86bbdd, Control Module #a9daee. Source of truth: .claude/rules/node-red-flow-layout.md.

3. Capability matrix

Capability Status Notes
Predicts deltaP from flow + Kv Hydraulic model picks liquid vs gas formula per serviceType.
Loads supplier curve by model name asset.model resolved through loadModel; inline curve override supported.
Position move FSM opening / closing states with interruptible setpoints.
Startup / shutdown sequences Pre-shutdown ramps to position 0 when operational.
Emergency-stop sequence Aliased cmd.estop → state-machine emergencystop.
Fluid-contract aggregation Tracks upstream service type via registered sources.
Gas-choke detection ⚠️ Capped at gasChokedRatioLimit; surfaced in hydraulicDiagnostics.
Multi-parent registration ⚠️ Allowed but not exercised in production tests.

4. Code map

flowchart TB
    subgraph nodeRED["nodeClass.js — adapter (BaseNodeAdapter)"]
        nc["buildDomainConfig()<br/>static DomainClass, commands"]
    end
    subgraph domain["specificClass.js — orchestrator (BaseDomain)"]
        sc["Valve.configure()<br/>wires concern modules<br/>installs FluidCompatibility registerChild"]
    end
    subgraph concerns["src/ concern modules"]
        state["state/<br/>stateBindings → positionChange"]
        fluid["fluid/<br/>FluidCompatibility"]
        curve["curve/<br/>SupplierCurvePredictor"]
        meas["measurement/<br/>MeasurementRouter + FORMULA_UNITS"]
        flow["flow/<br/>FlowController (setpoint, sequences)"]
        io["io/<br/>buildOutput + buildStatusBadge"]
        hyd["hydraulicModel.js<br/>ValveHydraulicModel"]
    end
    nc --> sc
    sc --> state
    sc --> fluid
    sc --> curve
    sc --> meas
    sc --> flow
    sc --> io
    sc --> hyd
Module Owns Read first if you're changing…
state/ Bindings from state-machine positionChangeupdatePosition() Move-finished triggers.
fluid/ Service-type compatibility, contract aggregation Gas-vs-liquid mismatch warnings.
curve/ Supplier Kv curve load + interpolation Curve fitting, model selection.
measurement/ Pressure/flow routing + deltaP recompute What triggers a recalc.
flow/ Sequence + setpoint execution Startup / shutdown / move semantics.
io/ Port-0 output shape + status badge What lands on the wire each tick.

5. Topic contract

Auto-generated from src/commands/index.js. Do NOT hand-edit between the markers. Re-run npm run wiki:contract.

Canonical topic Aliases Payload Unit Effect
set.mode setMode string Switch the valve between auto / manual control modes.
cmd.startup (none) any Initiate the valve startup sequence.
cmd.shutdown (none) any Initiate the valve shutdown sequence.
cmd.estop emergencystop, emergencyStop any Trigger an emergency stop on the valve.
execSequence (none) object Legacy umbrella that demuxes payload.action to startup / shutdown / estop.
set.position execMovement object Move the valve to a control-% position via execMovement.
data.flow updateFlow object Push a measured flow into the valve (variant + position + unit).
query.curve showcurve any Return the valve characteristic curve on the reply port.
child.register registerChild string Register a child measurement with this valve.

6. Child registration

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.

flowchart LR
    subgraph kids["accepted children (softwareType)"]
        src["machine / rotatingmachine /<br/>machinegroup / pumpingstation /<br/>valvegroupcontrol"]:::unit
        m["measurement"]:::ctrl
    end
    src -->|getFluidContract| fluid[FluidCompatibility<br/>aggregates serviceType]
    m   -->|"&lt;type&gt;.measured.&lt;position&gt;"| router[MeasurementRouter<br/>updatePressure / updateFlow]
    router --> deltaP[updateDeltaP<br/>writes pressure.predicted.delta]
    fluid --> evt1[evt.fluidCompatibilityChange]
    deltaP --> evt2[evt.deltaPChange]
    classDef unit fill:#50a8d9,color:#000
    classDef ctrl fill:#a9daee,color:#000
softwareType onRegister side-effect Subscribed events
machine / rotatingmachine Stored as upstream source; reads getFluidContract() or default liquid. fluidContractChange.
machinegroup / machinegroupcontrol Same; recomputes aggregate service type. fluidContractChange.
pumpingstation Same. fluidContractChange.
valvegroupcontrol Same. fluidContractChange.
measurement Routed via measurement handshake; values land in MeasurementContainer. <type>.measured.<position>.

7. Lifecycle — what one event does

sequenceDiagram
    participant parent as valveGroupControl
    participant valve as valve
    participant state as state FSM
    participant hyd as hydraulicModel
    participant out as Port-0

    parent->>valve: set.position { setpoint: 60 }
    valve->>state: moveTo(60)
    state-->>valve: positionChange ticks
    valve->>valve: predictKv(position)
    valve->>hyd: calculateDeltaPMbar(q, kv, downP, rho, T)
    hyd-->>valve: { deltaPMbar, details }
    valve->>valve: write pressure.predicted.delta
    valve->>parent: emitter.emit('deltaPChange', deltaP)
    valve->>out: msg{topic, payload (delta-compressed)}

8. Data model — getOutput()

What lands on Port 0. Composed in io/output.buildOutput, then delta-compressed by outputUtils.formatMsg.

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

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

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
Mode mode.current per schema enum setMode, flowController
Asset model asset.model null string SupplierCurvePredictor
Service type asset.serviceType per asset gas / liquid ValveHydraulicModel
Diameter asset.valveDiameter per asset > 0 (m) curve key selection
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 01 gas formula clamp

10. State chart

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').

11. Examples

Tier File What it shows Mandatory?
Basic examples/01-Basic.flow.json Inject set.position + dashboard, no parent
Integration examples/02-Integration.flow.json valve + VGC + upstream source
Dashboard examples/03-Dashboard.flow.json Live FlowFuse charts (position, ΔP, flow)

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