feat(S3): Cold Extraction (kalte Extraktion) mit Temperatur-Freigabe (5.3.0)

Kalte Extraktion ohne Kessel-Bypass: Da kaltes Wasser nur bei kaltem Wasserkessel
am Puck ankommt, wird die Funktion über eine Temperaturschwelle freigegeben
(Standard 30 °C, 10–40 °C einstellbar). Solange der Modus aktiv ist, heizt der
Wasserkreis nicht (SSR gesperrt, Stellgröße und dutyW-Telemetrie auf 0, I-Anteil
eingefroren, Feed-Forward-Boost aus); der Dampfkreis bleibt unberührt.

Die Freigabe wird vor jedem Bezug neu geprüft, weil der weiter heizende
Dampfkessel den Wasserkessel über die Zeit über die Schwelle bringen kann. Ein
abgewiesener Start meldet den Grund auf OLED, Touch-Display und Web-Dashboard;
ein laufender Bezug wird nie abgebrochen. 5 °C Hysterese, Sensorfehler sperrt.

Fluss über Pumpen-Pulsung nach einer Vorbenetzung mit voller Leistung; Ende über
Zielgewicht oder Timeout. Brew-by-Time/Weight und FlowGuard sind während einer
kalten Extraktion außer Kraft, da FlowGuard sonst um denselben Pumpen-Ausgang
konkurrieren würde. Pumpenschutz über kumulierte Einschaltzeit mit Zwangspause
plus Stillstands-Erkennung bei aktiver Waage.

Kalte Bezüge werden im CSV-Log mit einem vierten Feld "C" gekennzeichnet, zählen
in allen Stückzahlen mit, bleiben aber aus der durchschnittlichen Bezugsdauer
heraus. Neue additive State-Felder cx* im UART-JSON (Protokoll bleibt v2) und
neuer statusKey "coldextraction".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
raw-designs
2026-08-10 21:02:11 +02:00
co-authored by Claude Opus 5
parent 5a1e8d4b50
commit db1b080dc4
3 changed files with 931 additions and 49 deletions
+39 -1
View File
@@ -315,6 +315,23 @@ Alle gültigen `action`-Strings aus `executeDashboardAction()` (Stand v4.8.1, Ze
| `disableSteamHeat` | — | Dampf-Heizung abschalten |
| `enableSteamHeat` | — | Dampf-Heizung wieder aktivieren |
**Cold Extraction (kalte Extraktion, ab S3 5.3.0)**
| `action` | `value` | Wirkung |
|---|---|---|
| `startColdExtraction` | — | Modus aktivieren (Wasserkreis heizt nicht, Dampf bleibt möglich) |
| `stopColdExtraction` | — | Modus beenden |
| `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.
Die Parameter der kalten Extraktion (Schwelle, Vorbenetzung, Pulsperiode, Pumpenleistung,
Zielgewicht, Timeout, Pumpenschutz) sind bewusst **nicht** über `saveBrew` erreichbar, sondern
nur über die Web-Seite `/Brew-Control`. Das Display schaltet den Modus, konfiguriert ihn nicht.
**Persistente Toggles**
| `action` | `value` | Wirkung |
@@ -354,7 +371,28 @@ Aus `getTouchUartStatus()`. Für sprach-unabhängige UI-Logik/Icons auf dem P4 v
(statt `statusText` zu parsen):
`ready`, `error`, `standby`, `maintenance`, `tuning`, `brewing`, `eco`, `fastheatup`,
`heating`, `ready_eco_pending`.
`heating`, `ready_eco_pending`, `coldextraction` (ab S3 5.3.0).
### Cold-Extraction-Felder im `state` (ab S3 5.3.0, additiv — Protokoll bleibt v2)
| Feld | Typ | Bedeutung |
|---|---|---|
| `cxEnabled` | bool | Funktion in der Web-UI freigeschaltet (sonst Bedienelement ausblenden) |
| `cxActive` | bool | Modus scharf: Wasserkreis heizt nicht |
| `cxShot` | bool | Der laufende Bezug ist eine kalte Extraktion |
| `cxAllowed` | bool | Freigabe **jetzt** (Wasserkessel kalt genug, kein Standby/Wartung/Tuning) |
| `cxResting` | bool | Zwangspause des Pumpenschutzes läuft (Bezug läuft weiter) |
| `cxMaxTemp` | float | Freigabeschwelle in °C (für eigene Hinweistexte am Display) |
| `cxTarget` | float | Zielgewicht in g |
| `cxMaxSecs` | float | Sicherheits-Timeout des Bezugs in s |
| `cxMessage` | string | Sperr-/Abbruchmeldung, leer = keine (läuft nach ~6 s selbst ab) |
Während `cxShot` folgt die Phase weiterhin `piState`: `1` = Vorbenetzung, `3` = Hauptbezug
(gepulst). Eine Pause-Phase (`2`) gibt es bei der kalten Extraktion nicht.
In der Antwort auf `getUsageStats` trägt jeder Eintrag in `shots[]` zusätzlich `cx` (bool) —
kalte Bezüge zählen in `total`/`today`/`week` mit, sind aber in der durchschnittlichen
Bezugsdauer der S3-Statistik ausgenommen.
---