# generalFunctions API Reference Shared library (`nodes/generalFunctions/`) used across all EVOLV Node-RED nodes. ```js const { logger, outputUtils, MeasurementContainer, ... } = require('generalFunctions'); ``` --- ## Table of Contents 1. [Logger](#logger) 2. [OutputUtils](#outpututils) 3. [ValidationUtils](#validationutils) 4. [MeasurementContainer](#measurementcontainer) 5. [ConfigManager](#configmanager) 6. [ChildRegistrationUtils](#childregistrationutils) 7. [MenuUtils](#menuutils) 8. [EndpointUtils](#endpointutils) 9. [Positions](#positions) 10. [AssetLoader / loadCurve](#assetloader--loadcurve) --- ## Logger Structured, level-filtered console logger. **File:** `src/helper/logger.js` ### Constructor ```js new Logger(logging = true, logLevel = 'debug', nameModule = 'N/A') ``` | Param | Type | Default | Description | |---|---|---|---| | `logging` | `boolean` | `true` | Enable/disable all output | | `logLevel` | `string` | `'debug'` | Minimum severity: `'debug'` \| `'info'` \| `'warn'` \| `'error'` | | `nameModule` | `string` | `'N/A'` | Label prefixed to every message | ### Methods | Method | Signature | Description | |---|---|---| | `debug` | `(message: string): void` | Log at DEBUG level | | `info` | `(message: string): void` | Log at INFO level | | `warn` | `(message: string): void` | Log at WARN level | | `error` | `(message: string): void` | Log at ERROR level | | `setLogLevel` | `(level: string): void` | Change minimum level at runtime | | `toggleLogging` | `(): void` | Flip logging on/off | ### Example ```js const Logger = require('generalFunctions').logger; const log = new Logger(true, 'info', 'MyNode'); log.info('Node started'); // [INFO] -> MyNode: Node started log.debug('ignored'); // silent (below 'info') log.setLogLevel('debug'); log.debug('now visible'); // [DEBUG] -> MyNode: now visible ``` --- ## OutputUtils Tracks output state and formats messages for InfluxDB or process outputs. Only emits changed fields. **File:** `src/helper/outputUtils.js` ### Constructor ```js new OutputUtils() // no parameters ``` ### Methods | Method | Signature | Returns | Description | |---|---|---|---| | `formatMsg` | `(output, config, format)` | `object \| undefined` | Diff against last output; returns formatted msg or `undefined` if nothing changed | | `checkForChanges` | `(output, format)` | `object` | Returns only the key/value pairs that changed since last call | **`format`** must be `'influxdb'` or `'process'`. ### Example ```js const out = new OutputUtils(); const msg = out.formatMsg( { temperature: 22.5, pressure: 1013 }, config, 'influxdb' ); // msg = { topic: 'nodeName', payload: { measurement, fields, tags, timestamp } } ``` --- ## ValidationUtils Schema-driven config validation with type coercion, range clamping, and nested object support. **File:** `src/helper/validationUtils.js` ### Constructor ```js new ValidationUtils(loggerEnabled = true, loggerLevel = 'warn') ``` ### Methods | Method | Signature | Returns | Description | |---|---|---|---| | `validateSchema` | `(config, schema, name)` | `object` | Walk the schema, validate every field, return a clean config. Unknown keys are stripped. Missing keys get their schema default. | | `constrain` | `(value, min, max)` | `number` | Clamp a numeric value to `[min, max]` | | `removeUnwantedKeys` | `(obj)` | `object` | Strip `rules`/`description` metadata, collapse `default` values | **Supported `rules.type` values:** `number`, `integer`, `boolean`, `string`, `enum`, `array`, `set`, `object`, `curve`, `machineCurve`. ### Example ```js const ValidationUtils = require('generalFunctions').validation; const v = new ValidationUtils(true, 'warn'); const schema = { temperature: { default: 20, rules: { type: 'number', min: -40, max: 100 } }, unit: { default: 'C', rules: { type: 'enum', values: [{ value: 'C' }, { value: 'F' }] } } }; const validated = v.validateSchema({ temperature: 999 }, schema, 'myNode'); // validated.temperature === 100 (clamped) // validated.unit === 'C' (default applied) ``` --- ## MeasurementContainer Chainable measurement storage organised by **type / variant / position**. Supports auto unit conversion, windowed statistics, events, and positional difference calculations. **File:** `src/measurements/MeasurementContainer.js` ### Constructor ```js new MeasurementContainer(options = {}, logger) ``` | Option | Type | Default | Description | |---|---|---|---| | `windowSize` | `number` | `10` | Rolling window for statistics | | `defaultUnits` | `object` | `{ pressure:'mbar', flow:'m3/h', ... }` | Default unit per measurement type | | `autoConvert` | `boolean` | `true` | Auto-convert values to target unit | | `preferredUnits` | `object` | `{}` | Per-type unit overrides | ### Chainable Setters All return `this` for chaining. ```js container .type('pressure') .variant('static') .position('upstream') .distance(5) .unit('bar') .value(3.2, Date.now(), 'bar'); ``` | Method | Signature | Description | |---|---|---| | `type` | `(typeName): this` | Set measurement type (e.g. `'pressure'`) | | `variant` | `(variantName): this` | Set variant (e.g. `'static'`, `'differential'`) | | `position` | `(positionValue): this` | Set position (e.g. `'upstream'`, `'downstream'`) | | `distance` | `(distance): this` | Set physical distance from parent | | `unit` | `(unitName): this` | Set unit on the underlying measurement | | `value` | `(val, timestamp?, sourceUnit?): this` | Store a value; auto-converts if `sourceUnit` differs from target | ### Terminal / Query Methods | Method | Signature | Returns | Description | |---|---|---|---| | `get` | `()` | `Measurement \| null` | Get the raw measurement object | | `getCurrentValue` | `(requestedUnit?)` | `number \| null` | Latest value, optionally converted | | `getAverage` | `(requestedUnit?)` | `number \| null` | Windowed average | | `getMin` | `()` | `number \| null` | Window minimum | | `getMax` | `()` | `number \| null` | Window maximum | | `getAllValues` | `()` | `array \| null` | All stored samples | | `getLaggedValue` | `(lag?, requestedUnit?)` | `number \| null` | Value from `lag` samples ago | | `getLaggedSample` | `(lag?, requestedUnit?)` | `object \| null` | Full sample `{ value, timestamp, unit }` from `lag` samples ago | | `exists` | `({ type?, variant?, position?, requireValues? })` | `boolean` | Check if a measurement series exists | | `difference` | `({ from?, to?, unit? })` | `object \| null` | Compute `{ value, avgDiff, unit }` between two positions | ### Introspection / Lifecycle | Method | Signature | Returns | Description | |---|---|---|---| | `getTypes` | `()` | `string[]` | All registered measurement types | | `getVariants` | `()` | `string[]` | Variants under current type | | `getPositions` | `()` | `string[]` | Positions under current type+variant | | `getAvailableUnits` | `(measurementType?)` | `string[]` | Units available for a type | | `getBestUnit` | `(excludeUnits?)` | `object \| null` | Best human-readable unit for current value | | `setPreferredUnit` | `(type, unit)` | `this` | Override default unit for a type | | `setChildId` | `(id)` | `this` | Tag container with a child node ID | | `setChildName` | `(name)` | `this` | Tag container with a child node name | | `setParentRef` | `(parent)` | `this` | Store reference to parent node | | `clear` | `()` | `void` | Reset all measurements and chain state | ### Events The internal `emitter` fires `"type.variant.position"` on every `value()` call with: ```js { value, originalValue, unit, sourceUnit, timestamp, position, distance, variant, type, childId, childName, parentRef } ``` ### Example ```js const { MeasurementContainer } = require('generalFunctions'); const mc = new MeasurementContainer({ windowSize: 5 }); mc.type('pressure').variant('static').position('upstream').value(3.2); mc.type('pressure').variant('static').position('downstream').value(2.8); const diff = mc.type('pressure').variant('static').difference(); // diff = { value: -0.4, avgDiff: -0.4, unit: 'mbar', from: 'downstream', to: 'upstream' } ``` --- ## ConfigManager Loads JSON config files from disk and builds merged runtime configs. **File:** `src/configs/index.js` ### Constructor ```js new ConfigManager(relPath = '.') ``` `relPath` is resolved relative to the configs directory. ### Methods | Method | Signature | Returns | Description | |---|---|---|---| | `getConfig` | `(configName)` | `object` | Load and parse `.json` | | `getAvailableConfigs` | `()` | `string[]` | List config names (without `.json`) | | `hasConfig` | `(configName)` | `boolean` | Check existence | | `getBaseConfig` | `()` | `object` | Shortcut for `getConfig('baseConfig')` | | `buildConfig` | `(nodeName, uiConfig, nodeId, domainConfig?)` | `object` | Merge base schema + UI overrides into a runtime config | | `createEndpoint` | `(nodeName)` | `string` | Generate browser JS that injects config into `window.EVOLV.nodes` | ### Example ```js const { configManager } = require('generalFunctions'); const cfg = configManager.buildConfig('measurement', uiConfig, node.id, { scaling: { enabled: true, inputMin: 0, inputMax: 100 } }); ``` --- ## ChildRegistrationUtils Manages parent-child node relationships: registration, lookup, and structure storage. **File:** `src/helper/childRegistrationUtils.js` ### Constructor ```js new ChildRegistrationUtils(mainClass) ``` `mainClass` is the parent node instance (must expose `.logger` and optionally `.registerChild()`). ### Methods | Method | Signature | Returns | Description | |---|---|---|---| | `registerChild` | `(child, positionVsParent, distance?)` | `Promise` | Register a child node under the parent. Sets up parent refs, measurement context, and stores by softwareType/category. | | `getChildrenOfType` | `(softwareType, category?)` | `array` | Get children filtered by software type and optional category | | `getChildById` | `(childId)` | `object \| null` | Lookup a single child by its ID | | `getAllChildren` | `()` | `array` | All registered children | | `logChildStructure` | `()` | `void` | Debug-print the full child tree | ### Example ```js const { childRegistrationUtils: CRU } = require('generalFunctions'); const cru = new CRU(parentNode); await cru.registerChild(sensorNode, 'upstream'); cru.getChildrenOfType('measurement'); // [sensorNode] ``` --- ## MenuUtils Browser-side UI helper for Node-RED editor. Methods are mixed in from separate modules: toggles, data fetching, URL utils, dropdown population, and HTML generation. **File:** `src/helper/menuUtils.js` ### Constructor ```js new MenuUtils() // no parameters; sets isCloud=false, configData=null ``` ### Key Methods **Toggles** -- control UI element visibility: | Method | Signature | Description | |---|---|---| | `initBasicToggles` | `(elements)` | Bind log-level row visibility to log checkbox | | `initMeasurementToggles` | `(elements)` | Bind scaling input rows to scaling checkbox | | `initTensionToggles` | `(elements, node)` | Show/hide tension row based on interpolation method | **Data Fetching:** | Method | Signature | Returns | Description | |---|---|---|---| | `fetchData` | `(url, fallbackUrl)` | `Promise` | Fetch JSON from primary URL; fall back on failure | | `fetchProjectData` | `(url)` | `Promise` | Fetch project-level data | | `apiCall` | `(node)` | `Promise` | POST to asset-register API | **URL Construction:** | Method | Signature | Returns | Description | |---|---|---|---| | `getSpecificConfigUrl` | `(nodeName, cloudAPI)` | `{ cloudConfigURL, localConfigURL }` | Build cloud + local config URLs | | `constructUrl` | `(base, ...paths)` | `string` | Join URL segments safely | | `constructCloudURL` | `(base, ...paths)` | `string` | Same as `constructUrl`, for cloud endpoints | **Dropdown Population:** | Method | Signature | Description | |---|---|---| | `fetchAndPopulateDropdowns` | `(configUrls, elements, node)` | Cascading supplier > subType > model > unit dropdowns | | `populateDropdown` | `(htmlElement, options, node, property, callback?)` | Fill a `