update
This commit is contained in:
24
index.js
24
index.js
@@ -8,25 +8,27 @@
|
||||
*/
|
||||
|
||||
// Core helper modules
|
||||
const outputUtils = require('./src/helper/outputUtils.js');
|
||||
const logger = require('./src/helper/logger.js');
|
||||
const validation = require('./src/helper/validationUtils.js');
|
||||
const configUtils = require('./src/helper/configUtils.js');
|
||||
const assertions = require('./src/helper/assertionUtils.js')
|
||||
const helper = require('./src/helper/index.js');
|
||||
const {
|
||||
outputUtils,
|
||||
logger,
|
||||
validation,
|
||||
configUtils,
|
||||
assertions,
|
||||
childRegistrationUtils,
|
||||
gravity,
|
||||
} = helper;
|
||||
const coolprop = require('./src/coolprop-node/src/index.js');
|
||||
const gravity = require('./src/helper/gravity.js')
|
||||
const assetApiConfig = require('./src/configs/assetApiConfig.js');
|
||||
|
||||
// Domain-specific modules
|
||||
const { MeasurementContainer } = require('./src/measurements/index.js');
|
||||
const configManager = require('./src/configs/index.js');
|
||||
const nrmse = require('./src/nrmse/errorMetrics.js');
|
||||
const state = require('./src/state/state.js');
|
||||
const { nrmse } = require('./src/nrmse/index.js');
|
||||
const { state } = require('./src/state/index.js');
|
||||
const convert = require('./src/convert/index.js');
|
||||
const MenuManager = require('./src/menu/index.js');
|
||||
const predict = require('./src/predict/predict_class.js');
|
||||
const interpolation = require('./src/predict/interpolation.js');
|
||||
const childRegistrationUtils = require('./src/helper/childRegistrationUtils.js');
|
||||
const { predict, interpolation } = require('./src/predict/index.js');
|
||||
const { loadCurve } = require('./datasets/assetData/curves/index.js'); //deprecated replace with load model data
|
||||
const { loadModel } = require('./datasets/assetData/modelData/index.js');
|
||||
|
||||
|
||||
11
package.json
11
package.json
@@ -9,11 +9,16 @@
|
||||
"./menuUtils": "./src/helper/menuUtils.js",
|
||||
"./mathUtils": "./src/helper/mathUtils.js",
|
||||
"./assetUtils": "./src/helper/assetUtils.js",
|
||||
"./outputUtils": "./src/helper/outputUtils.js"
|
||||
"./outputUtils": "./src/helper/outputUtils.js",
|
||||
"./helper": "./src/helper/index.js",
|
||||
"./state": "./src/state/index.js",
|
||||
"./predict": "./src/predict/index.js",
|
||||
"./nrmse": "./src/nrmse/index.js",
|
||||
"./outliers": "./src/outliers/index.js"
|
||||
},
|
||||
|
||||
"scripts": {
|
||||
"test": "node test.js"
|
||||
"test": "node --test test/*.test.js src/nrmse/errorMetric.test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -26,4 +31,4 @@
|
||||
],
|
||||
"author": "Rene de Ren",
|
||||
"license": "SEE LICENSE"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,8 +6,18 @@ class ChildRegistrationUtils {
|
||||
}
|
||||
|
||||
async registerChild(child, positionVsParent, distance) {
|
||||
const { softwareType } = child.config.functionality;
|
||||
const { name, id } = child.config.general;
|
||||
if (!child || typeof child !== 'object') {
|
||||
this.logger?.warn('registerChild skipped: invalid child payload');
|
||||
return false;
|
||||
}
|
||||
if (!child.config?.functionality || !child.config?.general) {
|
||||
this.logger?.warn('registerChild skipped: missing child config/functionality/general');
|
||||
return false;
|
||||
}
|
||||
|
||||
const softwareType = child.config.functionality.softwareType;
|
||||
const name = child.config.general.name || child.config.general.id || 'unknown';
|
||||
const id = child.config.general.id || name;
|
||||
|
||||
this.logger.debug(`Registering child: ${name} (${id}) as ${softwareType} at ${positionVsParent}`);
|
||||
|
||||
@@ -43,19 +53,21 @@ class ChildRegistrationUtils {
|
||||
}
|
||||
|
||||
this.logger.info(`✅ Child ${name} registered successfully`);
|
||||
return true;
|
||||
}
|
||||
|
||||
_storeChild(child, softwareType) {
|
||||
// Maintain your existing structure
|
||||
if (!this.mainClass.child) this.mainClass.child = {};
|
||||
if (!this.mainClass.child[softwareType]) this.mainClass.child[softwareType] = {};
|
||||
const typeKey = softwareType || 'unknown';
|
||||
if (!this.mainClass.child[typeKey]) this.mainClass.child[typeKey] = {};
|
||||
|
||||
const { category = "sensor" } = child.config.asset || {};
|
||||
if (!this.mainClass.child[softwareType][category]) {
|
||||
this.mainClass.child[softwareType][category] = [];
|
||||
if (!this.mainClass.child[typeKey][category]) {
|
||||
this.mainClass.child[typeKey][category] = [];
|
||||
}
|
||||
|
||||
this.mainClass.child[softwareType][category].push(child);
|
||||
this.mainClass.child[typeKey][category].push(child);
|
||||
}
|
||||
|
||||
// NEW: Utility methods for parent to use
|
||||
@@ -95,4 +107,4 @@ class ChildRegistrationUtils {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChildRegistrationUtils;
|
||||
module.exports = ChildRegistrationUtils;
|
||||
|
||||
@@ -73,17 +73,25 @@ class ConfigUtils {
|
||||
return updatedConfig;
|
||||
}
|
||||
|
||||
_isPlainObject(value) {
|
||||
return Object.prototype.toString.call(value) === '[object Object]';
|
||||
}
|
||||
|
||||
// loop through objects and merge them obj1 will be updated with obj2 values
|
||||
mergeObjects(obj1, obj2) {
|
||||
for (let key in obj2) {
|
||||
if (obj2.hasOwnProperty(key)) {
|
||||
if (typeof obj2[key] === 'object') {
|
||||
if (!obj1[key]) {
|
||||
const nextValue = obj2[key];
|
||||
|
||||
if (Array.isArray(nextValue)) {
|
||||
obj1[key] = [...nextValue];
|
||||
} else if (this._isPlainObject(nextValue)) {
|
||||
if (!this._isPlainObject(obj1[key])) {
|
||||
obj1[key] = {};
|
||||
}
|
||||
this.mergeObjects(obj1[key], obj2[key]);
|
||||
this.mergeObjects(obj1[key], nextValue);
|
||||
} else {
|
||||
obj1[key] = obj2[key];
|
||||
obj1[key] = nextValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,13 +18,102 @@ class EndpointUtils {
|
||||
* @param {string} nodeName the name of the node (used in the URL)
|
||||
* @param {object} customHelpers additional helper functions to inject
|
||||
*/
|
||||
createMenuUtilsEndpoint(RED, nodeName, customHelpers = {}) {
|
||||
RED.httpAdmin.get(`/${nodeName}/resources/menuUtils.js`, (req, res) => {
|
||||
console.log(`Serving menuUtils.js for ${nodeName} node`);
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
const browserCode = this.generateMenuUtilsCode(nodeName, customHelpers);
|
||||
res.send(browserCode);
|
||||
createMenuUtilsEndpoint(RED, nodeName, customHelpers = {}, options = {}) {
|
||||
const basePath = `/${nodeName}/resources`;
|
||||
|
||||
RED.httpAdmin.get(`${basePath}/menuUtilsData.json`, (req, res) => {
|
||||
res.json(this.generateMenuUtilsData(nodeName, customHelpers, options));
|
||||
});
|
||||
|
||||
RED.httpAdmin.get(`${basePath}/menuUtils.legacy.js`, (req, res) => {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
res.send(this.generateLegacyMenuUtilsCode(nodeName, customHelpers));
|
||||
});
|
||||
|
||||
RED.httpAdmin.get(`${basePath}/menuUtils.js`, (req, res) => {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
res.send(this.generateMenuUtilsBootstrap(nodeName));
|
||||
});
|
||||
}
|
||||
|
||||
generateMenuUtilsData(nodeName, customHelpers = {}, options = {}) {
|
||||
const defaultHelpers = {
|
||||
validateRequired: `function(value) {
|
||||
return value != null && value.toString().trim() !== '';
|
||||
}`,
|
||||
formatDisplayValue: `function(value, unit) {
|
||||
return \`${'${'}value} ${'${'}unit || ''}\`.trim();
|
||||
}`,
|
||||
validateScaling: `function(min, max) {
|
||||
return !isNaN(min) && !isNaN(max) && Number(min) < Number(max);
|
||||
}`,
|
||||
validateUnit: `function(unit) {
|
||||
return typeof unit === 'string' && unit.trim() !== '';
|
||||
}`,
|
||||
};
|
||||
|
||||
return {
|
||||
nodeName,
|
||||
helpers: { ...defaultHelpers, ...customHelpers },
|
||||
options: {
|
||||
autoLoadLegacy: options.autoLoadLegacy !== false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
generateMenuUtilsBootstrap(nodeName) {
|
||||
return `
|
||||
// Stable bootstrap for EVOLV menu utils (${nodeName})
|
||||
(function() {
|
||||
const nodeName = ${JSON.stringify(nodeName)};
|
||||
const basePath = '/' + nodeName + '/resources';
|
||||
|
||||
window.EVOLV = window.EVOLV || {};
|
||||
window.EVOLV.nodes = window.EVOLV.nodes || {};
|
||||
window.EVOLV.nodes[nodeName] = window.EVOLV.nodes[nodeName] || {};
|
||||
window.EVOLV.nodes[nodeName].utils = window.EVOLV.nodes[nodeName].utils || {};
|
||||
|
||||
function parseHelper(fnBody) {
|
||||
try {
|
||||
return (new Function('return (' + fnBody + ')'))();
|
||||
} catch (error) {
|
||||
console.error('[menuUtils] helper parse failed:', error);
|
||||
return function() { return null; };
|
||||
}
|
||||
}
|
||||
|
||||
function loadLegacyIfNeeded(autoLoadLegacy) {
|
||||
if (!autoLoadLegacy || typeof window.MenuUtils === 'function') return Promise.resolve();
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = basePath + '/menuUtils.legacy.js';
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
fetch(basePath + '/menuUtilsData.json')
|
||||
.then(function(res) { return res.json(); })
|
||||
.then(function(payload) {
|
||||
const helperFns = {};
|
||||
Object.entries(payload.helpers || {}).forEach(function(entry) {
|
||||
helperFns[entry[0]] = parseHelper(entry[1]);
|
||||
});
|
||||
|
||||
window.EVOLV.nodes[nodeName].utils.helpers = helperFns;
|
||||
return loadLegacyIfNeeded(payload.options && payload.options.autoLoadLegacy);
|
||||
})
|
||||
.then(function() {
|
||||
if (typeof window.MenuUtils === 'function' && !window.EVOLV.nodes[nodeName].utils.menuUtils) {
|
||||
window.EVOLV.nodes[nodeName].utils.menuUtils = new window.MenuUtils();
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error('[menuUtils] bootstrap failed for ' + nodeName, error);
|
||||
});
|
||||
})();
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,7 +122,7 @@ class EndpointUtils {
|
||||
* @param {object} customHelpers map of name: functionString pairs
|
||||
* @returns {string} a JS snippet to run in the browser
|
||||
*/
|
||||
generateMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
generateLegacyMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
// Default helper implementations to expose alongside MenuUtils
|
||||
const defaultHelpers = {
|
||||
validateRequired: `function(value) {
|
||||
@@ -101,6 +190,11 @@ ${helpersCode}
|
||||
console.log('Loaded EVOLV.nodes.${nodeName}.utils.menuUtils');
|
||||
`;
|
||||
}
|
||||
|
||||
// Backward-compatible alias.
|
||||
generateMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
return this.generateLegacyMenuUtilsCode(nodeName, customHelpers);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EndpointUtils;
|
||||
|
||||
25
src/helper/index.js
Normal file
25
src/helper/index.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const assertions = require('./assertionUtils.js');
|
||||
const assetUtils = require('./assetUtils.js');
|
||||
const childRegistrationUtils = require('./childRegistrationUtils.js');
|
||||
const configUtils = require('./configUtils.js');
|
||||
const endpointUtils = require('./endpointUtils.js');
|
||||
const gravity = require('./gravity.js');
|
||||
const logger = require('./logger.js');
|
||||
const menuUtils = require('./menuUtils.js');
|
||||
const nodeTemplates = require('./nodeTemplates.js');
|
||||
const outputUtils = require('./outputUtils.js');
|
||||
const validation = require('./validationUtils.js');
|
||||
|
||||
module.exports = {
|
||||
assertions,
|
||||
assetUtils,
|
||||
childRegistrationUtils,
|
||||
configUtils,
|
||||
endpointUtils,
|
||||
gravity,
|
||||
logger,
|
||||
menuUtils,
|
||||
nodeTemplates,
|
||||
outputUtils,
|
||||
validation,
|
||||
};
|
||||
@@ -480,17 +480,26 @@ generateHtml(htmlElement, options, savedValue) {
|
||||
}
|
||||
}
|
||||
|
||||
createMenuUtilsEndpoint(RED, nodeName, customHelpers = {}) {
|
||||
RED.httpAdmin.get(`/${nodeName}/resources/menuUtils.js`, function(req, res) {
|
||||
console.log(`Serving menuUtils.js for ${nodeName} node`);
|
||||
createMenuUtilsEndpoint(RED, nodeName, customHelpers = {}, options = {}) {
|
||||
const basePath = `/${nodeName}/resources`;
|
||||
|
||||
RED.httpAdmin.get(`${basePath}/menuUtilsData.json`, function(req, res) {
|
||||
res.json(this.generateMenuUtilsData(nodeName, customHelpers, options));
|
||||
}.bind(this));
|
||||
|
||||
RED.httpAdmin.get(`${basePath}/menuUtils.legacy.js`, function(req, res) {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
|
||||
const browserCode = this.generateMenuUtilsCode(nodeName, customHelpers);
|
||||
const browserCode = this.generateLegacyMenuUtilsCode(nodeName, customHelpers);
|
||||
res.send(browserCode);
|
||||
}.bind(this));
|
||||
|
||||
RED.httpAdmin.get(`${basePath}/menuUtils.js`, function(req, res) {
|
||||
res.set('Content-Type', 'application/javascript');
|
||||
res.send(this.generateMenuUtilsBootstrap(nodeName));
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
generateMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
generateMenuUtilsData(nodeName, customHelpers = {}, options = {}) {
|
||||
const defaultHelpers = {
|
||||
validateRequired: `function(value) {
|
||||
return value && value.toString().trim() !== '';
|
||||
@@ -500,7 +509,71 @@ generateMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
}`
|
||||
};
|
||||
|
||||
const allHelpers = { ...defaultHelpers, ...customHelpers };
|
||||
return {
|
||||
nodeName,
|
||||
helpers: { ...defaultHelpers, ...customHelpers },
|
||||
options: {
|
||||
autoLoadLegacy: options.autoLoadLegacy !== false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
generateMenuUtilsBootstrap(nodeName) {
|
||||
return `
|
||||
// Stable bootstrap for EVOLV menu utils (${nodeName})
|
||||
(function() {
|
||||
const nodeName = ${JSON.stringify(nodeName)};
|
||||
const basePath = '/' + nodeName + '/resources';
|
||||
|
||||
window.EVOLV = window.EVOLV || {};
|
||||
window.EVOLV.nodes = window.EVOLV.nodes || {};
|
||||
window.EVOLV.nodes[nodeName] = window.EVOLV.nodes[nodeName] || {};
|
||||
window.EVOLV.nodes[nodeName].utils = window.EVOLV.nodes[nodeName].utils || {};
|
||||
|
||||
function parseHelper(fnBody) {
|
||||
try {
|
||||
return (new Function('return (' + fnBody + ')'))();
|
||||
} catch (error) {
|
||||
console.error('[menuUtils] helper parse failed:', error);
|
||||
return function() { return null; };
|
||||
}
|
||||
}
|
||||
|
||||
function loadLegacyIfNeeded(autoLoadLegacy) {
|
||||
if (!autoLoadLegacy || typeof window.MenuUtils === 'function') return Promise.resolve();
|
||||
return new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = basePath + '/menuUtils.legacy.js';
|
||||
script.onload = resolve;
|
||||
script.onerror = reject;
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
|
||||
fetch(basePath + '/menuUtilsData.json')
|
||||
.then(function(res) { return res.json(); })
|
||||
.then(function(payload) {
|
||||
const helperFns = {};
|
||||
Object.entries(payload.helpers || {}).forEach(function(entry) {
|
||||
helperFns[entry[0]] = parseHelper(entry[1]);
|
||||
});
|
||||
window.EVOLV.nodes[nodeName].utils.helpers = helperFns;
|
||||
return loadLegacyIfNeeded(payload.options && payload.options.autoLoadLegacy);
|
||||
})
|
||||
.then(function() {
|
||||
if (typeof window.MenuUtils === 'function' && !window.EVOLV.nodes[nodeName].utils.menuUtils) {
|
||||
window.EVOLV.nodes[nodeName].utils.menuUtils = new window.MenuUtils();
|
||||
}
|
||||
})
|
||||
.catch(function(error) {
|
||||
console.error('[menuUtils] bootstrap failed for ' + nodeName, error);
|
||||
});
|
||||
})();
|
||||
`;
|
||||
}
|
||||
|
||||
generateLegacyMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
const allHelpers = { ...this.generateMenuUtilsData(nodeName).helpers, ...customHelpers };
|
||||
|
||||
const helpersCode = Object.entries(allHelpers)
|
||||
.map(([name, func]) => ` ${name}: ${func}`)
|
||||
@@ -533,6 +606,11 @@ ${helpersCode}
|
||||
`;
|
||||
}
|
||||
|
||||
// Backward-compatible alias
|
||||
generateMenuUtilsCode(nodeName, customHelpers = {}) {
|
||||
return this.generateLegacyMenuUtilsCode(nodeName, customHelpers);
|
||||
}
|
||||
|
||||
module.exports = MenuUtils;
|
||||
}
|
||||
|
||||
module.exports = MenuUtils;
|
||||
|
||||
@@ -53,4 +53,4 @@ const nodeTemplates = {
|
||||
// …add more node “templates” here…
|
||||
};
|
||||
|
||||
export default nodeTemplates;
|
||||
module.exports = nodeTemplates;
|
||||
|
||||
@@ -7,6 +7,9 @@ class OutputUtils {
|
||||
}
|
||||
|
||||
checkForChanges(output, format) {
|
||||
if (!output || typeof output !== 'object') {
|
||||
return {};
|
||||
}
|
||||
const changedFields = {};
|
||||
for (const key in output) {
|
||||
if (output.hasOwnProperty(key) && output[key] !== this.output[format][key]) {
|
||||
@@ -54,11 +57,11 @@ class OutputUtils {
|
||||
break;
|
||||
|
||||
default:
|
||||
console.log('Unknown format in output utils');
|
||||
break;
|
||||
return null;
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ const convertModule = require('../convert/index');
|
||||
|
||||
class MeasurementContainer {
|
||||
constructor(options = {},logger) {
|
||||
this.logger = logger || null;
|
||||
this.emitter = new EventEmitter();
|
||||
this.measurements = {};
|
||||
this.windowSize = options.windowSize || 10; // Default window size
|
||||
@@ -96,7 +97,10 @@ class MeasurementContainer {
|
||||
|
||||
variant(variantName) {
|
||||
if (!this._currentType) {
|
||||
throw new Error('Type must be specified before variant');
|
||||
if (this.logger) {
|
||||
this.logger.warn('variant() ignored: type must be specified before variant');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
this._currentVariant = variantName;
|
||||
this._currentPosition = null;
|
||||
@@ -106,11 +110,13 @@ class MeasurementContainer {
|
||||
|
||||
position(positionValue) {
|
||||
if (!this._currentVariant) {
|
||||
throw new Error('Variant must be specified before position');
|
||||
if (this.logger) {
|
||||
this.logger.warn('position() ignored: variant must be specified before position');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
this._currentPosition = positionValue.toString().toLowerCase();;
|
||||
this._currentPosition = positionValue.toString().toLowerCase();
|
||||
|
||||
return this;
|
||||
}
|
||||
@@ -429,7 +435,10 @@ class MeasurementContainer {
|
||||
// Difference calculations between positions
|
||||
difference({ from = "downstream", to = "upstream", unit: requestedUnit } = {}) {
|
||||
if (!this._currentType || !this._currentVariant) {
|
||||
throw new Error("Type and variant must be specified for difference calculation");
|
||||
if (this.logger) {
|
||||
this.logger.warn('difference() ignored: type and variant must be specified');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const get = pos => {
|
||||
@@ -510,7 +519,10 @@ class MeasurementContainer {
|
||||
|
||||
getVariants() {
|
||||
if (!this._currentType) {
|
||||
throw new Error('Type must be specified before listing variants');
|
||||
if (this.logger) {
|
||||
this.logger.warn('getVariants() ignored: type must be specified first');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
return this.measurements[this._currentType] ?
|
||||
Object.keys(this.measurements[this._currentType]) : [];
|
||||
@@ -518,7 +530,10 @@ class MeasurementContainer {
|
||||
|
||||
getPositions() {
|
||||
if (!this._currentType || !this._currentVariant) {
|
||||
throw new Error('Type and variant must be specified before listing positions');
|
||||
if (this.logger) {
|
||||
this.logger.warn('getPositions() ignored: type and variant must be specified first');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
if (!this.measurements[this._currentType] ||
|
||||
@@ -628,7 +643,10 @@ class MeasurementContainer {
|
||||
if (positionValue > 0) {
|
||||
return "downstream";
|
||||
}
|
||||
console.log(`Invalid position provided: ${positionValue}`);
|
||||
if (this.logger) {
|
||||
this.logger.warn(`Invalid position provided: ${positionValue}`);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
7
src/nrmse/index.js
Normal file
7
src/nrmse/index.js
Normal file
@@ -0,0 +1,7 @@
|
||||
const nrmse = require('./errorMetrics.js');
|
||||
const nrmseConfig = require('./nrmseConfig.json');
|
||||
|
||||
module.exports = {
|
||||
nrmse,
|
||||
nrmseConfig,
|
||||
};
|
||||
5
src/outliers/index.js
Normal file
5
src/outliers/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
const outlierDetection = require('./outlierDetection.js');
|
||||
|
||||
module.exports = {
|
||||
outlierDetection,
|
||||
};
|
||||
@@ -61,6 +61,8 @@ class DynamicClusterDeviation {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DynamicClusterDeviation;
|
||||
|
||||
// Rolling window simulation with outlier detection
|
||||
/*
|
||||
const detector = new DynamicClusterDeviation();
|
||||
@@ -86,4 +88,4 @@ dataStream.forEach((value, index) => {
|
||||
});
|
||||
|
||||
console.log("\nFinal detector cluster states:", JSON.stringify(detector.clusters, null, 2));
|
||||
*/
|
||||
*/
|
||||
|
||||
9
src/predict/index.js
Normal file
9
src/predict/index.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const predict = require('./predict_class.js');
|
||||
const interpolation = require('./interpolation.js');
|
||||
const predictConfig = require('./predictConfig.json');
|
||||
|
||||
module.exports = {
|
||||
predict,
|
||||
interpolation,
|
||||
predictConfig,
|
||||
};
|
||||
11
src/state/index.js
Normal file
11
src/state/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const state = require('./state.js');
|
||||
const stateManager = require('./stateManager.js');
|
||||
const movementManager = require('./movementManager.js');
|
||||
const stateConfig = require('./stateConfig.json');
|
||||
|
||||
module.exports = {
|
||||
state,
|
||||
stateManager,
|
||||
movementManager,
|
||||
stateConfig,
|
||||
};
|
||||
26
test/endpoint-utils.test.js
Normal file
26
test/endpoint-utils.test.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const EndpointUtils = require('../src/helper/endpointUtils.js');
|
||||
|
||||
test('generateMenuUtilsData returns helpers and compatibility options', () => {
|
||||
const endpointUtils = new EndpointUtils();
|
||||
const data = endpointUtils.generateMenuUtilsData('measurement', {
|
||||
customCheck: 'function(value) { return !!value; }',
|
||||
});
|
||||
|
||||
assert.equal(data.nodeName, 'measurement');
|
||||
assert.equal(typeof data.helpers.validateRequired, 'string');
|
||||
assert.equal(typeof data.helpers.customCheck, 'string');
|
||||
assert.equal(data.options.autoLoadLegacy, true);
|
||||
});
|
||||
|
||||
test('generateMenuUtilsBootstrap points to data and legacy endpoints', () => {
|
||||
const endpointUtils = new EndpointUtils();
|
||||
const script = endpointUtils.generateMenuUtilsBootstrap('measurement');
|
||||
|
||||
assert.match(script, /menuUtilsData\.json/);
|
||||
assert.match(script, /menuUtils\.legacy\.js/);
|
||||
assert.match(script, /window\.EVOLV\.nodes/);
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ test('process format emits message with changed fields only', () => {
|
||||
assert.deepEqual(first.payload, { a: 1, b: 2 });
|
||||
|
||||
const second = out.formatMsg({ a: 1, b: 2 }, config, 'process');
|
||||
assert.equal(second, undefined);
|
||||
assert.equal(second, null);
|
||||
|
||||
const third = out.formatMsg({ a: 1, b: 3, c: { x: 1 } }, config, 'process');
|
||||
assert.deepEqual(third.payload, { b: 3, c: JSON.stringify({ x: 1 }) });
|
||||
|
||||
Reference in New Issue
Block a user