Display-Seite der kalten Extraktion: Schalter unter "Modi" auf der Temperatur-Seite mit Erklärzeile, eigener Slot in der Statuszeile direkt hinter der Sicherheitsmeldung, "Cold Extraction - Heizen aus" in der Wasser-Kachel statt eines unerreichbaren Sollwerts, unterdrückter Aufheiz-Countdown, "Vorbenetzung" als erste Phase des kalten Bezugs, Parameter-Anzeige auf der Brew-Seite und "(kalt)"-Markierung in der Statistik (kalte Bezüge zählen nicht in die mittlere Dauer). Bug-Fix P4: PROTO_RX_LINE_MAX lag bei 2048 Bytes, während die State-Zeile der S3 bereits rund 2,1 KB erreicht. Mit langem Status-, Profil- oder SSID-Text lag sie darüber — dann wurde die ganze Zeile verworfen und das Display fror auf dem letzten Stand ein, ohne dass die Verbindung als tot erkannt wurde. Limit jetzt 4096 Bytes; der Puffer bleibt bei 2 KB reserviert, weil der interne RAM knapp ist und eine Arduino-String nicht ins PSRAM alloziert werden kann. S3 5.3.2: Sperrgrund und transiente Meldung gehen als Codes (cxBlock/cxNotice) statt als Klartext ans Display, dazu cxPreInf für die Phasenleiste. Der bis zu 110 Byte lange Freitext hätte die State-Zeile über das Zeilenlimit gedrückt; die Texte rendert jetzt das Display, analog zur Trennung statusKey/statusText. Auf dem OLED und in den ack-Antworten bleibt der Klartext unverändert. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
132 lines
6.9 KiB
C
132 lines
6.9 KiB
C
// =====================================================================================
|
|
// machine_state.h - Spiegelbild des 'state'-Objekts der Hauptplatine
|
|
// =====================================================================================
|
|
// Enthaelt genau die Felder, die die S3 im 'state'-Push sendet
|
|
// (siehe buildTouchUartStateJson() bzw. Doku/JC-Display_UART-Protokoll.md, Abschnitt 5).
|
|
// Das Display haelt KEINEN abweichenden Zustand - es spiegelt nur.
|
|
// =====================================================================================
|
|
|
|
#pragma once
|
|
|
|
#include <Arduino.h>
|
|
|
|
struct MachineState {
|
|
// --- Meta ---
|
|
uint16_t protocolVersion = 0;
|
|
String firmwareVersion;
|
|
|
|
// --- Temperaturen ---
|
|
float tempW = 0, setW = 0; // Wasser ist/soll
|
|
float tempD = 0, setD = 0; // Dampf ist/soll
|
|
|
|
// --- Status ---
|
|
String statusText; // Klartext (DE)
|
|
String statusKey; // sprachneutral: ready/error/standby/maintenance/...
|
|
bool wasserSensorError = false; // Wassersensor liefert ungueltigen Wert
|
|
bool wasserSafetyShutdown = false; // Wassertemperatur ueber Sicherheitslimit -> Heizung aus
|
|
bool dampfSensorError = false; // Dampfsensor liefert ungueltigen Wert
|
|
bool dampfSafetyShutdown = false; // Dampftemperatur ueber Sicherheitslimit -> Heizung aus
|
|
bool shotActive = false;
|
|
uint32_t shotElapsedMs = 0;
|
|
bool scaleTaring = false; // Tarier-Phase vor einem Brew-by-Weight-Bezug laeuft
|
|
bool steamCircuitActive = false;
|
|
uint32_t steamElapsedMs = 0; // verstrichene Dampfbezugszeit (fuer rueckwirkende Timer-Kopplung)
|
|
bool steamFlushActive = false;
|
|
uint32_t steamFlushElapsedMs = 0; // verstrichene Dampf-Flush-Zeit (aus steamFlushEndTime, race-frei)
|
|
bool flushActive = false;
|
|
uint32_t flushElapsedMs = 0; // verstrichene Wasser-Flush-Zeit (fuer rueckwirkende Timer-Kopplung)
|
|
bool ecoActive = false;
|
|
long ecoCountdownSec = -1; // Sekunden bis automatische Eco-Aktivierung (-1 = kein Timer scharf)
|
|
bool ecoShowInfo = false; // S3-Einstellung "Eco-Info auf dem Display anzeigen"
|
|
bool standbyActive = false;
|
|
bool standbyShowClock = false; // S3-Einstellung "Uhrzeit im Standby anzeigen"
|
|
uint8_t backlightActive = 100; // Helligkeit % wenn Display aktiv (von S3 konfiguriert)
|
|
uint8_t backlightStandbyClock = 30;// Helligkeit % fuer Standby-Uhr (von S3 konfiguriert)
|
|
bool maintenanceActive = false;
|
|
bool steamHeatDisabled = false;
|
|
bool steamDelayActive = false; // Dampf-Startverzoegerung laeuft
|
|
long steamDelayRemainSec = 0; // verbleibende Sekunden der Startverzoegerung
|
|
int heatUpMinutes = 0; // konfigurierte Aufheizzeit (Minuten); 0 = aus
|
|
long heatUpRemainSec = -1; // verbleibende Sekunden bis "durchgewaermt" (-1 = aus)
|
|
bool lightOn = false;
|
|
bool piezoEnabled = false;
|
|
String activeProfile; // zuletzt geladenes/gespeichertes Profil (leer = keines; seit S3 5.1.1)
|
|
bool profileDirty = false; // Einstellungen weichen seit dem Laden vom Profil ab
|
|
|
|
// --- Waage ---
|
|
float weight = 0, targetWeight = 0;
|
|
float lastShotWeight = 0; // Endgewicht des letzten Bezugs inkl. Offset (fuer Shot-Zusammenfassung)
|
|
bool lastShotByWeight = false;// war der letzte Bezug gewichtsbasiert? (dann lastShotWeight statt weight anzeigen)
|
|
float flowRate = 0; // aktuelle Flussrate in g/s (waehrend Bezug)
|
|
bool scaleEnabled = false;
|
|
uint8_t scaleType = 0;
|
|
bool scaleConnected = false;
|
|
|
|
// --- Brew-Control ---
|
|
bool piEnabled = false, bbtEnabled = false, bbwEnabled = false, sbtEnabled = false;
|
|
float bbtSecs = 0, sbtSecs = 0, piDurSecs = 0, piPauseSecs = 0;
|
|
float bbwTarget = 0, bbwOffset = 0;
|
|
uint8_t piState = 0; // Pre-Infusion-Phase (0=inaktiv,1=Pre-Infusion,2=Pause,3=Hauptbezug; seit S3 5.0.12)
|
|
|
|
// --- Cold Extraction (kalte Extraktion; seit S3 5.3.0) ---
|
|
bool cxEnabled = false; // Funktion auf der S3 freigeschaltet (sonst Bedienelement ausblenden)
|
|
bool cxActive = false; // Modus scharf: Wasserkreis heizt nicht (persistent, seit S3 5.3.1)
|
|
bool cxShot = false; // der laufende Bezug ist eine kalte Extraktion
|
|
bool cxAllowed = false; // Freigabe jetzt (Wasserkessel kalt genug, kein Standby/Wartung/Tuning)
|
|
bool cxResting = false; // Zwangspause des Pumpenschutzes laeuft (Bezug laeuft weiter)
|
|
float cxMaxTemp = 0; // Freigabeschwelle in C
|
|
float cxTarget = 0; // Zielgewicht in g
|
|
float cxPreInfSec = 0; // Vorbenetzung in s (fuer die Phasenleiste des kalten Bezugs)
|
|
float cxMaxSecs = 0; // Sicherheits-Timeout des Bezugs in s
|
|
// Sperrgrund: 0=frei, 1=nicht freigeschaltet, 2=Standby, 3=Wartung, 4=Reinigungsassistent,
|
|
// 5=PID-Tuning, 6=Sensorfehler, 7=Wasserkessel zu warm
|
|
uint8_t cxBlock = 0;
|
|
// Transiente Meldung: 0=keine, 1=Start abgewiesen, 2=Bezug ohne Zulauf beendet,
|
|
// 3=Umschalten waehrend eines Bezugs abgelehnt
|
|
uint8_t cxNotice = 0;
|
|
|
|
// --- Gehaeusesensor ---
|
|
bool caseSensorEnabled = false;
|
|
bool caseTempDashboard = false;
|
|
uint8_t caseSensorType = 0; // 0 = Gehaeuse, 1 = Tassenablage
|
|
bool hasCaseTemp = false; // false => caseTemp war null
|
|
float caseTemp = 0;
|
|
|
|
// --- Service ---
|
|
int maintenanceInterval = 0;
|
|
uint32_t maintenanceIntervalCounter = 0;
|
|
uint8_t flushDurationSeconds = 0;
|
|
uint8_t steamFlushDurationSeconds = 0;
|
|
|
|
// --- Reinigungsassistent (Live-Status + Parameter) ---
|
|
bool cleaningActive = false;
|
|
bool cleaningWaiting = false; // heizt noch auf 93 C vor
|
|
bool cleaningBrewPhase = false; // true = Bezug, false = Pause
|
|
uint8_t cleaningCycle = 0; // aktueller Zyklus
|
|
uint8_t cleaningCycles = 0; // Gesamtzahl Zyklen
|
|
uint8_t cleaningBrewSeconds = 0; // Bezugsdauer je Zyklus
|
|
uint8_t cleaningPauseSeconds = 0; // Pausendauer je Zyklus
|
|
long cleaningPhaseRemainSec = 0; // verbleibende Sekunden der aktuellen Phase
|
|
|
|
// --- v2: Heizleistung / PID / AutoTune ---
|
|
float dutyW = 0, dutyD = 0;
|
|
float kpW = 0, kiW = 0, kdW = 0;
|
|
float kpD = 0, kiD = 0, kdD = 0;
|
|
bool autoTuneW = false, autoTuneD = false;
|
|
// Ergebnis/Grund des letzten Tuning-Laufs (0=Idle,1=laeuft,2=Erfolg,3=Failsafe,
|
|
// 4=degeneriert,5=Sensorfehler,6=Sicherheitsabsch.,7=manuell)
|
|
uint8_t autoTuneWStatus = 0, autoTuneDStatus = 0;
|
|
|
|
// --- v2: Netzwerk ---
|
|
bool wifiConnected = false;
|
|
bool apMode = false;
|
|
String ip;
|
|
String ssid;
|
|
int rssi = 0;
|
|
String timeStr; // "HH:MM" wenn NTP synchronisiert, sonst leer
|
|
|
|
// --- Verbindungsstatus (lokal, nicht von der S3) ---
|
|
bool linkUp = false; // UART-Verbindung steht (hello bestaetigt)
|
|
unsigned long lastRxMs = 0; // letzte empfangene Nachricht
|
|
};
|