Files
Dual-PID/JC_Display_Firmware/machine_state.h
T
raw-designsandClaude Opus 5 7c1e485722 feat: Espresso/Cold-Auswahl bei jedem Aufwecken, auch per Schalter (S3 5.6.0 / P4 1.4.0)
Die Abfrage war eine reine Vorab-Abfrage des Displays und erschien nur beim
Antippen des Standby-Bildschirms. Beim Aufwecken über den Schalter ist der Standby
aber schon beendet, bevor das Display überhaupt fragen könnte — dieser Weg war nie
abgedeckt.

Die Steuerung hält jetzt nach dem Aufwecken ein Auswahlfenster offen (20 s): Der
Wasserkreis heizt in dieser Zeit nicht, das Display blendet die Auswahl von sich aus
ein und zeigt einen Countdown. Ohne Entscheidung wird danach normal geheizt, es geht
also nichts verloren, wenn niemand hinsieht.

Das Fenster öffnet nur mit angeschlossenem Display (sonst könnte niemand wählen),
bei freigeschalteter Funktion und aktiver Einstellung "Abfrage beim Aufwecken", und
nur wenn der Modus nicht ohnehin schon läuft. Es schließt bei Entscheidung,
Bezug/Spülen oder erneutem Standby.

Neue Aktion wakeEspresso (beendet Standby falls aktiv und schließt das Fenster) —
das Display sendet sie statt deactivateStandby, sobald die Auswahl relevant ist,
sonst würde direkt nach dem Aufwecken nochmal gefragt. Neue State-Felder
cxWakeChoice und cxWakeChoiceSec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 01:46:47 +02:00

142 lines
7.7 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)
bool cxWakeChoice = false; // Auswahlfenster nach dem Aufwecken offen (seit S3 5.6.0)
long cxWakeChoiceSec = 0; // Restsekunden der Bedenkzeit
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
};