Files
valve/wiki/Reference-Contracts.md
znetsixe 7acd6c2ce0 fix(commands): point set.mode description at the schema enum
Old description said "auto / manual" but the schema declares four modes
(auto, virtualControl, fysicalControl, maintenance). New description
enumerates the allowed values and refers readers to the schema as the
source of truth. wiki-gen regenerated Reference-Contracts.md to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 16:05:37 +02:00

13 KiB
Raw Blame History

Reference — Contracts

code-ref

Note

Full topic contract, configuration schema, and child-registration filters for valve. Source of truth: src/commands/index.js, src/specificClass.js configure(), and the schema at generalFunctions/src/configs/valve.json.

Pending full node review (2026-05). Content reflects CONTRACT.md and current source only. For an intuitive overview, return to the Home.


Topic contract

The registry lives in src/commands/index.js. Each descriptor maps a canonical msg.topic to its handler; aliases emit a one-time deprecation warning the first time they fire.

Canonical topic Aliases Payload Unit Effect
set.mode setMode string Switch the operating mode. Allowed: auto, virtualControl, fysicalControl, maintenance (schema-validated in valve.jsonmode.current).
cmd.startup any Initiate the valve startup sequence.
cmd.shutdown any Initiate the valve shutdown sequence.
cmd.estop emergencystop, emergencyStop any Trigger an emergency stop on the valve.
execSequence 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.

execSequence demux

The pre-refactor topic execSequence carried {source, action, parameter} where action selected the verb. The command registry does not natively dispatch by payload content, so execSequence keeps its own descriptor whose handler forwards directly to the canonical cmd.startup / cmd.shutdown / cmd.estop handler based on payload.action. A deprecation warning fires once. Future-Phase-7 removal of execSequence is a behavioural change — callers must migrate to the canonical topics.

Mode / source allow-lists

A topic that survives the registry still passes through flowController.handleInput:

if (!this.isValidSourceForMode(source, this.host.currentMode)) {
    this.logger.warn(`Source '${source}' is not valid for mode '${currentMode}'.`);
    return { status: false, feedback: msg };
}

Defaults from valve.json:

Mode allowedSources allowedActions (schema)
auto parent, GUI, fysical statusCheck, execMovement, execSequence, emergencyStop
virtualControl GUI, fysical statusCheck, execMovement, execSequence, emergencyStop
fysicalControl fysical statusCheck, emergencyStop
maintenance (none) statusCheck

Note

flowController.handleInput currently enforces only the source side. The schema's allowedActions is defined but not gated in code — flagged as a TODO in Architecture. Source: nodes/valve/src/flow/flowController.js line 13.

A rejected request logs at warn and short-circuits.


Data model — getOutput() shape

Composed each tick by src/io/output.js buildOutput(). Delta-compressed: consumers see only the keys that changed.

Per-measurement keys

For every (type, variant, position) stored in MeasurementContainer with a finite value, the flattened output emits:

<position>_<variant>_<type>

This is the legacy three-segment key shape (no trailing <childId>). Position labels are normalised to lowercase. valve does not use the four-segment <type>.<variant>.<position>.<childId> shape that rotatingMachine emits.

Key Type Unit Sample / notes
state string "operational" — one of the FSM states.
percentageOpen number % 60 — current position 0..100.
moveTimeleft number s 0 — seconds remaining on the current move.
mode string "auto" / "virtualControl" / "fysicalControl" / "maintenance".
delta_predicted_pressure number mbar Predicted deltaP across the valve. Emitted on the next position tick once kv > 0 and a finite flow is known.
downstream_predicted_flow number m3/h Last flow pushed via data.flow with variant=predicted.
downstream_measured_flow number m3/h Last flow pushed via data.flow with variant=measured, or written by a registered flow measurement child.
downstream_predicted_pressure number mbar Last predicted pressure written upstream.
downstream_measured_pressure number mbar Last measured pressure from a registered pressure measurement child.

Status badge

buildStatusBadge in io/output.js:

<mode>: <state-symbol>   <position%>%   💨<flow><unit>   ΔP<deltaP> <unit>

(The position / flow / deltaP line only appears in operational / warmingup / accelerating / decelerating; other states show just <mode>: <symbol>.)

State symbols (per STATE_SYMBOLS map in io/output.js):

State Symbol Fill
off red
idle ⏸️ blue
operational ⏵️ green
starting ⏯️ yellow
warmingup 🔄 green
accelerating yellow
decelerating yellow
stopping ⏹️ yellow
coolingdown ❄️ yellow

When getFluidCompatibility().status is mismatch or conflict, the badge is overridden to a yellow ring with ⚠ <message> appended.


Configuration schema — editor form to config keys

Source of truth: generalFunctions/src/configs/valve.json plus nodeClass.buildDomainConfig.

General (config.general)

Form field Config key Default Notes
Name general.name valve Re-derived in configure().
(auto-assigned) general.id null Node-RED node id.
Default unit general.unit m3/h (schema) Re-resolved to the unitPolicy output.flow in configure().
Enable logging general.logging.enabled true Master switch.
Log level general.logging.logLevel info debug / info / warn / error.

Functionality (config.functionality)

Form field Config key Default Notes
Position vs parent functionality.positionVsParent atEquipment One of atEquipment / upstream / downstream. Used in the child-register payload that goes UP to VGC.
(hidden) functionality.softwareType valve Constant.
(hidden) functionality.role controller Constant.

