2025-05-14 10:31:50 +02:00
2025-06-23 13:23:51 +02:00
< script src = "/measurement/menu.js" > < / script > <!-- Load the menu script for dynamic dropdowns -->
< script src = "/measurement/configData.js" > < / script > <!-- Load the config script for node information -->
2025-06-20 17:14:22 +02:00
2025-06-12 17:05:28 +02:00
< script >
2025-05-14 10:31:50 +02:00
RED.nodes.registerType("measurement", {
2025-06-25 17:25:13 +02:00
category: "EVOLV",
2025-05-14 10:31:50 +02:00
color: "#e4a363",
defaults: {
// Define default properties
2025-07-01 15:24:18 +02:00
name: { value: "" }, // use asset category as name
2025-05-14 10:31:50 +02:00
// Define specific properties
scaling: { value: false },
i_min: { value: 0, required: true },
i_max: { value: 0, required: true },
i_offset: { value: 0 },
o_min: { value: 0, required: true },
o_max: { value: 1, required: true },
simulator: { value: false },
smooth_method: { value: "" },
count: { value: "10", required: true },
//define asset properties
2025-06-25 14:52:20 +02:00
uuid: { value: "" },
2025-05-14 10:31:50 +02:00
supplier: { value: "" },
2025-06-20 17:14:22 +02:00
category: { value: "" },
assetType: { value: "" },
2025-05-14 10:31:50 +02:00
model: { value: "" },
unit: { value: "" },
2025-06-25 10:43:15 +02:00
//logger properties
enableLog: { value: false },
logLevel: { value: "error" },
//physicalAspect
2025-06-25 11:45:32 +02:00
positionVsParent: { value: "" },
2025-07-01 15:24:18 +02:00
positionIcon: { value: "" },
2025-06-25 10:43:15 +02:00
2025-05-14 10:31:50 +02:00
},
inputs: 1,
2025-06-20 17:14:22 +02:00
outputs: 3,
2025-06-25 17:25:13 +02:00
inputLabels: ["Input"],
2025-06-20 17:14:22 +02:00
outputLabels: ["process", "dbase", "parent"],
2025-05-14 10:31:50 +02:00
icon: "font-awesome/fa-tachometer",
label: function () {
2025-07-01 15:24:18 +02:00
return this.positionIcon + " " + this.assetType || "Measurement";
2025-05-14 10:31:50 +02:00
},
2025-06-20 17:14:22 +02:00
2025-05-14 10:31:50 +02:00
oneditprepare: function() {
2025-06-20 17:14:22 +02:00
const waitForMenuData = () => {
if (window.EVOLV?.nodes?.measurement?.initEditor) {
window.EVOLV.nodes.measurement.initEditor(this);
} else {
setTimeout(waitForMenuData, 50);
}
};
2025-06-24 10:48:40 +02:00
// Wait for the menu data to be ready before initializing the editor
2025-06-20 17:14:22 +02:00
waitForMenuData();
2025-06-24 10:48:40 +02:00
2025-06-25 10:43:15 +02:00
// 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)
2025-06-24 10:48:40 +02:00
// Populate smoothing methods dropdown
const smoothMethodSelect = document.getElementById('node-input-smooth_method');
const options = window.EVOLV?.nodes?.measurement?.config?.smoothing?.smoothMethod?.rules?.values || [];
2025-06-25 10:43:15 +02:00
2025-06-24 10:48:40 +02:00
// Clear existing options
smoothMethodSelect.innerHTML = '';
// Add empty option
const emptyOption = document.createElement('option');
emptyOption.value = '';
emptyOption.textContent = 'Select method...';
smoothMethodSelect.appendChild(emptyOption);
// Add smoothing method options
options.forEach(option => {
const optionElement = document.createElement('option');
optionElement.value = option.value;
optionElement.textContent = option.value;
optionElement.title = option.description; // Add tooltip with full description
smoothMethodSelect.appendChild(optionElement);
});
// Set current value if it exists
if (this.smooth_method) {
smoothMethodSelect.value = this.smooth_method;
}
2025-06-25 14:52:20 +02:00
// --- Scale rows toggle ---
const chk = document.getElementById('node-input-scaling');
const rowMin = document.getElementById('row-input-i_min');
const rowMax = document.getElementById('row-input-i_max');
function toggleScalingRows() {
const show = chk.checked;
rowMin.style.display = show ? 'block' : 'none';
rowMax.style.display = show ? 'block' : 'none';
}
// wire and initialize
chk.addEventListener('change', toggleScalingRows);
toggleScalingRows();
2025-06-24 10:48:40 +02:00
//------------------- END OF CUSTOM config UI ELEMENTS ------------------- //
2025-06-20 17:14:22 +02:00
},
2025-05-14 10:31:50 +02:00
oneditsave: function () {
const node = this;
2025-06-24 10:48:40 +02:00
// Validate asset properties using the asset menu
if (window.EVOLV?.nodes?.measurement?.assetMenu?.saveEditor) {
success = window.EVOLV.nodes.measurement.assetMenu.saveEditor(this);
}
2025-05-14 10:31:50 +02:00
2025-06-25 10:43:15 +02:00
// Validate logger properties using the logger menu
if (window.EVOLV?.nodes?.measurement?.loggerMenu?.saveEditor) {
success = window.EVOLV.nodes.measurement.loggerMenu.saveEditor(node);
}
2025-07-01 15:24:18 +02:00
// save position field
2025-07-01 17:02:17 +02:00
if (window.EVOLV?.nodes?.measurement?.positionMenu?.saveEditor) {
2025-07-01 15:24:18 +02:00
window.EVOLV.nodes.rotatingMachine.positionMenu.saveEditor(this);
}
2025-05-14 10:31:50 +02:00
// Save basic properties
2025-06-25 10:43:15 +02:00
["smooth_method"].forEach(
2025-05-14 10:31:50 +02:00
(field) => (node[field] = document.getElementById(`node-input-${field}`).value || "")
);
// Save numeric and boolean properties
2025-06-24 10:48:40 +02:00
["scaling", "simulator"].forEach(
2025-05-14 10:31:50 +02:00
(field) => (node[field] = document.getElementById(`node-input-${field}`).checked)
);
["i_min", "i_max", "i_offset", "o_min", "o_max", "count"].forEach(
(field) => (node[field] = parseFloat(document.getElementById(`node-input-${field}`).value) || 0)
);
// Validation checks
if (node.scaling & & (isNaN(node.i_min) || isNaN(node.i_max))) {
RED.notify("Scaling enabled, but input range is incomplete!", "error");
}
},
});
< / script >
<!-- Main UI -->
< script type = "text/html" data-template-name = "measurement" >
2025-06-25 10:43:15 +02:00
2025-05-14 10:31:50 +02:00
<!-- Scaling Checkbox -->
< div class = "form-row" >
< label for = "node-input-scaling"
2025-06-25 10:43:15 +02:00
>< i class = "fa fa-compress" > < / i > Scaling< / label >
< input type = "checkbox" id = "node-input-scaling" style = "width:20px; vertical-align:baseline;" / >
2025-05-14 10:31:50 +02:00
< span > Enable input scaling?< / span >
< / div >
<!-- Source Min/Max (only if scaling is true) -->
< div class = "form-row" id = "row-input-i_min" >
2025-06-25 10:43:15 +02:00
< label for = "node-input-i_min" > < i class = "fa fa-arrow-down" > < / i > Source Min< / label >
2025-05-14 10:31:50 +02:00
< input type = "number" id = "node-input-i_min" placeholder = "0" / >
< / div >
< div class = "form-row" id = "row-input-i_max" >
2025-06-25 10:43:15 +02:00
< label for = "node-input-i_max" > < i class = "fa fa-arrow-up" > < / i > Source Max< / label >
2025-05-14 10:31:50 +02:00
< input type = "number" id = "node-input-i_max" placeholder = "3000" / >
< / div >
<!-- Offset -->
< div class = "form-row" >
2025-06-25 10:43:15 +02:00
< label for = "node-input-i_offset" > < i class = "fa fa-adjust" > < / i > Input Offset< / label >
2025-05-14 10:31:50 +02:00
< input type = "number" id = "node-input-i_offset" placeholder = "0" / >
< / div >
<!-- Output / Process Min/Max -->
< div class = "form-row" >
< label for = "node-input-o_min" > < i class = "fa fa-tag" > < / i > Process Min< / label >
< input type = "number" id = "node-input-o_min" placeholder = "0" / >
< / div >
< div class = "form-row" >
< label for = "node-input-o_max" > < i class = "fa fa-tag" > < / i > Process Max< / label >
< input type = "number" id = "node-input-o_max" placeholder = "1" / >
< / div >
<!-- Simulator Checkbox -->
< div class = "form-row" >
2025-06-25 10:43:15 +02:00
< label for = "node-input-simulator" > < i class = "fa fa-cog" > < / i > Simulator< / label >
< input type = "checkbox" id = "node-input-simulator" style = "width:20px; vertical-align:baseline;" / >
2025-05-14 10:31:50 +02:00
< span > Activate internal simulation?< / span >
< / div >
<!-- Smoothing Method -->
< div class = "form-row" >
2025-06-25 10:43:15 +02:00
< label for = "node-input-smooth_method" > < i class = "fa fa-line-chart" > < / i > Smoothing< / label >
2025-05-14 10:31:50 +02:00
< select id = "node-input-smooth_method" style = "width:60%;" >
< / select >
< / div >
<!-- Smoothing Window -->
< div class = "form-row" >
< label for = "node-input-count" > Window< / label >
2025-06-25 10:43:15 +02:00
< input type = "number" id = "node-input-count" placeholder = "10" style = "width:60px;" / >
2025-05-14 10:31:50 +02:00
< div class = "form-tips" > Number of samples for smoothing< / div >
< / div >
2025-06-20 17:14:22 +02:00
<!-- Optional Extended Fields: supplier, cat, type, model, unit -->
2025-06-25 10:43:15 +02:00
<!-- Asset fields will be injected here -->
< div id = "asset-fields-placeholder" > < / div >
2025-05-14 10:31:50 +02:00
<!-- loglevel checkbox -->
2025-06-25 10:43:15 +02:00
< div id = "logger-fields-placeholder" > < / div >
2025-05-14 10:31:50 +02:00
2025-06-25 10:43:15 +02:00
<!-- Position fields will be injected here -->
< div id = "position-fields-placeholder" > < / div >
2025-05-14 10:31:50 +02:00
< / script >
< script type = "text/html" data-help-name = "measurement" >
< p > < b > Measurement Node< / b > : Scales, smooths, and simulates measurement data.< / p >
< p > Use this node to scale, smooth, and simulate measurement data. The node can be configured to scale input data to a specified range, smooth the data using a variety of methods, and simulate data for testing purposes.< / p >
< li > < b > Supplier:< / b > Select a supplier to populate machine options.< / li >
< li > < b > SubType:< / b > Select a subtype if applicable to further categorize the asset.< / li >
< li > < b > Model:< / b > Define the specific model for more granular asset configuration.< / li >
< li > < b > Unit:< / b > Assign a unit to standardize measurements or operations.< / li >
< li > < b > Scaling:< / b > Enable or disable input scaling. When enabled, you must provide the source min and max values.< / li >
< li > < b > Source Min/Max:< / b > Define the minimum and maximum values for the input range when scaling is enabled.< / li >
< li > < b > Input Offset:< / b > Specify an offset value to be added to the input measurement.< / li >
< li > < b > Process Min/Max:< / b > Define the minimum and maximum values for the output range after processing.< / li >
< li > < b > Simulator:< / b > Activate internal simulation for testing purposes.< / li >
< li > < b > Smoothing:< / b > Select a smoothing method to apply to the measurement data.< / li >
< li > < b > Window:< / b > Define the number of samples to use for smoothing.< / li >
< li > < b > Enable Log:< / b > Enable or disable logging for this node.< / li >
< li > < b > Log Level:< / b > Select the log level (Info, Debug, Warn, Error) for logging messages.< / li >
< / script >