updates for standaardisation

This commit is contained in:
znetsixe
2025-06-25 10:43:15 +02:00
parent 0f855a8d2f
commit 0feff2e0fe
3 changed files with 49 additions and 107 deletions

View File

@@ -9,9 +9,7 @@
defaults: { defaults: {
// Define default properties // Define default properties
name: { value: "", required: true }, name: { value: "", required: true }, // use asset category as name
enableLog: { value: false },
logLevel: { value: "error" },
// Define specific properties // Define specific properties
scaling: { value: false }, scaling: { value: false },
@@ -31,6 +29,13 @@
model: { value: "" }, model: { value: "" },
unit: { value: "" }, unit: { value: "" },
//logger properties
enableLog: { value: false },
logLevel: { value: "error" },
//physicalAspect
physicalAspect: { value: "" },
}, },
inputs: 1, inputs: 1,
@@ -54,11 +59,11 @@
// Wait for the menu data to be ready before initializing the editor // Wait for the menu data to be ready before initializing the editor
waitForMenuData(); waitForMenuData();
// --------------- Initialize the dropdowns and other specific UI elements -------------- this should be derived from the config in the future (make config based menu) // THIS IS NODE SPECIFIC --------------- Initialize the dropdowns and other specific UI elements -------------- this should be derived from the config in the future (make config based menu)
// Populate smoothing methods dropdown // Populate smoothing methods dropdown
const smoothMethodSelect = document.getElementById('node-input-smooth_method'); const smoothMethodSelect = document.getElementById('node-input-smooth_method');
const options = window.EVOLV?.nodes?.measurement?.config?.smoothing?.smoothMethod?.rules?.values || []; const options = window.EVOLV?.nodes?.measurement?.config?.smoothing?.smoothMethod?.rules?.values || [];
console.log("Smoothing methods options:", options);
// Clear existing options // Clear existing options
smoothMethodSelect.innerHTML = ''; smoothMethodSelect.innerHTML = '';
@@ -92,8 +97,13 @@
success = window.EVOLV.nodes.measurement.assetMenu.saveEditor(this); success = window.EVOLV.nodes.measurement.assetMenu.saveEditor(this);
} }
// Validate logger properties using the logger menu
if (window.EVOLV?.nodes?.measurement?.loggerMenu?.saveEditor) {
success = window.EVOLV.nodes.measurement.loggerMenu.saveEditor(node);
}
// Save basic properties // Save basic properties
["name", "smooth_method"].forEach( ["smooth_method"].forEach(
(field) => (node[field] = document.getElementById(`node-input-${field}`).value || "") (field) => (node[field] = document.getElementById(`node-input-${field}`).value || "")
); );
@@ -106,17 +116,11 @@
(field) => (node[field] = parseFloat(document.getElementById(`node-input-${field}`).value) || 0) (field) => (node[field] = parseFloat(document.getElementById(`node-input-${field}`).value) || 0)
); );
node.logLevel = document.getElementById("node-input-logLevel").value || "info";
node.enableLog = document.getElementById("node-input-enableLog").checked;
// Validation checks // Validation checks
if (node.scaling && (isNaN(node.i_min) || isNaN(node.i_max))) { if (node.scaling && (isNaN(node.i_min) || isNaN(node.i_max))) {
RED.notify("Scaling enabled, but input range is incomplete!", "error"); RED.notify("Scaling enabled, but input range is incomplete!", "error");
} }
}, },
}); });
</script> </script>
@@ -124,48 +128,30 @@
<!-- Main UI --> <!-- Main UI -->
<script type="text/html" data-template-name="measurement"> <script type="text/html" data-template-name="measurement">
<!-- Node Name -->
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input
type="text"
id="node-input-name"
placeholder="Measurement Name"
style="width:70%;"
/>
</div>
<!-- Scaling Checkbox --> <!-- Scaling Checkbox -->
<div class="form-row"> <div class="form-row">
<label for="node-input-scaling" <label for="node-input-scaling"
><i class="fa fa-compress"></i> Scaling</label ><i class="fa fa-compress"></i> Scaling</label>
> <input type="checkbox" id="node-input-scaling" style="width:20px; vertical-align:baseline;"/>
<input
type="checkbox"
id="node-input-scaling"
style="width:20px; vertical-align:baseline;"
/>
<span>Enable input scaling?</span> <span>Enable input scaling?</span>
</div> </div>
<!-- Source Min/Max (only if scaling is true) --> <!-- Source Min/Max (only if scaling is true) -->
<div class="form-row" id="row-input-i_min"> <div class="form-row" id="row-input-i_min">
<label for="node-input-i_min" <label for="node-input-i_min"><i class="fa fa-arrow-down"></i> Source Min</label>
><i class="fa fa-arrow-down"></i> Source Min</label>
<input type="number" id="node-input-i_min" placeholder="0" /> <input type="number" id="node-input-i_min" placeholder="0" />
</div> </div>
<div class="form-row" id="row-input-i_max"> <div class="form-row" id="row-input-i_max">
<label for="node-input-i_max" <label for="node-input-i_max"><i class="fa fa-arrow-up"></i> Source Max</label>
><i class="fa fa-arrow-up"></i> Source Max</label>
<input type="number" id="node-input-i_max" placeholder="3000" /> <input type="number" id="node-input-i_max" placeholder="3000" />
</div> </div>
<!-- Offset --> <!-- Offset -->
<div class="form-row"> <div class="form-row">
<label for="node-input-i_offset" <label for="node-input-i_offset"><i class="fa fa-adjust"></i> Input Offset</label>
><i class="fa fa-adjust"></i> Input Offset</label>
<input type="number" id="node-input-i_offset" placeholder="0" /> <input type="number" id="node-input-i_offset" placeholder="0" />
</div> </div>
@@ -181,20 +167,14 @@
<!-- Simulator Checkbox --> <!-- Simulator Checkbox -->
<div class="form-row"> <div class="form-row">
<label for="node-input-simulator" <label for="node-input-simulator"><i class="fa fa-cog"></i> Simulator</label>
><i class="fa fa-cog"></i> Simulator</label> <input type="checkbox" id="node-input-simulator" style="width:20px; vertical-align:baseline;"/>
<input
type="checkbox"
id="node-input-simulator"
style="width:20px; vertical-align:baseline;"
/>
<span>Activate internal simulation?</span> <span>Activate internal simulation?</span>
</div> </div>
<!-- Smoothing Method --> <!-- Smoothing Method -->
<div class="form-row"> <div class="form-row">
<label for="node-input-smooth_method" <label for="node-input-smooth_method"><i class="fa fa-line-chart"></i> Smoothing</label>
><i class="fa fa-line-chart"></i> Smoothing</label>
<select id="node-input-smooth_method" style="width:60%;"> <select id="node-input-smooth_method" style="width:60%;">
</select> </select>
</div> </div>
@@ -202,61 +182,19 @@
<!-- Smoothing Window --> <!-- Smoothing Window -->
<div class="form-row"> <div class="form-row">
<label for="node-input-count">Window</label> <label for="node-input-count">Window</label>
<input <input type="number" id="node-input-count" placeholder="10" style="width:60px;"/>
type="number"
id="node-input-count"
placeholder="10"
style="width:60px;"
/>
<div class="form-tips">Number of samples for smoothing</div> <div class="form-tips">Number of samples for smoothing</div>
</div> </div>
<!-- Optional Extended Fields: supplier, cat, type, model, unit --> <!-- Optional Extended Fields: supplier, cat, type, model, unit -->
<hr /> <!-- Asset fields will be injected here -->
<div class="form-row"> <div id="asset-fields-placeholder"></div>
<label for="node-input-supplier"><i class="fa fa-industry"></i> Supplier</label>
<select id="node-input-supplier" style="width:70%;"></select>
</div>
<div class="form-row">
<label for="node-input-category"><i class="fa fa-sitemap"></i> Category</label>
<select id="node-input-category" style="width:70%;"></select>
</div>
<div class="form-row">
<label for="node-input-assetType"><i class="fa fa-puzzle-piece"></i> Type</label>
<select id="node-input-assetType" style="width:70%;"></select>
</div>
<div class="form-row">
<label for="node-input-model"><i class="fa fa-wrench"></i> Model</label>
<select id="node-input-model" style="width:70%;"></select>
</div>
<div class="form-row">
<label for="node-input-unit"><i class="fa fa-balance-scale"></i> Unit</label>
<select id="node-input-unit" style="width:70%;"></select>
</div>
<hr />
<!-- loglevel checkbox --> <!-- loglevel checkbox -->
<div class="form-row"> <div id="logger-fields-placeholder"></div>
<label for="node-input-enableLog"
><i class="fa fa-cog"></i> Enable Log</label>
<input
type="checkbox"
id="node-input-enableLog"
style="width:20px; vertical-align:baseline;"
/>
<span>Enable logging</span>
</div>
<div class="form-row" id="row-logLevel"> <!-- Position fields will be injected here -->
<label for="node-input-logLevel"><i class="fa fa-cog"></i> Log Level</label> <div id="position-fields-placeholder"></div>
<select id="node-input-logLevel" style="width:60%;">
<option value="info">Info</option>
<option value="debug">Debug</option>
<option value="warn">Warn</option>
<option value="error">Error</option>
</select>
</div>
</script> </script>

