Der Aufweck-Dialog am Touch-Display wird zur Auswahl: "Womit aufwecken?" mit
"Espresso" (heizt normal auf) und "Cold Extraction (Wasser bleibt kalt)". Damit
lässt sich bei jedem Aufwecken neu entscheiden, ohne vorher die Web-UI zu bedienen.
Bei der kalten Variante wird der Modus scharf geschaltet, bevor der Standby endet —
der Wasserkreis heizt also gar nicht erst an.
Abschaltbar über die neue Einstellung "Abfrage beim Aufwecken" (EEPROM 982), zu
finden auf /Cold-Extraction und auf der Cold-Extraction-Seite des Displays. Ist sie
aus, erscheint wieder der bisherige Dialog. Ohne angeschlossenes Display oder bei
nicht freigeschalteter Funktion hat sie keine Wirkung. Neues Feld cxAskOnWake im
State und in saveBrew.
Dazu: Die Meldungstexte der kalten Extraktion sind jetzt mit echten Umlauten
geschrieben ("nicht möglich" statt "nicht moeglich"). Für das OLED übersetzt die
neue Hilfsfunktion oledUmlauts() sie beim Rendern nach CP437 — dort hätte UTF-8
sonst zwei Fehlzeichen je Umlaut ergeben, weshalb die Texte ursprünglich
transliteriert waren. Web-UI und Touch-Display stellen UTF-8 direkt dar.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
140 lines
7.6 KiB
C
140 lines
7.6 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; // Bezug jetzt moeglich (Wasserkessel kalt genug, kein Standby/Wartung/Tuning)
|
|
bool cxArmable = false; // Modus umschaltbar - auch im Standby und bei warmem Kessel (seit S3 5.3.5)
|
|
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)
|
|
// Restliche Parameter fuer die Einstellseite am Display (seit S3 5.4.0)
|
|
float cxPreInfDuty = 0; // Pumpenleistung Vorbenetzung in %
|
|
float cxDuty = 0; // Pumpenleistung Hauptbezug in %
|
|
uint16_t cxPulseMs = 0; // Pulsperiode in ms
|
|
float cxPumpMaxRun = 0; // Pumpenschutz: max. kumulierte Laufzeit in s
|
|
float cxPumpRest = 0; // Pumpenschutz: Zwangspause in s
|
|
bool cxAskOnWake = false; // Beim Aufwecken aus dem Standby fragen (seit S3 5.5.0)
|
|
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
|
|
};
|