Files
machineGroupControl/mgc.html
znetsixe 4cb9c5084c feat(mgc): editor defaults, compact status badge, mode-case fix, real example flows + dashboard
Editor (mgc.html)
- Drag-in defaults now expose mode (optimalControl) and scaling (normalized)
  via dropdowns in the edit dialog. Was: no control fields in the UI at all,
  so users had to send set.mode/set.scaling after deploy or live with the
  hidden schema defaults.

Wire-up (src/nodeClass.js)
- buildDomainConfig now bridges the flat editor fields (mode, scaling) into
  the nested schema shape (mode.current, scaling.current). Was: returned {}
  so the editor's mode/scaling never reached the runtime.

Mode-case bug fix (src/specificClass.js)
- Schema enum values are camelCase (optimalControl, priorityControl) but the
  runtime switch in _runDispatch matched lowercase only. With the default
  config, dispatch silently fell through to the warning branch and nothing
  ran. Normalise via String(this.mode).toLowerCase() so both forms work.

Status badge (src/io/output.js)
- Compacted from ~80 chars (mode | Ⓝ: 💨=Q/Qmax | =P | N machine(s)) to
  ~50 chars (mode | norm | Q=Q/Qmax m³/h | P=P kW | active/total x).
  Drops emoji glyphs that rendered inconsistently across themes; uses the
  same dot+fill convention as pumpingStation.

Output extension (src/io/output.js)
- getOutput() now also emits flowCapacityMin/Max, machineCount,
  machineCountActive. Was: only group-level totals + dist-from-peak +
  mode/scaling, so dashboards couldn't show capacity / active count
  without subscribing to each rotatingMachine individually.

Examples
- Drop pre-refactor stubs (basic.flow.json, integration.flow.json,
  edge.flow.json). They had a single MGC + inject + debug, no children,
  and never dispatched anything.
- 01-Basic.json: 1 MGC + 3 rotatingMachine pumps + Setup once-fires
  virtualControl + cmd.startup on all pumps via fan-out function. Numbered
  driver groups for Control mode / Scaling / Operator demand. Pumps
  register with MGC via Port 2 (child.register, automatic).
- 02-Dashboard.json: same plumbing + FlowFuse Dashboard 2.0 page with
  Controls (mode + scaling buttons, demand slider 0–100, stop + init
  buttons), Status (7 ui-text rows), Trends (3 charts: flow + capacity,
  power, BEP rel %), and a raw-output ui-template dumping every Port 0
  field. Fan-out function caches last-known values so deltas don't blank.

Wiki + README
- examples/README.md rewritten for the two-file set with canonical command
  surface table and "what to try" recipes.
- wiki/Home.md §11 (Examples) updated; §14 #4 (TODO flow item) replaced
  with the actual current limitation (no per-pump fan-out on Port 0).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 15:24:03 +02:00

138 lines
5.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
| S88-niveau | Primair (blokkleur) | Tekstkleur |
| ---------------------- | ------------------- | ---------- |
| **Area** | `#0f52a5` | wit |
| **Process Cell** | `#0c99d9` | wit |
| **Unit** | `#50a8d9` | zwart |
| **Equipment (Module)** | `#86bbdd` | zwart |
| **Control Module** | `#a9daee` | zwart |
-->
<script src="/machineGroupControl/menu.js"></script> <!-- Load the menu script for dynamic dropdowns -->
<script src="/machineGroupControl/configData.js"></script> <!-- Load the config script for node information -->
<script>
RED.nodes.registerType('machineGroupControl',{
category: "EVOLV",
color: "#50a8d9",
defaults: {
// Define default properties
name: { value: "" },
processOutputFormat: { value: "process" },
dbaseOutputFormat: { value: "influxdb" },
// Control strategy
mode: { value: "optimalControl" }, // optimalControl | priorityControl | prioritypercentagecontrol | maintenance
scaling: { value: "normalized" }, // normalized (0100 %) | absolute (m³/h)
//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"],
icon: "font-awesome/fa-cogs",
label: function () {
return (this.positionIcon || "") + " machineGroup";
},
oneditprepare: function() {
// Initialize the menu data for the node
const waitForMenuData = () => {
if (window.EVOLV?.nodes?.machineGroupControl?.initEditor) {
window.EVOLV.nodes.machineGroupControl.initEditor(this);
} else {
setTimeout(waitForMenuData, 50);
}
};
// Wait for the menu data to be ready before initializing the editor
waitForMenuData();
},
oneditsave: function(){
const node = this;
// Validate logger properties using the logger menu
if (window.EVOLV?.nodes?.machineGroupControl?.loggerMenu?.saveEditor) {
success = window.EVOLV.nodes.machineGroupControl.loggerMenu.saveEditor(node);
}
// save position field
if (window.EVOLV?.nodes?.machineGroupControl?.positionMenu?.saveEditor) {
window.EVOLV.nodes.machineGroupControl.positionMenu.saveEditor(this);
}
}
});
</script>
<script type="text/html" data-template-name="machineGroupControl">
<h3>Control strategy</h3>
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-cogs"></i> Mode</label>
<select id="node-input-mode" style="width:60%;">
<option value="optimalControl">optimalControl &mdash; pick the best valid pump combination by BEP-gravitation / NCog</option>
<option value="priorityControl">priorityControl &mdash; sequential equal-flow control by priority list</option>
<option value="prioritypercentagecontrol">prioritypercentagecontrol &mdash; sequential percentage control (requires normalized scaling)</option>
<option value="maintenance">maintenance &mdash; monitoring only, no dispatch</option>
</select>
</div>
<div class="form-row">
<label for="node-input-scaling"><i class="fa fa-arrows-h"></i> Scaling</label>
<select id="node-input-scaling" style="width:60%;">
<option value="normalized">normalized &mdash; demand interpreted as 0&ndash;100 % of group capacity</option>
<option value="absolute">absolute &mdash; demand interpreted as /h, capped by group min/max</option>
</select>
</div>
<h3>Output Formats</h3>
<div class="form-row">
<label for="node-input-processOutputFormat"><i class="fa fa-random"></i> Process Output</label>
<select id="node-input-processOutputFormat" style="width:60%;">
<option value="process">process</option>
<option value="json">json</option>
<option value="csv">csv</option>
</select>
</div>
<div class="form-row">
<label for="node-input-dbaseOutputFormat"><i class="fa fa-database"></i> Database Output</label>
<select id="node-input-dbaseOutputFormat" style="width:60%;">
<option value="influxdb">influxdb</option>
<option value="json">json</option>
<option value="csv">csv</option>
</select>
</div>
<!-- Logger fields injected here -->
<div id="logger-fields-placeholder"></div>
<!-- Position fields injected here -->
<div id="position-fields-placeholder"></div>
</script>
<script type="text/html" data-help-name="machineGroupControl">
<p>A machineGroupControl node</p>
</script>