2025-10-14 13:51:32 +02:00
<!--
| S88-niveau | Primair (blokkleur) | Tekstkleur |
| ---------------------- | ------------------- | ---------- |
| **Area** | `#0f52a5` | wit |
| **Process Cell** | `#0c99d9` | wit |
| **Unit** | `#50a8d9` | zwart |
| **Equipment (Module)** | `#86bbdd` | zwart |
| **Control Module** | `#a9daee` | zwart |
-->
2025-10-14 08:36:45 +02:00
< script src = "/pumpingStation/menu.js" > < / script > <!-- Load the menu script for dynamic dropdowns -->
< script src = "/pumpingStation/configData.js" > < / script > <!-- Load the config script for node information -->
2025-10-07 18:05:54 +02:00
2025-10-13 11:50:54 +02:00
< script > / / t e s t
2025-10-14 08:36:45 +02:00
RED.nodes.registerType("pumpingStation", {
2025-10-07 18:05:54 +02:00
category: "EVOLV",
2025-10-14 13:51:32 +02:00
color: "#0c99d9", // color for the node based on the S88 schema
2025-10-07 18:05:54 +02:00
defaults: {
// 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
uuid: { value: "" },
supplier: { value: "" },
category: { value: "" },
assetType: { value: "" },
model: { value: "" },
unit: { value: "" },
//logger properties
enableLog: { value: false },
logLevel: { value: "error" },
//physicalAspect
positionVsParent: { value: "" },
positionIcon: { value: "" },
hasDistance: { value: false },
distance: { value: 0 },
distanceUnit: { value: "m" },
distanceDescription: { value: "" }
},
inputs: 1,
outputs: 3,
inputLabels: ["Input"],
outputLabels: ["process", "dbase", "parent"],
2025-10-14 13:51:32 +02:00
icon: "font-awesome/fa-tint",
2025-10-07 18:05:54 +02:00
label: function () {
2025-10-14 13:51:32 +02:00
return this.positionIcon + " " + this.assetType || "pumpingStation";
2025-10-07 18:05:54 +02:00
},
oneditprepare: function() {
const waitForMenuData = () => {
2025-10-14 13:51:32 +02:00
if (window.EVOLV?.nodes?.pumpingStation?.initEditor) {
window.EVOLV.nodes.pumpingStation.initEditor(this);
2025-10-07 18:05:54 +02:00
} else {
setTimeout(waitForMenuData, 50);
}
};
// Wait for the menu data to be ready before initializing the editor
waitForMenuData();
// 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
const smoothMethodSelect = document.getElementById('node-input-smooth_method');
2025-10-14 13:51:32 +02:00
const options = window.EVOLV?.nodes?.pumpingStation?.config?.smoothing?.smoothMethod?.rules?.values || [];
2025-10-07 18:05:54 +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;
}
// --- 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();
//------------------- END OF CUSTOM config UI ELEMENTS ------------------- //
},
oneditsave: function () {
const node = this;
// Validate asset properties using the asset menu
2025-10-14 13:51:32 +02:00
if (window.EVOLV?.nodes?.pumpingStation?.assetMenu?.saveEditor) {
success = window.EVOLV.nodes.pumpingStation.assetMenu.saveEditor(this);
2025-10-07 18:05:54 +02:00
}
// Validate logger properties using the logger menu
2025-10-14 13:51:32 +02:00
if (window.EVOLV?.nodes?.pumpingStation?.loggerMenu?.saveEditor) {
success = window.EVOLV.nodes.pumpingStation.loggerMenu.saveEditor(node);
2025-10-07 18:05:54 +02:00
}
// save position field
2025-10-14 13:51:32 +02:00
if (window.EVOLV?.nodes?.pumpingStation?.positionMenu?.saveEditor) {
window.EVOLV.nodes.pumpingStation.positionMenu.saveEditor(this);
2025-10-07 18:05:54 +02:00
}
// Save basic properties
["smooth_method"].forEach(
(field) => (node[field] = document.getElementById(`node-input-${field}`).value || "")
);
// Save numeric and boolean properties
["scaling", "simulator"].forEach(
(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 -->
2025-10-14 13:51:32 +02:00
< script type = "text/html" data-template-name = "pumpingStation" >
2025-10-07 18:05:54 +02:00
<!-- Scaling Checkbox -->
< div class = "form-row" >
< label for = "node-input-scaling"
>< i class = "fa fa-compress" > < / i > Scaling< / label >
< input type = "checkbox" id = "node-input-scaling" style = "width:20px; vertical-align:baseline;" / >
< span > Enable input scaling?< / span >
< / div >
<!-- Source Min/Max (only if scaling is true) -->
< div class = "form-row" id = "row-input-i_min" >
< label for = "node-input-i_min" > < i class = "fa fa-arrow-down" > < / i > Source Min< / label >
< input type = "number" id = "node-input-i_min" placeholder = "0" / >
< / div >
< div class = "form-row" id = "row-input-i_max" >
< label for = "node-input-i_max" > < i class = "fa fa-arrow-up" > < / i > Source Max< / label >
< input type = "number" id = "node-input-i_max" placeholder = "3000" / >
< / div >
<!-- Offset -->
< div class = "form-row" >
< label for = "node-input-i_offset" > < i class = "fa fa-adjust" > < / i > Input Offset< / label >
< 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" >
< 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;" / >
< span > Activate internal simulation?< / span >
< / div >
<!-- Smoothing Method -->
< div class = "form-row" >
< label for = "node-input-smooth_method" > < i class = "fa fa-line-chart" > < / i > Smoothing< / label >
< select id = "node-input-smooth_method" style = "width:60%;" >
< / select >
< / div >
<!-- Smoothing Window -->
< div class = "form-row" >
< label for = "node-input-count" > Window< / label >
< input type = "number" id = "node-input-count" placeholder = "10" style = "width:60px;" / >
< div class = "form-tips" > Number of samples for smoothing< / div >
< / div >
<!-- Optional Extended Fields: supplier, cat, type, model, unit -->
<!-- Asset fields will be injected here -->
< div id = "asset-fields-placeholder" > < / div >
<!-- loglevel checkbox -->
< div id = "logger-fields-placeholder" > < / div >
<!-- Position fields will be injected here -->
< div id = "position-fields-placeholder" > < / div >
< / script >
2025-10-14 13:51:32 +02:00
< script type = "text/html" data-help-name = "pumpingStation" >
2025-10-07 18:05:54 +02:00
< / script >