fix: Auswahl beim Aufwecken über Touch entfiel manchmal (S3 5.6.3 / P4 1.4.2)

Über den Schalter kam die Abfrage "Espresso oder Cold Extraction" zuverlässig,
über Antippen am Display nur manchmal. Ursache waren zwei unterschiedliche
Bedingungen für dieselbe Sache:

- askMode (zeigt die Auswahl im Dialog) verlangte zusätzlich cxArmable
- choiceRelevant (sendet "wakeEspresso" und schließt damit das Auswahlfenster
  der S3) verlangte es nicht

In der Lücke dazwischen zeigte der Dialog nur "Aufwecken", unterdrückte aber
trotzdem die Rückfrage der S3 - die Frage war auf beiden Seiten weg. Der
Schalterweg hatte diese Lücke nie, weil er allein an der S3 hängt.

P4: beide Stellen benutzen jetzt wake_choice_offered(). Bot der Dialog die
Auswahl nicht an, sendet er "deactivateStandby"; dann öffnet die S3 ihr
eigenes Auswahlfenster und die Frage kommt trotzdem.

S3: Die Fensterentscheidung ist als Bedingungskette geschrieben und hält
Quelle und Ergebnis des letzten Aufweckens fest. /Cold-Extraction zeigt das
an - die bisherige Live-Liste zeigt nur den jetzigen Stand, der beim
Nachsehen längst wieder ein anderer sein kann.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
raw-designs
2026-08-19 01:02:30 +02:00
co-authored by Claude Opus 5
parent 535f640bbd
commit 743c38e994
5 changed files with 141 additions and 12 deletions
+96 -5
View File
@@ -369,7 +369,7 @@ Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire);
* Firmware-Informationen
************************************************************************************/
String version = "5.6.2";
String version = "5.6.3";
String versionHersteller = "Thomas M&uuml;ller";
String versionHerstellerMail =
"<a href='mailto:thomas@mueller.black' class='info-link'>thomas@mueller.black</a>";
@@ -804,6 +804,28 @@ unsigned long coldExtractionWakeDecisionMs = 0; // Zeitpunkt der letzten ex
const unsigned long COLDEX_WAKE_CHOICE_MS = 20000UL; // Bedenkzeit
const unsigned long COLDEX_WAKE_DECISION_GRACE_MS = 5000UL; // frisch entschieden -> kein Fenster
// Diagnose des letzten Aufweckens: Bleibt die Abfrage aus, ist von aussen nicht erkennbar,
// welche der Voraussetzungen gefehlt hat - die Live-Anzeige auf /Cold-Extraction zeigt nur
// den JETZIGEN Stand, und der kann sich bis zum Nachsehen laengst wieder geaendert haben.
// Deshalb wird das Ergebnis beim Aufwecken festgehalten. Reine Anzeige, keine Logik.
#define COLDEX_WAKE_SRC_UNKNOWN 0 // Schalter, Timer, Web - alles ohne Display-Beteiligung
#define COLDEX_WAKE_SRC_TOUCH 1 // Display: "Aufwecken" (ohne Auswahl im Dialog)
#define COLDEX_WAKE_SRC_ESPRESSO 2 // Display: "Espresso" gewaehlt
#define COLDEX_WAKE_SRC_COLD 3 // Display: "Cold Extraction" gewaehlt
#define COLDEX_WAKE_RES_NONE 0 // seit dem Start noch nicht aufgeweckt
#define COLDEX_WAKE_RES_OPENED 1 // Auswahlfenster geoeffnet
#define COLDEX_WAKE_RES_DECIDED 2 // am Display bereits entschieden -> keine zweite Frage
#define COLDEX_WAKE_RES_ASK_OFF 3 // Abfrage in den Einstellungen ausgeschaltet
#define COLDEX_WAKE_RES_NO_DISP 4 // kein Touch-Display verbunden
#define COLDEX_WAKE_RES_NOT_ARM 5 // Wartung / Reinigung / PID-Tuning aktiv
#define COLDEX_WAKE_RES_DISABLED 6 // Funktion nicht freigeschaltet
uint8_t coldExtractionWakeSource = COLDEX_WAKE_SRC_UNKNOWN; // Quelle des laufenden Aufweckens
unsigned long coldExtractionWakeSourceMs = 0; // ... wann gemeldet (verfaellt)
const unsigned long COLDEX_WAKE_SRC_VALID_MS = 3000UL; // danach gilt sie als veraltet
uint8_t coldExtractionLastWakeSource = COLDEX_WAKE_SRC_UNKNOWN; // ... des letzten, fuer die Anzeige
uint8_t coldExtractionLastWakeResult = COLDEX_WAKE_RES_NONE;
unsigned long coldExtractionLastWakeMs = 0;
const bool defaultColdExtractionEnabled = false;
const float defaultColdExtractionMaxTempC = 30.0f;
const float defaultColdExtractionPreInfusionSeconds = 10.0f;
@@ -5452,12 +5474,34 @@ void loop() {
// die Abfrage muss in BEIDE Richtungen gehen - auch von "kalt" zurueck auf Espresso.
// Sonst bliebe man nach dem ersten kalten Bezug dauerhaft im kalten Modus haengen,
// ohne beim Aufwecken je wieder gefragt zu werden.
if (coldExtractionEnabled && coldExtractionAskOnWake && touchUartClientActive &&
coldExtractionArmable() &&
(coldExtractionWakeDecisionMs == 0 ||
(currentMillis - coldExtractionWakeDecisionMs) > COLDEX_WAKE_DECISION_GRACE_MS)) {
// Als Kette geschrieben, damit jeder Zweig seinen Grund hinterlaesst (Anzeige auf
// /Cold-Extraction). Ohne das bleibt ein ausgebliebenes Fenster nicht nachvollziehbar.
// Eine gemeldete Quelle gilt nur kurz: Wird der Modus im Standby ueber die
// Einstellseite scharfgestellt, ohne dass ein Aufwecken folgt, darf sie nicht
// spaeter am naechsten Aufwecken kleben.
coldExtractionLastWakeSource =
(coldExtractionWakeSourceMs != 0 &&
(currentMillis - coldExtractionWakeSourceMs) <= COLDEX_WAKE_SRC_VALID_MS)
? coldExtractionWakeSource : COLDEX_WAKE_SRC_UNKNOWN;
coldExtractionWakeSource = COLDEX_WAKE_SRC_UNKNOWN;
coldExtractionWakeSourceMs = 0;
coldExtractionLastWakeMs = currentMillis;
if (!coldExtractionEnabled) {
coldExtractionLastWakeResult = COLDEX_WAKE_RES_DISABLED;
} else if (!coldExtractionAskOnWake) {
coldExtractionLastWakeResult = COLDEX_WAKE_RES_ASK_OFF;
} else if (!touchUartClientActive) {
coldExtractionLastWakeResult = COLDEX_WAKE_RES_NO_DISP;
} else if (!coldExtractionArmable()) {
coldExtractionLastWakeResult = COLDEX_WAKE_RES_NOT_ARM;
} else if (coldExtractionWakeDecisionMs != 0 &&
(currentMillis - coldExtractionWakeDecisionMs) <= COLDEX_WAKE_DECISION_GRACE_MS) {
// Am Display wurde gerade gewaehlt - eine zweite Frage waere nur laestig.
coldExtractionLastWakeResult = COLDEX_WAKE_RES_DECIDED;
} else {
coldExtractionWakeChoicePending = true;
coldExtractionWakeChoiceUntilMs = currentMillis + COLDEX_WAKE_CHOICE_MS;
coldExtractionLastWakeResult = COLDEX_WAKE_RES_OPENED;
}
}
// Gleiche Auswahl nach einem Kaltstart: Wer die Maschine am Netzschalter einschaltet,
@@ -5469,6 +5513,9 @@ void loop() {
coldExtractionBootChoiceDone = true;
coldExtractionWakeChoicePending = true;
coldExtractionWakeChoiceUntilMs = currentMillis + COLDEX_WAKE_CHOICE_MS;
coldExtractionLastWakeSource = COLDEX_WAKE_SRC_UNKNOWN;
coldExtractionLastWakeResult = COLDEX_WAKE_RES_OPENED;
coldExtractionLastWakeMs = currentMillis;
} else if (!coldExtractionBootChoiceDone && touchUartClientActive && standbyModeActive) {
// Start in den Standby hinein: Der Standby-Uebergang uebernimmt die Abfrage.
coldExtractionBootChoiceDone = true;
@@ -7868,6 +7915,33 @@ void handleColdExtraction(AsyncWebServerRequest *request) {
long remainSec = (remainMs > 0) ? ((remainMs + 999) / 1000) : 0;
diag += "<b style='color:#66CC66;'>Auswahlfenster ist gerade offen (noch " + String(remainSec) + " s).</b><br>";
}
// Letztes Aufwecken: Die Liste darueber zeigt nur den jetzigen Stand. Blieb die Frage
// aus, ist der Grund von damals hier festgehalten - sonst muesste man ihn raten.
if (coldExtractionLastWakeResult != COLDEX_WAKE_RES_NONE) {
String src;
switch (coldExtractionLastWakeSource) {
case COLDEX_WAKE_SRC_TOUCH: src = "Display (Aufwecken)"; break;
case COLDEX_WAKE_SRC_ESPRESSO: src = "Display (Espresso gew&auml;hlt)"; break;
case COLDEX_WAKE_SRC_COLD: src = "Display (Cold Extraction gew&auml;hlt)"; break;
default: src = "Schalter / Timer / Web"; break;
}
String res;
bool resOk = false;
switch (coldExtractionLastWakeResult) {
case COLDEX_WAKE_RES_OPENED: res = "Auswahlfenster ge&ouml;ffnet"; resOk = true; break;
case COLDEX_WAKE_RES_DECIDED: res = "am Display bereits entschieden"; resOk = true; break;
case COLDEX_WAKE_RES_ASK_OFF: res = "Abfrage ist ausgeschaltet"; break;
case COLDEX_WAKE_RES_NO_DISP: res = "kein Touch-Display verbunden"; break;
case COLDEX_WAKE_RES_NOT_ARM: res = "Wartung / Reinigung / PID-Tuning aktiv"; break;
case COLDEX_WAKE_RES_DISABLED: res = "Funktion nicht freigeschaltet"; break;
default: res = "unbekannt"; break;
}
unsigned long agoSec = (millis() - coldExtractionLastWakeMs) / 1000UL;
diag += "<span style='color:#b0b0b0;'>Letztes Aufwecken vor " + String(agoSec) + " s &uuml;ber " + src +
": <span style='color:";
diag += resOk ? "#66CC66" : "#FFCC00";
diag += ";'>" + res + "</span>.</span><br>";
}
diag += "</small>";
cxFieldsHtml.replace("{CX_ASK_DIAG}", diag);
}
@@ -17442,6 +17516,23 @@ static bool touchUartHandleCommandLine(const String& line) {
String message = "";
bool settingsChanged = false;
bool pidNeedsUpdate = false;
// Herkunft des Aufweckens fuer die Diagnose festhalten - nur hier ist bekannt, dass
// die Aktion vom Touch-Display kommt und nicht aus der Web-UI. "Cold Extraction"
// schickt erst den Modus und dann das Aufwecken, deshalb darf das nachfolgende
// deactivateStandby die schon gesetzte Quelle nicht ueberschreiben.
if (standbyModeActive) {
if (action == "wakeEspresso") {
coldExtractionWakeSource = COLDEX_WAKE_SRC_ESPRESSO;
coldExtractionWakeSourceMs = millis();
} else if (action == "startColdExtraction") {
coldExtractionWakeSource = COLDEX_WAKE_SRC_COLD;
coldExtractionWakeSourceMs = millis();
} else if (action == "deactivateStandby" &&
coldExtractionWakeSource == COLDEX_WAKE_SRC_UNKNOWN) {
coldExtractionWakeSource = COLDEX_WAKE_SRC_TOUCH;
coldExtractionWakeSourceMs = millis();
}
}
executeDashboardAction(action, value, success, message, settingsChanged, pidNeedsUpdate);
touchUartSendAck(id, success, message);
touchUartSendState();