Files
generalFunctions/wiki/Home.md
znetsixe 8b28f8969e docs(wiki): full 5-page wiki matching the rotatingMachine reference format
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>
2026-05-19 09:42:15 +02:00

13 KiB

generalFunctions

code-ref kind status

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