2025-10-14 13:52:39 +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-06-25 17:26:13 +02:00
<!-- Load the dynamic menu & config endpoints -->
< script src = "/rotatingMachine/menu.js" > < / script >
< script src = "/rotatingMachine/configData.js" > < / script >
< script >
RED.nodes.registerType("rotatingMachine", {
category: "EVOLV",
2025-10-14 13:52:39 +02:00
color: "#86bbdd",
2025-06-25 17:26:13 +02:00
defaults: {
2026-04-22 17:50:50 +02:00
name: { value: "" },
2025-06-25 17:26:13 +02:00
// Define specific properties
speed: { value: 1, required: true },
startup: { value: 0 },
warmup: { value: 0 },
shutdown: { value: 0 },
2025-07-02 10:53:03 +02:00
cooldown: { value: 0 },
2025-11-20 11:09:44 +01:00
movementMode : { value: "staticspeed" }, // static or dynamic
2025-06-25 17:26:13 +02:00
machineCurve : { value: {}},
2026-03-12 16:39:25 +01:00
processOutputFormat: { value: "process" },
dbaseOutputFormat: { value: "influxdb" },
2025-06-25 17:26:13 +02:00
//define asset properties
uuid: { value: "" },
2026-03-11 11:13:26 +01:00
assetTagNumber: { value: "" },
2025-06-25 17:26:13 +02:00
supplier: { value: "" },
category: { value: "" },
assetType: { value: "" },
model: { value: "" },
unit: { value: "" },
2026-03-11 11:13:26 +01:00
curvePressureUnit: { value: "mbar" },
curveFlowUnit: { value: "" },
curvePowerUnit: { value: "kW" },
curveControlUnit: { value: "%" },
2025-06-25 17:26:13 +02:00
//logger properties
enableLog: { value: false },
logLevel: { value: "error" },
//physicalAspect
positionVsParent: { value: "" },
2025-07-01 15:25:07 +02:00
positionIcon: { value: "" },
2025-09-05 16:20:27 +02:00
hasDistance: { value: false },
distance: { value: 0 },
distanceUnit: { value: "m" },
distanceDescription: { value: "" }
2025-06-02 16:56:36 +02:00
2025-05-14 10:07:27 +02:00
},
2025-06-25 17:26:13 +02:00
inputs: 1,
outputs: 3,
inputLabels: ["Input"],
outputLabels: ["process", "dbase", "parent"],
2025-10-14 13:52:39 +02:00
icon: "font-awesome/fa-cog",
2025-06-25 17:26:13 +02:00
2025-07-01 15:25:07 +02:00
label: function () {
2026-03-11 11:13:26 +01:00
return (this.positionIcon || "") + " " + (this.category || "Machine");
2025-06-25 17:26:13 +02:00
},
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
oneditprepare: function() {
// wait for the menu scripts to load
fix: production hardening — safety fixes, prediction accuracy, test coverage
Safety:
- Async input handler: await all handleInput() calls, prevents unhandled rejections
- Fix emergencyStop case mismatch: "emergencyStop" → "emergencystop" matching config
- Implement showCoG() method (was routing to undefined)
- Null guards on 6 methods for missing curve data
- Editor menu polling timeout (5s max)
- Listener cleanup on node close (child measurements + state emitter)
- Tick loop race condition: track startup timeout, clear on close
Prediction accuracy:
- Remove efficiency rounding that destroyed signal in canonical units
- Fix calcEfficiency variant: hydraulic power reads from correct variant
- Guard efficiency calculations against negative/zero values
- Division-by-zero protection in calcRelativeDistanceFromPeak
- Curve data anomaly detection (cross-pressure median-y ratio check)
- calcEfficiencyCurve O(n²) → O(n) with running min
- updateCurve bootstraps predictors when they were null
Tests: 43 new tests (76 total) covering emergency stop, shutdown/maintenance
sequences, efficiency/CoG, movement lifecycle, output format, null guards,
and listener cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:41:00 +02:00
let menuRetries = 0;
const maxMenuRetries = 100; // 5 seconds at 50ms intervals
2025-06-25 17:26:13 +02:00
const waitForMenuData = () => {
if (window.EVOLV?.nodes?.rotatingMachine?.initEditor) {
window.EVOLV.nodes.rotatingMachine.initEditor(this);
fix: production hardening — safety fixes, prediction accuracy, test coverage
Safety:
- Async input handler: await all handleInput() calls, prevents unhandled rejections
- Fix emergencyStop case mismatch: "emergencyStop" → "emergencystop" matching config
- Implement showCoG() method (was routing to undefined)
- Null guards on 6 methods for missing curve data
- Editor menu polling timeout (5s max)
- Listener cleanup on node close (child measurements + state emitter)
- Tick loop race condition: track startup timeout, clear on close
Prediction accuracy:
- Remove efficiency rounding that destroyed signal in canonical units
- Fix calcEfficiency variant: hydraulic power reads from correct variant
- Guard efficiency calculations against negative/zero values
- Division-by-zero protection in calcRelativeDistanceFromPeak
- Curve data anomaly detection (cross-pressure median-y ratio check)
- calcEfficiencyCurve O(n²) → O(n) with running min
- updateCurve bootstraps predictors when they were null
Tests: 43 new tests (76 total) covering emergency stop, shutdown/maintenance
sequences, efficiency/CoG, movement lifecycle, output format, null guards,
and listener cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:41:00 +02:00
} else if (++menuRetries < maxMenuRetries ) {
2025-06-25 17:26:13 +02:00
setTimeout(waitForMenuData, 50);
fix: production hardening — safety fixes, prediction accuracy, test coverage
Safety:
- Async input handler: await all handleInput() calls, prevents unhandled rejections
- Fix emergencyStop case mismatch: "emergencyStop" → "emergencystop" matching config
- Implement showCoG() method (was routing to undefined)
- Null guards on 6 methods for missing curve data
- Editor menu polling timeout (5s max)
- Listener cleanup on node close (child measurements + state emitter)
- Tick loop race condition: track startup timeout, clear on close
Prediction accuracy:
- Remove efficiency rounding that destroyed signal in canonical units
- Fix calcEfficiency variant: hydraulic power reads from correct variant
- Guard efficiency calculations against negative/zero values
- Division-by-zero protection in calcRelativeDistanceFromPeak
- Curve data anomaly detection (cross-pressure median-y ratio check)
- calcEfficiencyCurve O(n²) → O(n) with running min
- updateCurve bootstraps predictors when they were null
Tests: 43 new tests (76 total) covering emergency stop, shutdown/maintenance
sequences, efficiency/CoG, movement lifecycle, output format, null guards,
and listener cleanup.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 13:41:00 +02:00
} else {
console.warn("rotatingMachine: menu scripts failed to load within 5 seconds");
2025-05-14 10:07:27 +02:00
}
2025-06-25 17:26:13 +02:00
};
waitForMenuData();
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
// your existing project‐ settings & asset dropdown logic can remain here
2025-07-24 13:15:33 +02:00
document.getElementById("node-input-speed");
document.getElementById("node-input-startup");
document.getElementById("node-input-warmup");
document.getElementById("node-input-shutdown");
document.getElementById("node-input-cooldown");
2025-11-20 11:09:44 +01:00
const movementMode = document.getElementById("node-input-movementMode");
if (movementMode) {
movementMode.value = this.movementMode || "staticspeed";
}
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
},
oneditsave: function() {
const node = this;
2025-10-02 17:09:24 +02:00
2025-06-25 17:26:13 +02:00
// save asset fields
if (window.EVOLV?.nodes?.rotatingMachine?.assetMenu?.saveEditor) {
window.EVOLV.nodes.rotatingMachine.assetMenu.saveEditor(this);
2025-05-14 10:07:27 +02:00
}
2025-06-25 17:26:13 +02:00
// save logger fields
if (window.EVOLV?.nodes?.rotatingMachine?.loggerMenu?.saveEditor) {
window.EVOLV.nodes.rotatingMachine.loggerMenu.saveEditor(this);
2025-05-14 10:07:27 +02:00
}
2025-06-25 17:26:13 +02:00
// save position field
if (window.EVOLV?.nodes?.rotatingMachine?.positionMenu?.saveEditor) {
window.EVOLV.nodes.rotatingMachine.positionMenu.saveEditor(this);
2025-05-14 10:07:27 +02:00
}
2025-07-02 10:53:03 +02:00
["speed", "startup", "warmup", "shutdown", "cooldown"].forEach((field) => {
const element = document.getElementById(`node-input-${field}`);
const value = parseFloat(element?.value) || 0;
console.log(`----------------> Saving ${field}: ${value}`);
node[field] = value;
});
2025-05-14 10:07:27 +02:00
2025-11-20 11:09:44 +01:00
node.movementMode = document.getElementById("node-input-movementMode").value;
console.log(`----------------> Saving movementMode: ${node.movementMode}`);
2025-06-25 17:26:13 +02:00
}
2025-05-14 10:07:27 +02:00
});
2025-06-25 17:26:13 +02:00
< / script >
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
<!-- Main UI Template -->
< script type = "text/html" data-template-name = "rotatingMachine" >
<!-- Machine - specific controls -->
< div class = "form-row" >
< label for = "node-input-speed" > < i class = "fa fa-clock-o" > < / i > Reaction Speed< / label >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< input type = "number" id = "node-input-speed" style = "width:60%;" placeholder = "position units / second" / >
< div style = "font-size:11px;color:#666;margin-left:160px;" > Ramp rate of the controller position in units per second (0– 100% controller range; e.g. 1 = 1%/s).< / div >
2025-06-25 17:26:13 +02:00
< / div >
< div class = "form-row" >
< label for = "node-input-startup" > < i class = "fa fa-clock-o" > < / i > Startup Time< / label >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< input type = "number" id = "node-input-startup" style = "width:60%;" placeholder = "seconds" / >
< div style = "font-size:11px;color:#666;margin-left:160px;" > Seconds spent in the < code > starting< / code > state before moving to < code > warmingup< / code > .< / div >
2025-06-25 17:26:13 +02:00
< / div >
< div class = "form-row" >
< label for = "node-input-warmup" > < i class = "fa fa-clock-o" > < / i > Warmup Time< / label >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< input type = "number" id = "node-input-warmup" style = "width:60%;" placeholder = "seconds" / >
< div style = "font-size:11px;color:#666;margin-left:160px;" > Seconds spent in the protected < code > warmingup< / code > state before reaching < code > operational< / code > .< / div >
2025-06-25 17:26:13 +02:00
< / div >
< div class = "form-row" >
< label for = "node-input-shutdown" > < i class = "fa fa-clock-o" > < / i > Shutdown Time< / label >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< input type = "number" id = "node-input-shutdown" style = "width:60%;" placeholder = "seconds" / >
< div style = "font-size:11px;color:#666;margin-left:160px;" > Seconds spent in the < code > stopping< / code > state before moving to < code > coolingdown< / code > .< / div >
2025-06-25 17:26:13 +02:00
< / div >
< div class = "form-row" >
< label for = "node-input-cooldown" > < i class = "fa fa-clock-o" > < / i > Cooldown Time< / label >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< input type = "number" id = "node-input-cooldown" style = "width:60%;" placeholder = "seconds" / >
< div style = "font-size:11px;color:#666;margin-left:160px;" > Seconds spent in the protected < code > coolingdown< / code > state before returning to < code > idle< / code > .< / div >
2025-06-25 17:26:13 +02:00
< / div >
2025-11-20 11:09:44 +01:00
< div class = "form-row" >
< label for = "node-input-movementMode" > < i class = "fa fa-exchange" > < / i > Movement Mode< / label >
< select id = "node-input-movementMode" style = "width:60%;" >
< option value = "staticspeed" > Static< / option >
< option value = "dynspeed" > Dynamic< / option >
< / select >
< / div >
2025-05-14 10:07:27 +02:00
2026-03-12 16:39:25 +01:00
< 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 >
2025-06-25 17:26:13 +02:00
<!-- Asset fields injected here -->
< div id = "asset-fields-placeholder" > < / div >
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
<!-- Logger fields injected here -->
< div id = "logger-fields-placeholder" > < / div >
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
<!-- Position fields injected here -->
< div id = "position-fields-placeholder" > < / div >
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
< / script >
2025-05-14 10:07:27 +02:00
2025-06-25 17:26:13 +02:00
< script type = "text/html" data-help-name = "rotatingMachine" >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< p > < b > Rotating Machine< / b > : individual pump / compressor / blower control module. Runs a 10-state S88 sequence, predicts flow and power from a supplier curve, and publishes process + telemetry outputs each second.< / p >
< h3 > Configuration< / h3 >
< ul >
< li > < b > Reaction Speed< / b > : controller ramp rate (position units / second). E.g. < code > 1< / code > = 1%/s, so Set 60% from idle reaches 60% in ~60 s.< / li >
< li > < b > Startup / Warmup / Shutdown / Cooldown< / b > : seconds per FSM phase. Warmup and Cooldown are < i > protected< / i > — they cannot be aborted by a new command.< / li >
< li > < b > Movement Mode< / b > : < code > staticspeed< / code > = linear ramp; < code > dynspeed< / code > = ease-in/out.< / li >
< li > < b > Asset< / b > (menu): supplier, category, model (must match a curve in < code > generalFunctions< / code > ), flow unit (e.g. m³/h), curve units.< / li >
< li > < b > Output Formats< / b > : < code > process< / code > /< code > json< / code > /< code > csv< / code > on port 0; < code > influxdb< / code > /< code > json< / code > /< code > csv< / code > on port 1.< / li >
< li > < b > Position< / b > (menu): < code > upstream< / code > / < code > atEquipment< / code > / < code > downstream< / code > relative to a parent group/station.< / li >
< / ul >
< h3 > Input topics (< code > msg.topic< / code > )< / h3 >
2025-06-25 17:26:13 +02:00
< ul >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< li > < code > setMode< / code > — < code > payload< / code > = < code > auto< / code > | < code > virtualControl< / code > | < code > fysicalControl< / code > < / li >
< li > < code > execSequence< / code > — < code > payload< / code > = < code > {source, action:"execSequence", parameter: "startup"|"shutdown"|"entermaintenance"|"exitmaintenance"}< / code > < / li >
< li > < code > execMovement< / code > — < code > payload< / code > = < code > {source, action:"execMovement", setpoint: 0..100}< / code > (controller %)< / li >
< li > < code > flowMovement< / code > — < code > payload< / code > = < code > {source, action:"flowMovement", setpoint: < flow in configured unit> }< / code > < / li >
< li > < code > emergencystop< / code > — < code > payload< / code > = < code > {source, action:"emergencystop"}< / code > . Aborts any active movement.< / li >
< li > < code > simulateMeasurement< / code > — < code > payload< / code > = < code > {type:"pressure"|"flow"|"temperature"|"power", position, value, unit}< / code > . Injects dashboard-side measurement.< / li >
< li > < code > showWorkingCurves< / code > , < code > CoG< / code > — diagnostics, reply arrives on port 0.< / li >
2025-06-25 17:26:13 +02:00
< / ul >
fix: interruptible shutdown/emergencystop + dual-curve test coverage
Runtime:
- executeSequence now normalizes sequenceName to lowercase so parent
orchestrators that use 'emergencyStop' (capital S) route correctly to
the 'emergencystop' sequence key. Closes the "Sequence 'emergencyStop'
not defined" warn seen when commands reach the node during accelerating.
- When a shutdown or emergencystop sequence is requested while the FSM is
in accelerating/decelerating, the active movement is aborted via
state.abortCurrentMovement() and the sequence waits (up to 2s) for the
FSM to return to 'operational' before proceeding. New helper
_waitForOperational listens on the state emitter for the transition.
- Single-side pressure warning: fix "acurate" typo and make the message
actionable.
Tests (+15, now 91/91 passing):
- test/integration/interruptible-movement.integration.test.js (+3):
shutdown during accelerating -> idle; emergencystop during accelerating
-> off; mixed-case sequence-name normalization.
- test/integration/curve-prediction.integration.test.js (+12):
parametrized across both shipped pump curves (hidrostal-H05K-S03R and
hidrostal-C5-D03R-SHN1). Verifies loader integrity, mid-range prediction
sanity, flow monotonicity in ctrl, inverse-pressure monotonicity, CoG
finiteness, and reverse-predictor round-trip.
E2E:
- test/e2e/curve-prediction-benchmark.py: live Dockerized Node-RED
benchmark that deploys one rotatingMachine per curve and runs a per-pump
(pressure x ctrl) sweep inside each curve's envelope. Reports envelope
compliance and monotonicity.
- test/e2e/README.md documents the benchmark and a known limitation:
pressure below the curve's minimum slice extrapolates wildly
(defended by upstream measurement-node clamping in production).
UX:
- rotatingMachine.html: added placeholders and descriptions for Reaction
Speed / Startup / Warmup / Shutdown / Cooldown. Expanded the Node-RED
help panel with a topic reference, port documentation, state diagram,
and prediction rules.
Docs:
- README.md rewritten (was a single line) with install, quick start,
topic/port reference, state machine, predictions, testing, production
status.
Depends on generalFunctions commit 75d16c6 (state.js abort recovery and
rotatingMachine schema additions).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 13:21:48 +02:00
< h3 > Output ports< / h3 >
< ol >
< li > < b > process< / b > — delta-compressed process payload. Consumers must cache and merge each tick. Keys use 4-segment format < code > type.variant.position.childId< / code > (e.g. < code > flow.predicted.downstream.default< / code > ).< / li >
< li > < b > dbase< / b > — InfluxDB telemetry.< / li >
< li > < b > parent< / b > — < code > registerChild< / code > handshake for a parent < code > machineGroupControl< / code > / < code > pumpingStation< / code > .< / li >
< / ol >
< h3 > State machine< / h3 >
< p > States: < code > idle → starting → warmingup → operational → (accelerating ⇄ decelerating) → operational → stopping → coolingdown → idle< / code > . < code > emergencystop → off< / code > is reachable from every active state.< / p >
< p > If a < code > shutdown< / code > or < code > emergencystop< / code > sequence is requested while a setpoint move is in flight (< code > accelerating< / code > / < code > decelerating< / code > ), the move is aborted automatically and the sequence proceeds once the FSM returns to < code > operational< / code > .< / p >
< h3 > Predictions< / h3 >
< p > Flow and power predictions only produce meaningful values once at least one pressure child is reporting (or a < code > simulateMeasurement< / code > pressure is injected). Inject BOTH upstream and downstream for best accuracy.< / p >
2026-03-11 11:13:26 +01:00
< / script >