Refactor of diffuser to use the platform infrastructure (BaseDomain, BaseNodeAdapter, ChildRouter, commandRegistry, statusBadge). Extracts concerns into focused modules per .claude/refactor/MODULE_SPLIT.md generic template. Tests stay green; CONTRACT.md generated; legacy aliases preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.7 KiB
diffuser — Contract
Hand-maintained for Phase 6; the ## Inputs table is generated from
src/commands/index.js (see Phase 9 generator). Keep ≤ 100 lines.
Inputs (msg.topic on Port 0)
| Canonical | Aliases (deprecated) | Payload | Effect |
|---|---|---|---|
data.flow |
air_flow |
number — airflow in Nm³/h |
Calls source.setFlow(payload); clamps to ≥ 0 and recomputes OTR. |
set.density |
density |
number — diffuser density (per m²) |
Calls source.setDensity(payload) and recomputes. |
set.water-height |
height_water |
number — water column height in m |
Calls source.setWaterHeight(payload); clamps to ≥ 0 and recomputes head + total pressure. |
set.header-pressure |
header_pressure |
number — header gauge pressure in mbar |
Calls source.setHeaderPressure(payload) and recomputes. |
set.elements |
elements |
number — element count (rounded; must be > 0) |
Calls source.setElementCount(payload) and recomputes per-element flow. |
set.alfa-factor |
alfaFactor |
number — alpha correction (≥ 0) |
Calls source.setAlfaFactor(payload) and recomputes oxygen output. |
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 byoutputUtils.formatMsg(..., 'process')fromgetOutput()— delta-compressed (only changed fields are emitted). Fields:iPressure,iMWater,iFlow— echoed inputs.nFlow— normalised airflow (Nm³/h).oOtr— interpolated oxygen transfer rate (g O₂ / Nm³).oPLoss— total head loss (mbar) = static head + diffuser ΔP.oKgo2H— kg O₂ per hour at current operating point.oFlowElement— flow per element (Nm³/h/element).efficiency— combined OTR/ΔP efficiency (0–100).slope— local OTR-vs-flow slope.oZoneOtr— reactor zone OTR (kg O₂ / m³ / day) computed againstdiffuser.zoneVolume;0when zone volume is unset.idle— true whendata.flow ≤ 0.warning,alarm— string arrays describing flow-per-element band excursions.
- Port 1 (InfluxDB telemetry): same shape as Port 0, formatted with
the
'influxdb'formatter. - Port 2 (registration): at startup the node sends one
{ topic: 'child.register', payload: <node.id>, positionVsParent, distance }to the upstream parent (typically a reactor).positionVsParentdefaults to'atEquipment'.
Port-count change (Phase 6)
Pre-refactor the diffuser exposed 4 outputs (process, dbase, reactor
control with topic: 'OTR', parent registration). The reactor control
message merged into Port 0 as oZoneOtr; consumers that previously
listened to the dedicated control port should switch to reading
payload.oZoneOtr from the process output. The legacy OTR topic is
removed in this refactor — there is no alias, since the data shape
differs (single value vs full process payload).
Events emitted by source.measurements.emitter
None today. The diffuser does not currently publish typed measurements
through MeasurementContainer; all output flows via getOutput().
A future phase may promote oOtr and oZoneOtr to typed series so
parent reactors can subscribe through the standard ChildRouter
handshake.
Events emitted by source.emitter
output-changed— fires whenever an input setter recomputes the oxygen-transfer state.BaseNodeAdapterlistens and pushes the delta-compressed Port 0 / Port 1 messages.
Children registered by this node
None. The diffuser is a leaf Equipment Module; it registers itself with its parent (reactor / process cell) via the Port 2 handshake.