From c697e65a019673118861888704027f9dbcde9f3d Mon Sep 17 00:00:00 2001 From: raw-designs Date: Mon, 10 Aug 2026 21:31:59 +0200 Subject: [PATCH] =?UTF-8?q?feat(S3):=20Cold=20Extraction=20=C3=BCberlebt?= =?UTF-8?q?=20Standby=20und=20Neustart=20(5.3.1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Der Modus wird im EEPROM (Adresse 977) gespeichert und beim Start wieder übernommen, sofern die Funktion auf /Brew-Control freigeschaltet ist. Standby beendet ihn nicht mehr, sondern verwirft nur die Laufzeitdaten. Grund: Wer nur kalte Bezüge machen will, musste den Modus nach jedem Standby neu einschalten. Bis dahin heizte die Maschine bereits auf und war für die nächste kalte Extraktion zu warm — man musste auf das Abkühlen warten, also genau die Situation, die der Modus vermeiden soll. Der Modus endet nur noch durch explizites Ausschalten, durch Entzug der Freischaltung oder durch einen Werksreset. Co-Authored-By: Claude Opus 5 --- Changelog.txt | 10 ++++++++ Doku/JC-Display_UART-Protokoll.md | 9 ++++--- Dual-PID.ino | 39 +++++++++++++++++++++---------- 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 55c6c99..fc4f78a 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,13 @@ +Version 5.3.1: +- Cold Extraction ist jetzt persistent: Der Modus wird im EEPROM gespeichert und überlebt sowohl den + Standby als auch einen Neustart. Zuvor wurde er beim Standby beendet und war nach dem Aufwachen aus - + die Maschine heizte dann erst auf, obwohl der nächste kalte Bezug einen kalten Kessel braucht, und man + musste auf das Abkühlen warten. Wer nur kalte Bezüge machen will, schaltet den Modus damit einmal ein + und wieder aus, wenn er fertig ist. +- Der Modus fällt nur weg, wenn auf /Brew-Control die Freischaltung entzogen wird oder ein Werksreset + läuft. Solange er aktiv ist, heizt der Wasserkreis nicht - Dashboard, OLED („(COLD)" in der Wasserzeile) + und Touch-Display zeigen das durchgehend an. + Version 5.3.0: - Neu: Cold Extraction (kalte Extraktion). Die Maschine hat keinen Bypass um den Wasserkessel, kaltes Wasser kommt also nur bei kaltem Kessel am Puck an. Die Funktion wird deshalb über eine Temperaturschwelle diff --git a/Doku/JC-Display_UART-Protokoll.md b/Doku/JC-Display_UART-Protokoll.md index 235cc2b..2fad6fa 100644 --- a/Doku/JC-Display_UART-Protokoll.md +++ b/Doku/JC-Display_UART-Protokoll.md @@ -324,9 +324,12 @@ Alle gültigen `action`-Strings aus `executeDashboardAction()` (Stand v4.8.1, Ze | `toggleColdExtraction` | — | Modus umschalten | Alle drei Aktionen werden abgewiesen (`ok:false` + `message`), solange die Bedingungen nicht -erfüllt sind — Hauptfall ist ein zu warmer Wasserkessel (`cxAllowed:false`). Der Modus wird -**nicht** persistiert und ist nach jedem Neustart aus; Standby beendet ihn. Ein laufender -Bezug wird nie abgebrochen, `stopColdExtraction` schlägt dann fehl. +erfüllt sind — Hauptfall ist ein zu warmer Wasserkessel (`cxAllowed:false`). Der Modus ist +**persistent** (EEPROM) und überlebt Standby und Neustart; er endet nur durch explizites +Ausschalten, durch Entzug der Freischaltung auf `/Brew-Control` oder durch einen Werksreset. +Das P4-UI sollte `cxActive` deshalb dauerhaft sichtbar spiegeln — sonst wundert sich der +Benutzer, warum die Maschine nicht heizt. Ein laufender Bezug wird nie abgebrochen, +`stopColdExtraction` schlägt dann fehl. Die Parameter der kalten Extraktion (Schwelle, Vorbenetzung, Pulsperiode, Pumpenleistung, Zielgewicht, Timeout, Pumpenschutz) sind bewusst **nicht** über `saveBrew` erreichbar, sondern diff --git a/Dual-PID.ino b/Dual-PID.ino index 81e3f32..f1127b9 100644 --- a/Dual-PID.ino +++ b/Dual-PID.ino @@ -369,7 +369,7 @@ Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire); * Firmware-Informationen ************************************************************************************/ -String version = "5.3.0"; +String version = "5.3.1"; String versionHersteller = "Thomas Müller"; String versionHerstellerMail = "thomas@mueller.black"; @@ -1036,7 +1036,8 @@ const int EEPROM_ADDR_COLDEX_TARGET_GRAMS = 961; // 4 Bytes (float) -> Ende const int EEPROM_ADDR_COLDEX_MAX_SECONDS = 965; // 4 Bytes (float) -> Ende 968 const int EEPROM_ADDR_COLDEX_PUMP_MAX_RUN = 969; // 4 Bytes (float) -> Ende 972 const int EEPROM_ADDR_COLDEX_PUMP_REST = 973; // 4 Bytes (float) -> Ende 976 -// Naechste freie Adresse: 977 (Innerhalb EEPROM_SIZE=1024) +const int EEPROM_ADDR_COLDEX_MODE_ACTIVE = 977; // 1 Byte (uint8_t) -> Ende 977 +// Naechste freie Adresse: 978 (Innerhalb EEPROM_SIZE=1024) /************************************************************************************ * Eco-Mode Variablen @@ -3027,6 +3028,7 @@ void resetToDefaults() { EEPROM.put(EEPROM_ADDR_COLDEX_MAX_SECONDS, defaultColdExtractionMaxSeconds); EEPROM.put(EEPROM_ADDR_COLDEX_PUMP_MAX_RUN, defaultColdExtractionPumpMaxRunSec); EEPROM.put(EEPROM_ADDR_COLDEX_PUMP_REST, defaultColdExtractionPumpRestSec); + EEPROM.put(EEPROM_ADDR_COLDEX_MODE_ACTIVE, (uint8_t)0); // Werksreset: Modus immer aus // Piezo auf Default im EEPROM schreiben EEPROM.put(EEPROM_ADDR_PIEZO_ENABLED, defaultPiezoEnabled); @@ -3988,6 +3990,12 @@ void applyFlowGuardPumpControl(unsigned long currentShotTimeMillis, float netWei * Cold Extraction (kalte Extraktion) ************************************************************************************/ +// Modus-Zustand ins EEPROM schreiben (persistent ueber Standby und Neustart hinweg). +void persistColdExtractionMode() { + EEPROM.put(EEPROM_ADDR_COLDEX_MODE_ACTIVE, (uint8_t)(coldExtractionModeActive ? 1 : 0)); + EEPROM.commit(); +} + void resetColdExtractionRuntime() { coldExtractionShotActive = false; coldExtractionPumpResting = false; @@ -4072,7 +4080,8 @@ bool setColdExtractionMode(bool enable, String& message) { } coldExtractionModeActive = true; resetColdExtractionRuntime(); - message = "Cold Extraction aktiviert - Wasserkreis heizt nicht."; + persistColdExtractionMode(); + message = "Cold Extraction aktiviert - Wasserkreis heizt nicht (bleibt auch nach Standby/Neustart aktiv)."; return true; } @@ -4082,6 +4091,7 @@ bool setColdExtractionMode(bool enable, String& message) { } coldExtractionModeActive = false; resetColdExtractionRuntime(); + persistColdExtractionMode(); message = "Cold Extraction beendet - Wasserkreis heizt wieder."; return true; } @@ -4615,9 +4625,13 @@ void setup() { if (!isfinite(coldExtractionPumpRestSec) || coldExtractionPumpRestSec < COLDEX_PUMP_REST_SEC_MIN || coldExtractionPumpRestSec > COLDEX_PUMP_REST_SEC_MAX) { coldExtractionPumpRestSec = defaultColdExtractionPumpRestSec; } - // Der Modus selbst wird bewusst NICHT persistiert: nach einem Neustart startet die - // Maschine immer im normalen Heizbetrieb. - coldExtractionModeActive = false; + // Der Modus ist bewusst persistent: Wer nur kalte Bezuege machen will, soll die + // Maschine nicht nach jedem Standby/Neustart erst aufheizen lassen, um sie danach + // wieder abkuehlen zu muessen. Nur bei entzogener Freischaltung faellt er weg. + uint8_t storedColdExtractionMode = 0; + EEPROM.get(EEPROM_ADDR_COLDEX_MODE_ACTIVE, storedColdExtractionMode); + if (storedColdExtractionMode > 1) { storedColdExtractionMode = 0; } + coldExtractionModeActive = (storedColdExtractionMode == 1) && coldExtractionEnabled; coldExtractionShotActive = false; // Piezo-Status laden @@ -5234,11 +5248,10 @@ void loop() { if (wartungsModusAktiv) { wartungsModusAktiv = false; } - // Cold Extraction beim Wechsel in den Standby beenden (analog Eco/Wartung) - if (coldExtractionModeActive) { - coldExtractionModeActive = false; - resetColdExtractionRuntime(); - } + // Cold Extraction bleibt beim Standby bewusst aktiv (anders als Eco/Wartung): Die + // Maschine soll nach dem Aufwachen nicht erst aufheizen, nur um fuer den naechsten + // kalten Bezug wieder abkuehlen zu muessen. Nur die Laufzeitdaten werden verworfen. + resetColdExtractionRuntime(); coldExtractionBlockMessage = ""; } else if (lastStandbyModeActive) { startupTime = currentMillis; @@ -7109,7 +7122,8 @@ static const char brewControlCX_Fields[] PROGMEM = R"rawliteral( aus dem kalten Zustand heraus. Solange der Modus aktiv ist, heizt der Wasserkreis nicht - der Dampfkreis bleibt unberührt und darf weiter heizen. Die Pumpenlaufzeit wird kumuliert gezählt; nach der eingestellten Laufzeit legt die Steuerung eine Zwangspause ein. Der Modus selbst wird auf dem Dashboard bzw. am Touch-Display - ein- und ausgeschaltet.) + ein- und ausgeschaltet und bleibt über Standby und Neustart hinweg aktiv, bis er dort wieder ausgeschaltet + wird - solange heizt der Wasserkreis nicht.) {CX_STATUS_MSG}
)rawliteral"; @@ -7461,6 +7475,7 @@ bool applyBrewControlUpdate(const BrewControlUpdate& update) { if (!coldExtractionEnabled && coldExtractionModeActive && !shotActive && !shotSoftwareActive) { coldExtractionModeActive = false; // Freischaltung entzogen -> Modus beenden resetColdExtractionRuntime(); + EEPROM.put(EEPROM_ADDR_COLDEX_MODE_ACTIVE, (uint8_t)0); // Commit erfolgt am Ende der Funktion } } if (update.hasCXMaxTemp) { -- 2.54.0