Files
machineGroupControl/CONTRACT.md
znetsixe a57e0095a3 fix(commands+CONTRACT): correct set.mode mode list
- src/commands/index.js: description now lists the actual schema modes
  (`optimalControl`, `priorityControl`, `maintenance`); was generic
  "auto / manual" which never matched the schema.
- CONTRACT.md: same fix — old list included `dynamiccontrol` (doesn't
  exist) and used lowercase names that don't match the canonical
  schema enum.

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

3.7 KiB

machineGroupControl — Contract

Hand-maintained for Phase 4; the ## Inputs table is generated from src/commands/index.js (see Phase 9 generator). Keep ≤ 80 lines.

Inputs (msg.topic on Port 0)

Canonical Aliases (deprecated) Payload Effect
set.mode setMode string — one of optimalControl, priorityControl, maintenance (schema-validated) Switches the control strategy via source.setMode(payload).
child.register registerChild string — the child node's Node-RED id Resolves the child via RED.nodes.getNode and registers it through childRegistrationUtils.registerChild(childObj.source, msg.positionVsParent).
set.demand Qd numeric (number or numeric string) Calls source.handleInput('parent', parseFloat(payload)). On success, replies on Port 0 with topic = source.config.general.name, payload = 'done'. Non-numeric payloads log error and are skipped.

Aliases log a one-time deprecation warning the first time they fire.

Outputs (msg.topic on Port 0/1/2)

  • Port 0 (process): msg.topic = config.general.name. Payload built by outputUtils.formatMsg(..., 'process') from getOutput() — delta-compressed (only changed fields are emitted). On a successful set.demand dispatch the node additionally emits { topic: <name>, payload: 'done' } as an acknowledgement.
  • Port 1 (InfluxDB telemetry): same shape as Port 0, formatted with the 'influxdb' formatter.
  • Port 2 (registration): at startup the node sends one { topic: 'registerChild', payload: <node.id>, positionVsParent } to the upstream parent.

Events emitted by source.measurements.emitter

The MeasurementContainer fires <type>.<variant>.<position> whenever the corresponding series receives a new value. Parents subscribe via the generic child.measurements.emitter.on(eventName, ...) handshake. machineGroupControl publishes:

  • flow.predicted.atequipment — aggregated predicted group flow (sum of member-machine predicted flows at the group operating point).
  • flow.predicted.downstream — mirror of the live group flow seen at the discharge header (written by handlePressureChange for downstream consumers such as pumpingStation).
  • power.predicted.atequipment — aggregated predicted group power.
  • efficiency.predicted.atequipment — group efficiency = flow/power at the selected operating point.
  • Ncog.predicted.atequipment — group normalised cost-of-goods score.
  • pressure.measured.upstream, pressure.measured.downstream, pressure.measured.differential — mirrored from header-side measurement children (asset.type='pressure'), when registered.

The exact set is data-driven by which children register and what they publish; downstream consumers should subscribe by event name, not assume a fixed catalogue.

Children registered by this node

machineGroupControl accepts two softwareTypes through the childRegistrationUtils handshake:

  • machine — a rotatingMachine. Stored in source.machines[id]. The group subscribes to its child's pressure.measured.differential, pressure.measured.downstream, and flow.predicted.downstream events to trigger handlePressureChange.
  • measurement — a header-side sensor (typically a pressure transmitter at the discharge or suction manifold). The group subscribes to the matching <asset.type>.measured.<positionVsParent> event and mirrors the value into its own MeasurementContainer; pressure events also trigger handlePressureChange so optimalControl can use ONE header operating point for all pumps.

Position labels accepted from children are upstream, downstream, atequipment (and case variants — normalised internally).