From e8dd657b4fbff703c0649f10fa985e8f7a739a40 Mon Sep 17 00:00:00 2001 From: znetsixe Date: Tue, 14 Apr 2026 13:42:43 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20continuous=20proportional=20control=20?= =?UTF-8?q?=E2=80=94=20eliminate=20dead=20zone=20between=20start/stop=20le?= =?UTF-8?q?vels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously PS only sent demand to MGC when level > startLevel AND direction === 'filling'. Between startLevel and stopLevel (the 'dead zone'), pumps kept running at their last commanded setpoint with no updates. Basin drained uncontrolled until hitting stopLevel. Fix: send percControl on every tick when level > stopLevel. The _scaleLevelToFlowPercent math naturally gives: - Positive % above startLevel (pumps ramp up) - 0% at exactly startLevel (pumps at minimum) - Negative % below startLevel → clamped to 0 → MGC scales to 0 → pumps ramp down gracefully This creates smooth visible ramp-up and ramp-down as the basin fills and drains, instead of a sudden jump at startLevel and stuck ctrl in the dead zone. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/specificClass.js | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/src/specificClass.js b/src/specificClass.js index ef00497..bacb65c 100644 --- a/src/specificClass.js +++ b/src/specificClass.js @@ -264,15 +264,26 @@ class PumpingStation { return; } - if (level > startLevel && direction === 'filling') { - const percControl = this._scaleLevelToFlowPercent(level); - this.logger.debug(`Controllevel based => Level ${level} control applying to pump : ${percControl}`); - await this._applyMachineLevelControl(percControl); - // Also forward to machine groups (e.g. MGC) — the level-based - // control originally only addressed direct-child machines, but in - // a hierarchical topology (PS → MGC → pumps) the machines sit - // under MGC and PS.machines is empty. - await this._applyMachineGroupLevelControl(percControl); + // Continuous proportional control: command pumps whenever level is + // above stopLevel. The percControl ramp gives: + // - 0% at minFlowLevel (= startLevel) → pumps barely running + // - linearly up to 100% at maxFlowLevel → all pumps full + // - Below startLevel but above stopLevel: percControl < 0 → clamp + // to 0 → MGC turns off pumps (graceful ramp-down instead of a + // dead zone where pumps keep running at their last setpoint). + if (level > stopLevel) { + const rawPercControl = this._scaleLevelToFlowPercent(level); + const percControl = Math.max(0, rawPercControl); + this.logger.debug(`Controllevel based => Level ${level} percControl ${percControl}`); + if (percControl > 0) { + await this._applyMachineLevelControl(percControl); + await this._applyMachineGroupLevelControl(percControl); + } else { + // Between stopLevel and startLevel with percControl ≤ 0: + // tell MGC to scale back to 0 rather than leaving pumps + // running at the last commanded setpoint. + await this._applyMachineGroupLevelControl(0); + } } if (level < stopLevel && direction === 'draining') {