Replaces the prior stub/partial wiki with a Home + Reference-{Architecture,
Contracts,Examples,Limitations} + _Sidebar structure. Topic-contract and
data-model sections wrapped in AUTOGEN markers for the future wiki-gen tool.
Source-vs-spec contradictions surfaced and flagged inline (not silently
fixed). Pending-review notes mark sections that need a full node review.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
13 KiB
generalFunctions
generalFunctions is the shared infrastructure every EVOLV node depends on. It provides the base classes all nodes extend (BaseDomain, BaseNodeAdapter), the command dispatch engine, the measurement store, unit-policy system, child-registration machinery, InfluxDB output formatting, and a set of domain utilities (PID, curve interpolation, prediction, statistics, coolprop). Nodes hold zero duplicated scaffolding — they only write the logic that differs.
At a glance
| Thing | Value |
|---|---|
| What it is | The shared library — not a Node-RED node, never placed in a flow |
| Kind | Shared library (require('generalFunctions')) |
| Consumed by | All 12 EVOLV nodes (rotatingMachine, MGC, pumpingStation, valve, VGC, reactor, settler, monster, measurement, diffuser, dashboardAPI) |
| Import style | Package root only — const { BaseDomain, UnitPolicy } = require('generalFunctions'); |
| Side effects on a flow | None — the library has no editor form, no node registration |
| Cross-node coupling | Through this library's API surface + Node-RED messages only — never direct imports between node packages |
How it fits
flowchart LR
gf["generalFunctions<br/>(shared library)"]:::lib
rm["rotatingMachine<br/>Equipment"]:::equip
mgc["machineGroupControl<br/>Unit"]:::unit
ps["pumpingStation<br/>Process Cell"]:::proc
meas["measurement<br/>Control Module"]:::ctrl
valve["valve<br/>Equipment"]:::equip
vgc["valveGroupControl<br/>Unit"]:::unit
reactor["reactor<br/>Unit"]:::unit
settler["settler<br/>Unit"]:::unit
monster["monster<br/>Unit"]:::unit
diffuser["diffuser<br/>Equipment"]:::equip
dashAPI["dashboardAPI<br/>utility"]:::util
gf --> rm
gf --> mgc
gf --> ps
gf --> meas
gf --> valve
gf --> vgc
gf --> reactor
gf --> settler
gf --> monster
gf --> diffuser
gf --> dashAPI
classDef lib fill:#222,color:#fff,stroke:#444
classDef proc fill:#0c99d9,color:#fff
classDef unit fill:#50a8d9,color:#000
classDef equip fill:#86bbdd,color:#000
classDef ctrl fill:#a9daee,color:#000
classDef util fill:#dddddd,color:#000
Every EVOLV node declares generalFunctions as a dependencies entry and imports from the package root only. The library has no S88 level of its own — it is the substrate the S88-classified nodes are built on.
How to import
Single root import, destructure what you need:
const {
// Platform base classes
BaseDomain, BaseNodeAdapter, ChildRouter, UnitPolicy, HealthStatus, LatestWinsGate,
// Node-RED bridge
createRegistry, CommandRegistry, statusBadge, StatusUpdater,
// Measurement + config
MeasurementContainer, configManager, configUtils, validation,
// Output formatting + logging
outputUtils, logger,
// Child registration
childRegistrationUtils,
// Unit conversion + physics
convert, Fysics, gravity, coolprop,
// Control + prediction
PIDController, CascadePIDController, createPidController, createCascadePidController,
predict, interpolation, nrmse, stats, state,
// Editor menus
MenuManager,
// Asset registry
assetResolver, AssetResolver, FileBackend, HttpBackend,
// Constants
POSITIONS, POSITION_VALUES, isValidPosition,
} = require('generalFunctions');
Important
Never import internal paths (
require('generalFunctions/src/domain/UnitPolicy')). Only the package root is contractual; internal layout may move.
For the full export list with signatures and stability tags, see Reference — Contracts.
Module map — what lives where
flowchart TB
subgraph domain["src/domain/ — base classes"]
BD["BaseDomain.js"]
CR["ChildRouter.js"]
UP["UnitPolicy.js"]
LWG["LatestWinsGate.js"]
HS["HealthStatus.js"]
end
subgraph nodered["src/nodered/ — Node-RED adapter layer"]
BNA["BaseNodeAdapter.js"]
CMR["commandRegistry.js"]
SB["statusBadge.js"]
SU["statusUpdater.js"]
end
subgraph measurements["src/measurements/ — measurement store"]
MC["MeasurementContainer.js"]
MB["MeasurementBuilder.js"]
Meas["Measurement.js"]
end
subgraph helper["src/helper/ — shared utilities"]
LOG["logger.js"]
OU["outputUtils.js"]
CRU["childRegistrationUtils.js"]
CFG["configUtils.js"]
VAL["validationUtils.js"]
MU["menuUtils.js"]
GR["gravity.js"]
end
subgraph predict_grp["src/predict/ — curve prediction"]
PRED["predict_class.js"]
INTERP["interpolation.js"]
end
subgraph configs["src/configs/ — schema registry"]
CFGM["index.js (ConfigManager)"]
JSON["*.json — per-node schemas"]
end
subgraph math["numeric & domain utilities"]
PID["src/pid/"]
NRMSE["src/nrmse/"]
STATS["src/stats/"]
OUT["src/outliers/"]
STATE["src/state/"]
CONV["src/convert/"]
COOL["src/coolprop-node/"]
FYS["src/convert/fysics.js"]
end
subgraph menu_grp["src/menu/"]
MM["MenuManager"]
end
subgraph constants["src/constants/"]
POS["positions.js"]
end
BD --> CR
BD --> UP
BD --> MC
BD --> CRU
BD --> LOG
BNA --> BD
BNA --> CMR
BNA --> OU
BNA --> SU
| Directory | Primary export | Read first if you're changing… |
|---|---|---|
src/domain/ |
BaseDomain, ChildRouter, UnitPolicy, LatestWinsGate, HealthStatus |
Base class contracts, child routing, unit system |
src/nodered/ |
BaseNodeAdapter, CommandRegistry, statusBadge, StatusUpdater |
Input dispatch, output loops, editor status |
src/measurements/ |
MeasurementContainer |
Measurement storage, statistics, 4-segment key output |
src/helper/ |
logger, outputUtils, childRegistrationUtils, configUtils, validationUtils, menuUtils, gravity |
Logging, InfluxDB formatting, child registration |
src/configs/ |
ConfigManager + per-node JSON schemas |
Schema loading, config validation, default values |
src/predict/ |
predict, interpolation |
Characteristic curve fitting + flow/power prediction |
src/pid/ |
PIDController, CascadePIDController |
Closed-loop control |
src/nrmse/ |
ErrorMetrics (NRMSE) |
Prediction quality scoring |
src/stats/ |
stats (mean, stddev, median) |
Statistical reducers |
src/outliers/ |
DynamicClusterDeviation |
Online outlier detection |
src/state/ |
state, StateManager, MovementManager |
FSM for valve / machine state machines |
src/convert/ |
convert, Fysics |
Unit conversion, physical constants |
src/coolprop-node/ |
coolprop |
Thermodynamic property lookup |
src/menu/ |
MenuManager |
Editor-form dropdown population |
src/registry/ |
assetResolver, AssetResolver, FileBackend, HttpBackend |
Asset metadata lookup (replaces ad-hoc JSON readers) |
src/constants/ |
POSITIONS, POSITION_VALUES, isValidPosition |
Canonical spatial position constants |
What you'll send (the platform contract)
This library doesn't accept msg.topic directly — nodes do. But every node's nodeClass.js and specificClass.js route through the same primitives:
| Primitive | Role |
|---|---|
BaseNodeAdapter.input(msg) |
Routes incoming Node-RED messages through the node's CommandRegistry, applies unit normalisation, then dispatches to the handler. |
CommandRegistry |
Topic + alias map. Handlers are pure functions; units: {measure, default} triggers automatic convert normalisation. |
ChildRouter |
Declarative parent-side routing. .onRegister(type, cb), .onMeasurement(type, filter, cb), .onPrediction(type, filter, cb). |
MeasurementContainer.type().variant().position().value() |
Chainable write. Flattened output emits 4-segment keys <type>.<variant>.<position>.<childId>. |
UnitPolicy.declare({canonical, output, curve?}) |
The per-node unit triple. Used by MeasurementContainer (auto-convert on write) and by the output formatter (render in output units). |
outputUtils.formatMsg(snapshot, config, mode) |
Delta-compresses successive snapshots. Returns undefined when nothing changed. |
HealthStatus.ok / degraded / compose |
Frozen plain-object factory for prediction-quality state. |
LatestWinsGate.fire(value) |
Serialises async dispatches; the latest call wins, intermediates are marked SUPERSEDED. |
For full signatures and stability tags see Reference — Contracts.
What you'll see come out
A node that imports BaseNodeAdapter automatically gets the three EVOLV ports:
| Port | Carries | Built by |
|---|---|---|
| 0 (process) | Delta-compressed state snapshot (the getOutput() return) |
outputUtils.formatMsg(snapshot, config, 'process') |
| 1 (telemetry) | InfluxDB line-protocol payload (same fields) | outputUtils.formatMsg(snapshot, config, 'influxdb') |
| 2 (register / control) | Parent-child handshake messages | childRegistrationUtils via BaseNodeAdapter |
The 4-segment key shape <type>.<variant>.<position>.<childId> is the contractual output of MeasurementContainer.getFlattenedOutput(). Position labels are normalised to lowercase. Changing this shape is a forbidden breaking change — see Reference — Limitations.
Capability matrix
| Capability | Status | Notes |
|---|---|---|
Base domain scaffolding (BaseDomain) |
✅ | Constructor, emitter, logger, measurements, child registry wired automatically |
Base Node-RED adapter (BaseNodeAdapter) |
✅ | Tick/event loop, status badge, input dispatch, Port 0/1/2 output |
Declarative command dispatch (CommandRegistry) |
✅ | Alias deprecation warnings, unit normalisation, query.units auto-topic |
Declarative child-registration routing (ChildRouter) |
✅ | Replaces per-node registerChild switch blocks |
Unit policy + conversion (UnitPolicy, convert) |
✅ | Canonical ↔ output ↔ curve unit sets; dual method/property access |
Measurement store (MeasurementContainer) |
✅ | Chainable, windowed, auto-convert, 4-segment key output |
InfluxDB + process output formatting (outputUtils) |
✅ | Delta-compressed; consumers must cache and merge |
Status badge helpers (statusBadge, StatusUpdater) |
✅ | Converged look-and-feel across all nodes |
Latest-wins async gate (LatestWinsGate) |
✅ | Extracted from MGC; shared by PS, VGC, MGC |
Prediction quality / drift tracking (HealthStatus) |
✅ | Frozen plain-object shape; composable |
Config schema registry (configManager) |
✅ | One JSON schema per node in src/configs/ |
PID control (PIDController, CascadePIDController) |
✅ | Full-featured discrete PID with bumpless transfer |
Curve interpolation (interpolation, predict) |
✅ | Multidimensional characteristic-curve predictor |
Statistical helpers (stats, nrmse, outliers) |
✅ | Mean, stddev, median, NRMSE, dynamic-cluster outlier detection |
Thermodynamic properties (coolprop) |
✅ | CoolProp bindings for fluid/gas property lookup |
FSM for valve/machine states (state) |
✅ | StateManager + MovementManager |
Gravity calculations (gravity) |
✅ | WGS-84 model |
Physical constants (Fysics) |
✅ | Air density, viscosity, etc. |
Browser-side editor dropdowns (MenuManager, menuUtils) |
✅ | Node-RED editor form population |
Asset metadata registry (assetResolver) |
✅ | Replaces loadCurve, AssetCategoryManager, ad-hoc JSON readers |
Need more?
| Page | What you'll find |
|---|---|
| Reference — Contracts | Full public API surface table — one row per export, with source file, stability tag, and signature |
| Reference — Architecture | Three-tier rules, src/ directory tree, how 12 nodes consume the library, additive-only export discipline |
| Reference — Examples | Usage patterns: extending BaseDomain and BaseNodeAdapter, registering commands, declaring child routes, MeasurementContainer chaining |
| Reference — Limitations | Known issues (deprecated loadCurve, outlierDetection logs to console, configUtils silent strip, …) and stability/versioning rules |
EVOLV master wiki · Platform CONTRACTS.md · Topic Conventions