Files
generalFunctions/src/configs/index.js
Rene De Ren 89aec9a7eb Reset chaining context in MeasurementContainer.clear()
Closes #25

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 15:06:17 +01:00

139 lines
5.2 KiB
JavaScript

const fs = require('fs');
const path = require('path');
class ConfigManager {
constructor(relPath = '.') {
this.configDir = path.resolve(__dirname, relPath);
}
/**
* Load a configuration file by name
* @param {string} configName - Name of the config file (without .json extension)
* @returns {Object} Parsed configuration object
*/
getConfig(configName) {
try {
const configPath = path.resolve(this.configDir, `${configName}.json`);
const configData = fs.readFileSync(configPath, 'utf8');
return JSON.parse(configData);
} catch (error) {
throw new Error(`Failed to load config '${configName}': ${error.message}`);
}
}
/**
* Get list of available configuration files
* @returns {Array<string>} Array of config names (without .json extension)
*/
getAvailableConfigs() {
try {
const resolvedDir = path.resolve(this.configDir);
const files = fs.readdirSync(resolvedDir);
return files
.filter(file => file.endsWith('.json'))
.map(file => path.basename(file, '.json'));
} catch (error) {
throw new Error(`Failed to read config directory: ${error.message}`);
}
}
/**
* Check if a specific config exists
* @param {string} configName - Name of the config file
* @returns {boolean} True if config exists
*/
hasConfig(configName) {
const configPath = path.resolve(this.configDir, `${configName}.json`);
return fs.existsSync(configPath);
}
/**
* Build a runtime config by merging base schema + node schema + UI overrides.
* Eliminates the need for each nodeClass to manually construct general/asset/functionality sections.
*
* @param {string} nodeName - Node type name (e.g., 'valve', 'measurement')
* @param {object} uiConfig - Raw config from Node-RED UI
* @param {string} nodeId - Node-RED node ID (from node.id)
* @param {object} [domainConfig={}] - Domain-specific config sections (e.g., { scaling: {...}, smoothing: {...} })
* @returns {object} Merged runtime config
*
* @example
* const cfgMgr = new ConfigManager();
* const config = cfgMgr.buildConfig('measurement', uiConfig, node.id, {
* scaling: { enabled: uiConfig.scaling, inputMin: uiConfig.i_min, ... },
* smoothing: { smoothWindow: uiConfig.count, ... }
* });
*/
buildConfig(nodeName, uiConfig, nodeId, domainConfig = {}) {
// Build base sections from UI config (common to ALL nodes)
const config = {
general: {
name: uiConfig.name || nodeName,
id: nodeId,
unit: uiConfig.unit || 'unitless',
logging: {
enabled: uiConfig.enableLog !== undefined ? uiConfig.enableLog : true,
logLevel: uiConfig.logLevel || 'info'
}
},
functionality: {
softwareType: nodeName.toLowerCase(),
positionVsParent: uiConfig.positionVsParent || 'atEquipment',
distance: uiConfig.hasDistance ? uiConfig.distance : undefined
}
};
// Add asset section if UI provides asset fields
if (uiConfig.supplier || uiConfig.category || uiConfig.assetType || uiConfig.model) {
config.asset = {
uuid: uiConfig.uuid || uiConfig.assetUuid || null,
tagCode: uiConfig.tagCode || uiConfig.assetTagCode || null,
supplier: uiConfig.supplier || 'Unknown',
category: uiConfig.category || 'sensor',
type: uiConfig.assetType || 'Unknown',
model: uiConfig.model || 'Unknown',
unit: uiConfig.unit || 'unitless'
};
}
// Merge domain-specific sections
Object.assign(config, domainConfig);
return config;
}
/**
* Get the base config schema (shared across all nodes).
* @returns {object} Base config schema
*/
getBaseConfig() {
return this.getConfig('baseConfig');
}
createEndpoint(nodeName) {
try {
// Load the config for this node
const config = this.getConfig(nodeName);
// Convert config to JSON
const configJSON = JSON.stringify(config, null, 2);
// Assemble the complete script
return `
// Create the namespace structure
window.EVOLV = window.EVOLV || {};
window.EVOLV.nodes = window.EVOLV.nodes || {};
window.EVOLV.nodes.${nodeName} = window.EVOLV.nodes.${nodeName} || {};
// Inject the pre-loaded config data directly into the namespace
window.EVOLV.nodes.${nodeName}.config = ${configJSON};
console.log('${nodeName} config loaded and endpoint created');
`;
} catch (error) {
throw new Error(`Failed to create endpoint for '${nodeName}': ${error.message}`);
}
}
}
module.exports = ConfigManager;