View File

@@ -2,10 +2,11 @@
* Thin wrapper that registers a node with Node-RED and exposes HTTP endpoints. and loads EVOLV in a standard way * Thin wrapper that registers a node with Node-RED and exposes HTTP endpoints. and loads EVOLV in a standard way
*/ */
const nodeClass = require('./src/nodeClass.js'); const nameOfNode = 'measurement'; // this is the name of the node, it should match the file name and the node type in Node-RED
const nodeClass = require('./src/nodeClass.js'); // this is the specific node class
const { MenuManager, configManager } = require('generalFunctions'); const { MenuManager, configManager } = require('generalFunctions');
const nameOfNode = 'measurement';
// This is the main entry point for the Node-RED node, it will register the node and setup the endpoints
module.exports = function(RED) { module.exports = function(RED) {
// Register the node type // Register the node type
RED.nodes.registerType(nameOfNode, function(config) { RED.nodes.registerType(nameOfNode, function(config) {
@@ -17,14 +18,15 @@ module.exports = function(RED) {
}); });
// Setup admin UIs // Setup admin UIs
const menuMgr = new MenuManager(); const menuMgr = new MenuManager(); //this will handle the menu endpoints so we can load them dynamically
const cfgMgr = new configManager(); const cfgMgr = new configManager(); // this will handle the config endpoints so we can load them dynamically
console.log(`Loading endpoint for ${nameOfNode} menu...`); console.log(`Loading endpoint for ${nameOfNode} menu...`);
// Register the menu for the measurement node
// Register the different menu's for the measurement node (in the future we could automate this further by refering to the config)
RED.httpAdmin.get('/measurement/menu.js', (req, res) => { RED.httpAdmin.get('/measurement/menu.js', (req, res) => {
try { try {
const script = menuMgr.createEndpoint(nameOfNode, ['asset']); const script = menuMgr.createEndpoint(nameOfNode, ['asset','logger','position']);
res.type('application/javascript').send(script); res.type('application/javascript').send(script);
} catch (err) { } catch (err) {
res.status(500).send(`// Error generating menu: ${err.message}`); res.status(500).send(`// Error generating menu: ${err.message}`);
@@ -32,7 +34,8 @@ module.exports = function(RED) {
}); });
console.log(`Loading endpoint for ${nameOfNode} config...`); console.log(`Loading endpoint for ${nameOfNode} config...`);
// Endpoint to get the configuration data for the measurement node
// Endpoint to get the configuration data for the specific node
RED.httpAdmin.get(`/measurement/configData.js`, (req, res) => { RED.httpAdmin.get(`/measurement/configData.js`, (req, res) => {
try { try {
const script = cfgMgr.createEndpoint(nameOfNode); const script = cfgMgr.createEndpoint(nameOfNode);

View File

@@ -48,17 +48,17 @@ class MeasurementNode {
this.config = { this.config = {
general: { general: {
name: uiConfig.name, name: uiConfig.name,
id: this.id, id: uiConfig.id, //need to add this later use node.uuid from a single project file thats unique per location + node-red environment + node
unit: uiConfig.unit, unit: uiConfig.unit, // add converter options later to convert to default units (need like a model that defines this which units we are going to use and then conver to those standards)
logging: { logging: {
enabled: uiConfig.enableLog, enabled: uiConfig.enableLog,
logLevel: uiConfig.logLevel logLevel: uiConfig.logLevel
} }
}, },
asset: { asset: {
tagCode: uiConfig.assetTagCode, tagCode: uiConfig.assetTagCode, //need to add this later to the asset model
supplier: uiConfig.supplier, supplier: uiConfig.supplier,
category: uiConfig.category, category: uiConfig.category, //add later to define as the software type
type: uiConfig.assetType, type: uiConfig.assetType,
model: uiConfig.model, model: uiConfig.model,
unit: uiConfig.unit unit: uiConfig.unit
@@ -77,7 +77,8 @@ class MeasurementNode {
}, },
simulation: { simulation: {
enabled: uiConfig.simulator enabled: uiConfig.simulator
} },
positionVsParent: uiConfig.position || 'atEquipment', // default to 'atEquipment' if not set
}; };
// Utility for formatting outputs // Utility for formatting outputs
@@ -92,7 +93,7 @@ class MeasurementNode {
} }
/** /**
* Bind Measurement events to Node-RED status updates. Using internal emitter. * Bind Measurement events to Node-RED status updates. Using internal emitter. --> REMOVE LATER WE NEED ONLY COMPLETE CHILDS AND THEN CHECK FOR UPDATES
*/ */
_bindEvents() { _bindEvents() {
this.source.emitter.on('mAbs', (val) => { this.source.emitter.on('mAbs', (val) => {
@@ -109,7 +110,7 @@ class MeasurementNode {
this.node.send([ this.node.send([
null, null,
null, null,
{ topic: 'registerChild', payload: this.id, positionVsParent: 'upstream' } { topic: 'registerChild', payload: this.id, positionVsParent: this.config.functionality.positionVsParent }
]); ]);
}, 100); }, 100);
} }