feat: Cold Extraction im Standby scharf schaltbar (S3 5.3.5 / P4 1.1.3)
"Standby aktiv" und "Kessel zu warm" galten bisher auch fürs Aktivieren. Das war falsch herum gedacht: Der Modus schaltet die Heizung AB, man kam aber erst an den Schalter, nachdem die Maschine aufgeweckt war und schon zu heizen begonnen hatte — genau der Ablauf, den die Funktion vermeiden soll. Scharfschalten und Beziehen sind jetzt getrennt: - Scharfschalten (neues State-Feld cxArmable): blockiert nur durch fehlende Freischaltung, Wartungsmodus, Reinigungsassistent, PID-Tuning oder einen laufenden Bezug/Spülvorgang. - Bezug (unverändert cxAllowed): zusätzlich kein Standby, Kessel unter der Freigabeschwelle, gültiger Sensorwert. Ist der Modus scharf, der Bezug aber gesperrt, sagen Web-UI und Display das jetzt ausdrücklich. Bei Aktivierung mit warmem Kessel geht die Heizung sofort aus, die Rückmeldung nennt die Sperre bis zum Unterschreiten der Schwelle. P4: Der Aufweck-Dialog bekommt "Aufwecken mit Cold Extraction" — sendet startColdExtraction vor deactivateStandby, damit der Wasserkreis gar nicht erst anheizt. Der Schalter hängt jetzt an cxArmable; bei älterer S3-Firmware fällt das Feld auf cxEnabled zurück und bleibt bedienbar. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
6dd3f1eaf2
commit
9b91543435
@@ -1,3 +1,15 @@
|
||||
Version 1.1.3:
|
||||
- Aufweck-Dialog hat einen dritten Knopf: „Aufwecken mit Cold Extraction" (braucht S3 ab 5.3.5).
|
||||
Er stellt den Modus scharf und beendet erst danach den Standby - in dieser Reihenfolge, damit
|
||||
der Wasserkreis gar nicht erst anheizt. Ohne diesen Weg musste man normal aufwecken (Maschine
|
||||
heizt an) und den Modus danach umschalten. Der Knopf erscheint nur, wenn die Funktion
|
||||
freigeschaltet und umschaltbar ist und der Modus nicht ohnehin schon läuft.
|
||||
- Der Schalter „Cold Extraction" auf der Temperatur-Seite hängt jetzt am neuen State-Feld
|
||||
cxArmable statt an cxAllowed: umschaltbar auch im Standby und bei warmem Kessel, gesperrt nur
|
||||
während eines laufenden kalten Bezugs. Bei älterer S3-Firmware fällt das Feld auf cxEnabled
|
||||
zurück, der Schalter bleibt also bedienbar.
|
||||
- Erklärzeile im Standby: „Nach dem Aufwecken bleibt der Wasserkreis aus."
|
||||
|
||||
Version 1.1.2:
|
||||
- Cold Extraction: Fehlt eine nutzbare Waage, weist das Display jetzt dauerhaft darauf hin.
|
||||
Ohne Waage greifen weder Zielgewicht noch Stillstands-Erkennung, der Bezug endet erst nach der
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Firmware
|
||||
// -------------------------------------------------------------------------------------
|
||||
#define DISPLAY_FW_VERSION "1.1.2" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
|
||||
#define DISPLAY_FW_VERSION "1.1.3" // Firmware-Stand der P4-Display-Steuerung (Info-Seite)
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Protokoll
|
||||
|
||||
@@ -72,7 +72,8 @@ struct MachineState {
|
||||
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 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
|
||||
|
||||
@@ -225,6 +225,8 @@ void ProtocolClient::applyState(const String& json) {
|
||||
s.cxActive = doc["cxActive"] | false;
|
||||
s.cxShot = doc["cxShot"] | false;
|
||||
s.cxAllowed = doc["cxAllowed"] | false;
|
||||
// Fehlt bei S3-FW < 5.3.5 -> auf cxEnabled zurueckfallen, sonst waere der Schalter tot
|
||||
s.cxArmable = doc["cxArmable"] | (doc["cxEnabled"] | false);
|
||||
s.cxResting = doc["cxResting"] | false;
|
||||
s.cxMaxTemp = doc["cxMaxTemp"] | s.cxMaxTemp;
|
||||
s.cxTarget = doc["cxTarget"] | s.cxTarget;
|
||||
|
||||
@@ -38,6 +38,7 @@ static lv_timer_t* g_toastTimer = nullptr;
|
||||
static lv_obj_t* g_standbyScreen = nullptr; // Vollbild-Overlay im Standby (Uhr)
|
||||
static lv_obj_t* g_standbyClock = nullptr;
|
||||
static lv_obj_t* g_wakeConfirm = nullptr; // Bestaetigungsdialog "Aus dem Standby aufwecken?"
|
||||
static lv_obj_t* g_wakeColdBtn = nullptr; // "Aufwecken mit Cold Extraction" (nur wenn freigeschaltet)
|
||||
static bool g_wakeDialogOpen = false; // Dialog sichtbar -> Display hell schalten (lesbar)
|
||||
static bool g_standbyShown = false; // Standby-Uhr-Overlay zuletzt als sichtbar geschaltet (fuer Ein-/Ausblend-Uebergang)
|
||||
|
||||
@@ -572,6 +573,17 @@ static void wake_yes_cb(lv_event_t*) { // Aufwecken -> hell lassen, S3 bee
|
||||
// das Display in der Uebergangsphase kurz auf Standby-Helligkeit abdunkeln.
|
||||
if (g_client) { g_client->sendAction("deactivateStandby"); showToast("Maschine wird aufgeweckt...", false); }
|
||||
}
|
||||
// Aufwecken direkt in die kalte Extraktion. Reihenfolge ist wichtig: erst den Modus scharf
|
||||
// stellen, dann den Standby beenden - sonst heizt der Wasserkreis in der Zwischenzeit an,
|
||||
// und genau das soll die Funktion ja verhindern.
|
||||
static void wake_cold_cb(lv_event_t*) {
|
||||
wake_confirm_hide();
|
||||
if (g_client) {
|
||||
g_client->sendAction("startColdExtraction");
|
||||
g_client->sendAction("deactivateStandby");
|
||||
showToast("Aufwecken mit Cold Extraction...", false);
|
||||
}
|
||||
}
|
||||
bool ui_wake_dialog_open() { return g_wakeDialogOpen; } // fuer die Helligkeitssteuerung in onState
|
||||
|
||||
// =====================================================================================
|
||||
@@ -3224,6 +3236,13 @@ void ui_init(ProtocolClient* client) {
|
||||
lv_obj_t* wakeYes = th_accent_button(wakeBtns, "Aufwecken");
|
||||
lv_obj_set_width(wakeYes, 150);
|
||||
lv_obj_add_event_cb(wakeYes, wake_yes_cb, LV_EVENT_CLICKED, nullptr);
|
||||
// Zweite Zeile: direkt in die kalte Extraktion aufwecken. Ohne diesen Weg muesste man
|
||||
// erst normal aufwecken (Maschine heizt an) und den Modus danach umschalten.
|
||||
// Nur sichtbar, wenn die S3 die Funktion freigeschaltet meldet (siehe ui_update).
|
||||
g_wakeColdBtn = th_button(wakeCard, "Aufwecken mit Cold Extraction", COL_CARD2, COL_ACCENT);
|
||||
lv_obj_set_width(g_wakeColdBtn, LV_PCT(100));
|
||||
lv_obj_add_event_cb(g_wakeColdBtn, wake_cold_cb, LV_EVENT_CLICKED, nullptr);
|
||||
lv_obj_add_flag(g_wakeColdBtn, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_add_flag(g_wakeConfirm, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
// OTA-Overlay (Vollbild, waehrend Firmware-Update)
|
||||
@@ -3449,6 +3468,12 @@ void ui_update(const MachineState& st) {
|
||||
// Ohne nutzbare Waage laeuft die kalte Extraktion rein zeitgesteuert (Zielgewicht und
|
||||
// Stillstands-Erkennung greifen nicht) - das wird dauerhaft mit angezeigt.
|
||||
const bool cxScaleOk = st.scaleEnabled && st.scaleConnected;
|
||||
// "Aufwecken mit Cold Extraction" nur anbieten, wenn die Funktion freigeschaltet und
|
||||
// umschaltbar ist und der Modus nicht ohnehin schon laeuft.
|
||||
if (g_wakeColdBtn) {
|
||||
if (st.cxEnabled && st.cxArmable && !st.cxActive) lv_obj_remove_flag(g_wakeColdBtn, LV_OBJ_FLAG_HIDDEN);
|
||||
else lv_obj_add_flag(g_wakeColdBtn, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
if (st.cxNotice == 2) {
|
||||
status_set(ST_COLDEX, true, LV_SYMBOL_WARNING " Cold Extraction beendet: kein Zulauf",
|
||||
COL_WARN, lv_color_hex(0x000000));
|
||||
@@ -3851,8 +3876,9 @@ void ui_update(const MachineState& st) {
|
||||
if (lblColdExHint) lv_obj_add_flag(lblColdExHint, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
sw_set(swColdEx, st.cxActive);
|
||||
// Einschalten nur bei Freigabe; Ausschalten immer - ausser waehrend eines kalten Bezugs
|
||||
bool usable = st.cxEnabled && (st.cxActive ? !st.cxShot : st.cxAllowed);
|
||||
// Umschalten haengt an cxArmable, NICHT an cxAllowed: Der Modus muss auch im Standby
|
||||
// und bei warmem Kessel scharf zu stellen sein. Waehrend eines kalten Bezugs gesperrt.
|
||||
bool usable = st.cxEnabled && st.cxArmable && !(st.cxActive && st.cxShot);
|
||||
if (usable) lv_obj_remove_state(swColdEx, LV_STATE_DISABLED);
|
||||
else lv_obj_add_state(swColdEx, LV_STATE_DISABLED);
|
||||
if (lblColdExHint && st.cxEnabled) {
|
||||
@@ -3860,7 +3886,9 @@ void ui_update(const MachineState& st) {
|
||||
String hint;
|
||||
if (st.cxActive) {
|
||||
hint = "Wasserkreis heizt nicht (bleibt über Standby und Neustart aktiv). ";
|
||||
if (st.cxAllowed) {
|
||||
if (st.standbyActive) {
|
||||
hint += "Nach dem Aufwecken bleibt der Wasserkreis aus.";
|
||||
} else if (st.cxAllowed) {
|
||||
char b[96];
|
||||
if (scaleOk) {
|
||||
snprintf(b, sizeof(b), "Bezug regulär starten - Ziel %.0f g, max %.0f s.",
|
||||
|
||||
Reference in New Issue
Block a user