Asset (config.asset)

Form field Config key Default Notes
Asset UUID asset.uuid null Globally-unique identifier.
Tag code asset.tagCode null
Geolocation asset.geoLocation {x:0, y:0, z:0}
Model asset.model null Optional. If set, resolves curve + supplier / type / allowed units via assetResolver.resolveAssetMetadata('valve', model). If null, the predictor uses the inline valveCurve.
Deployment unit asset.unit null Must appear in the registry's allowed list for the model when set.
Accuracy asset.accuracy null Optional.
Valve curve asset.valveCurve { '1.204': { '1': { x: [0..100 by 10], y: [0,18,50,95,150,216,337,564,882,1398,1870] } } } Nested map: outer key = density (kg per nm³), middle = diameter (mm), leaf = {x: position%, y: Kv (m³/h)}.

Runtime options that bypass config and reach configure() via Valve._pendingExtras.runtimeOptions:

UI field runtimeOptions key Default Effect
Service type serviceType derived (gas if not liquid) Picks the hydraulic formula in ValveHydraulicModel.
Fluid density fluidDensity model default (997 / 1.204) Sets host.rho.
Fluid temperature K fluidTemperatureK 293.15 Sets host.T.
Gas choke ratio limit gasChokedRatioLimit 0.7 Cap for the gas hydraulic formula.

Warning

Legacy asset fields rejected. supplier, category, and assetType are no longer node config — the registry derives them from the model. Flows saved before the AssetResolver refactor will throw a startup error from _rejectLegacyAssetFields with a clear migration message. Re-open the node, re-select the model from the asset menu, and save.

State times (stateConfig.time)

Set on the state machine via nodeClass.buildDomainConfig from editor fields:

Form field Config key Notes
Startup Time time.starting Time spent in starting before transitioning to warmingup.
Warmup Time time.warmingup Time in warmingupnon-interruptible safety.
Shutdown Time time.stopping Time in stopping.
Cooldown Time time.coolingdown Time in coolingdownnon-interruptible safety.

Note

TODO: confirm canonical defaults. valve.json does not declare them inline; they come from generalFunctions/src/configs/state.json or the parent state-machine schema. Source: nodeClass.buildDomainConfig lines 1926.

Movement (stateConfig.movement)

Form field Config key Notes
Reaction Speed movement.speed Position ramp rate (%/s). E.g. 1 means setpoint 60 from 0 takes ~60 s.

Sequences (config.sequences)

State-transition lists per sequence name. Defaults:

Sequence States
startup [starting, warmingup, operational]
shutdown [stopping, coolingdown, idle]
emergencystop [emergencystop, off]
boot [idle, starting, warmingup, operational]

Note: unlike rotatingMachine, valve.json does not ship entermaintenance / exitmaintenance sequences. TODO: confirm whether maintenance transitions are intentionally manual.

Mode (config.mode)

Form field Config key Default Range
Mode mode.current auto auto / virtualControl / fysicalControl / maintenance
(defaults) mode.allowedActions.<mode> see Topic contract schema only — not currently gated in code
(defaults) mode.allowedSources.<mode> see above enforced by flowController.isValidSourceForMode

Unit policy

Source: src/specificClass.js lines 2024.

Quantity Canonical (internal) Output (rendered) Required-unit
Pressure Pa mbar
Flow m3/s m3/h
Temperature K C

requireUnitForTypes means MeasurementContainer rejects writes that omit unit for these types. The hydraulic model itself reads back via fixed FORMULA_UNITS = {pressure: 'mbar', flow: 'm3/h', temperature: 'K'}.

Calculation mode (config.calculationMode)

low / medium (default) / high — declared in the schema. TODO: confirm whether the dispatch path consults calculationMode for trigger frequency. Source: valve.json lines 346366.


Child registration

Source: src/specificClass.js lines 100101 and src/fluid/fluidCompatibility.js.

valve overrides BaseDomain.registerChild so registrations fall into FluidCompatibility.registerChild rather than the generic ChildRouter. Upstream sources feed the fluid-contract aggregator; measurement children attach via the standard measurement handshake and land in MeasurementRouter.

Software type Side-effect Subscribed events
machine / rotatingmachine Stored as upstream source; reads getFluidContract() or asset.serviceType, defaulting to liquid for the rotating-equipment family. Recomputes aggregate service type. fluidContractChange
machinegroup / machinegroupcontrol Same; recomputes aggregate service type. fluidContractChange
pumpingstation Same. fluidContractChange
valvegroupcontrol Same. fluidContractChange
measurement (asset.type=pressure, position=*) Routed through MeasurementRouter.updatePressure(variant, value, position, unit); triggers a deltaP recompute. <type>.measured.<position>
measurement (asset.type=flow, position=*) Routed through MeasurementRouter.updateFlow(variant, value, position, unit); triggers a deltaP recompute. <type>.measured.<position>

The valve's _updateMeasurement path (via updateMeasurement(variant, subType, value, position, unit)) currently handles pressure and flow. power is recognised but ignored.


Page Why
Home Intuitive overview
Reference — Architecture Code map, FSM, hydraulic-model pipeline
Reference — Examples Shipped flows + debug recipes
Reference — Limitations Known issues and open questions
EVOLV — Topic Conventions Platform-wide topic rules
EVOLV — Telemetry Port 0 / 1 / 2 InfluxDB layout