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>
13 KiB
Reference — Contracts
Note
Full topic contract, configuration schema, and child-registration filters for
valve. Source of truth:src/commands/index.js,src/specificClass.jsconfigure(), and the schema atgeneralFunctions/src/configs/valve.json.Pending full node review (2026-05). Content reflects
CONTRACT.mdand 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.json → mode.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.handleInputcurrently enforces only the source side. The schema'sallowedActionsis defined but not gated in code — flagged as a TODO in Architecture. Source:nodes/valve/src/flow/flowController.jsline 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, andassetTypeare no longer node config — the registry derives them from the model. Flows saved before the AssetResolver refactor will throw a startup error from_rejectLegacyAssetFieldswith 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 warmingup — non-interruptible safety. |
| Shutdown Time | time.stopping |
Time in stopping. |
| Cooldown Time | time.coolingdown |
Time in coolingdown — non-interruptible safety. |
Note
TODO: confirm canonical defaults.
valve.jsondoes not declare them inline; they come fromgeneralFunctions/src/configs/state.jsonor the parent state-machine schema. Source:nodeClass.buildDomainConfiglines 19–26.
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 20–24.
| 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 346–366.
Child registration
Source: src/specificClass.js lines 100–101 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.
Related pages
| 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 |