Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
edfa2d4711 | ||
|
|
fc0a756127 | ||
|
|
cc9ae945b1 | ||
|
|
696707a9a4 | ||
|
|
6bf046801c | ||
|
|
cd1617fdce | ||
|
|
5df6c20171 | ||
|
|
7d7893cf08 | ||
|
|
db707ffd8c | ||
|
|
9eb386095d | ||
|
|
7fec5d9fb5 | ||
|
|
32280a7ea3 | ||
|
|
5988668026 | ||
|
|
4f2700d59a | ||
|
|
0ec3d89973 | ||
|
|
06d9710b16 | ||
|
|
b3b96362c3 | ||
|
|
14f1a4789d | ||
|
|
326af4288a | ||
|
|
2e8651bc00 | ||
|
|
b13e5fdaf1 | ||
|
|
671a6696ce | ||
|
|
288f61447d | ||
|
|
a91c792491 | ||
|
|
e32c654b8d | ||
|
|
484812cb4c | ||
|
|
ff23e0e614 | ||
|
|
09b5231357 |
@@ -1,3 +1,176 @@
|
||||
Version 1.10.1:
|
||||
- Die beiden Verlaufskurven teilen sich jetzt eine gemeinsame Skala. In 1.10.0 zoomte jede
|
||||
Kurve auf ihre eigenen Werte - dadurch saß jede mittig in ihrem eigenen Fenster, und
|
||||
Wasser bei 70 Grad lag genauso hoch wie Dampf bei 0. Die Höhe sagte nichts mehr aus.
|
||||
- Die Skala richtet sich nach den Werten beider Kessel zusammen. Der wärmere Kessel liegt
|
||||
damit sichtbar höher, und die Skala bleibt so eng, wie es die Daten zulassen: Stehen beide
|
||||
dicht beieinander, greift die Mindestspanne von vier Grad und schon Zehntelgrade sind zu
|
||||
erkennen.
|
||||
|
||||
Version 1.10.0:
|
||||
- Die Verlaufskurven im Dashboard zeigen jetzt wirklich einen Verlauf. Ihr Ausschnitt hing
|
||||
bisher am Sollwert - sechs Grad darunter bis drei darüber. Das funktioniert nur, solange
|
||||
der Kessel schon nahe am Ziel ist. Heizte er noch auf oder war er ganz aus, lag jeder
|
||||
Messwert unterhalb des Fensters und wurde auf den unteren Rand geklemmt: Beide Kurven lagen
|
||||
flach auf derselben Höhe und bewegten sich nicht, obwohl der eine Kessel bei 80 Grad stand
|
||||
und der andere bei 0. Der Ausschnitt richtet sich jetzt nach den tatsächlich vorhandenen
|
||||
Werten, mit einer Mindestspanne von vier Grad, damit ein ruhig geregelter Kessel nicht
|
||||
jedes Zehntelgrad zum vollen Ausschlag aufbläht.
|
||||
- Die Kurven nehmen jetzt den Platz unterhalb der Zahlen ein statt als schmaler Streifen in
|
||||
der Mitte zu hängen: Sie beginnen weiter unten auf der Karte und sind deutlich höher.
|
||||
- Der Nachlauf beim Wischen ist zurück. Er war abgeschaltet, weil jedes Einzelbild während
|
||||
des Schwungs den ganzen Bildschirm neu zeichnete; seit die Anzeigewerte feste Maße haben,
|
||||
fällt das weg.
|
||||
- Die Messzeilen der Fehlersuche sind wieder entfernt. Die Messung des Bildaufbaus bleibt
|
||||
erhalten, liegt aber hinter dem Schalter WS7_PERF_MONITOR und ist aus.
|
||||
|
||||
Version 1.9.12:
|
||||
- Die Hintergrundbeleuchtung kommt beim Wechsel in den und aus dem Standby jetzt sofort.
|
||||
Bisher stand das Bild bereits fertig da - im Gegenlicht war es zu sehen -, blieb aber
|
||||
mehrere Sekunden dunkel. Das war die ganze gesuchte Verzögerung.
|
||||
- Ursache: Die Bridge übernimmt eine neue Helligkeit nicht zuverlässig beim ersten Mal. Der
|
||||
Beispielcode von Waveshare setzt sie deshalb zweimal, mit einer Pause dazwischen,
|
||||
ausdrücklich „sicherheitshalber". Genau diese Wiederholung fehlte.
|
||||
- Die Panel-Freigabe wird nur noch beim ersten Mal gesetzt. Sie erneut zu setzen, während die
|
||||
Beleuchtung läuft, stößt die Helligkeitsstufe der Bridge neu an; der Beispielcode setzt sie
|
||||
ebenfalls nur ein einziges Mal.
|
||||
- Jeder Helligkeitswechsel meldet jetzt seine Dauer. Bleibt die Beleuchtung wieder hinterher,
|
||||
lässt sich die Pause zwischen den beiden Übernahmen über WS7_BACKLIGHT_LATCH_MS erhöhen.
|
||||
|
||||
Version 1.9.11:
|
||||
- Endlose Startschleife behoben: Beleuchtung an, nie ein Bild. Der P4 startet sich nach dem
|
||||
Einschalten absichtlich einmal neu, weil das Panel sonst schwarz bleibt. Die Absicherung
|
||||
dagegen verließ sich darauf, dass der zweite Start kein Kaltstart mehr ist - der Chip
|
||||
meldet aber auch nach dem selbst ausgelösten Neustart wieder einen Kaltstart. Damit griff
|
||||
die Bedingung erneut, endlos.
|
||||
- Der Neustart wird jetzt vermerkt und beim zweiten Durchlauf erkannt, unabhängig davon, was
|
||||
der Chip als Startgrund meldet. Beim nächsten echten Einschalten erfolgt wieder genau ein
|
||||
Neustart.
|
||||
- Die Meldung über diesen Neustart lief bisher über die USB-Verbindung und war im seriellen
|
||||
Monitor nicht zu sehen - deshalb war von der Schleife nichts zu erkennen. Sie läuft jetzt
|
||||
denselben Weg wie die übrigen Panel-Meldungen.
|
||||
|
||||
Version 1.9.10:
|
||||
- Alle Messzeilen laufen jetzt auf derselben Uhr. Die des Zeichenablaufs startete später als
|
||||
die des Hauptablaufs; die Zeiten ließen sich nur mit Umrechnung vergleichen.
|
||||
- Der Touch meldet jetzt, wenn er Rohwerte verwirft, weil sie außerhalb des gültigen
|
||||
Bereichs liegen, und nennt bei jeder erkannten Berührung, wie viele vorher verworfen
|
||||
wurden. Eine Berührung, deren Rohwerte lange verworfen werden, sieht von außen genauso aus
|
||||
wie ein Display, das nicht reagiert - das war bisher nicht zu unterscheiden.
|
||||
|
||||
Version 1.9.9:
|
||||
- Die kleinen Kacheln unten im Dashboard behalten beim Bezug ihre Höhe. Bisher bekam die
|
||||
untere Zeile während des Bezugs deutlich mehr Platz - die Kacheln wurden enorm hoch und
|
||||
das Dashboard sprang bei jedem Bezugsbeginn sichtbar um.
|
||||
- Die Messzeilen gingen bisher teils über die USB-Verbindung hinaus und waren im seriellen
|
||||
Monitor gar nicht zu sehen - die Messung der Helligkeit lief damit ins Leere. Alle
|
||||
Messzeilen laufen jetzt über denselben Weg wie die Panel-Meldungen.
|
||||
- Jede Messzeile trägt jetzt eine Zeitmarke. Nur so sind die Lücken zu sehen, in denen die
|
||||
fünf Sekunden vergehen.
|
||||
- Der Wechsel in den und aus dem Standby wird an jeder Station vermessen: Ankunft der
|
||||
Meldung, Warten auf die Anzeigesperre, Dauer der Aktualisierung. Ebenso der Weg vom Tippen
|
||||
auf die Standby-Uhr bis zur fertig aufgebauten Rückfrage.
|
||||
|
||||
Version 1.9.8:
|
||||
- Der Stillstand beim Wechsel in den Standby ist gefunden und behoben. LVGL legt für JEDE
|
||||
Textglyphe einen eigenen Zwischenpuffer an - bei der großen Uhr rund 48 KB pro Ziffer, mit
|
||||
zwei parallel arbeitenden Zeicheneinheiten fast 100 KB gleichzeitig. Der interne
|
||||
LVGL-Speicher hatte nur rund 98 KB am Stück frei; es reichte knapp nicht. Schlägt die
|
||||
Anforderung fehl, hält LVGL per Zusicherung in einer Endlosschleife an - kein Absturz,
|
||||
keine Meldung, das Display steht einfach. Deshalb brach der Mitschnitt ohne Fehler ab.
|
||||
- Große Glyphenpuffer liegen jetzt im externen Speicher (PSRAM, 32 MB frei). Kleine bleiben
|
||||
im internen, der ist schneller - sonst würde jeder Text langsamer.
|
||||
- Hält LVGL künftig wegen einer verletzten Zusicherung an, sagt es das jetzt, statt stumm
|
||||
stehen zu bleiben.
|
||||
|
||||
Version 1.9.7:
|
||||
- Messpunkte für den Stillstand beim Wechsel in den Standby: Beide Abläufe - der Haupt- und
|
||||
der Zeichenablauf - melden jetzt alle zwei Sekunden einen Herzschlag mit Speicherstand.
|
||||
Bleibt nur einer von beiden aus, ist klar, welcher stehen bleibt.
|
||||
- Das Einblenden der Standby-Uhr meldet Anfang und Ende mit Dauer. Bleibt die zweite Meldung
|
||||
aus, hängt es genau dort.
|
||||
- Jeder Helligkeitswechsel, der länger als 50 ms braucht, wird mit seiner Dauer gemeldet. Der
|
||||
Schreibzugriff geht über denselben Bus wie der Touch - ein Verdacht für die bekannte
|
||||
Verzögerung von ein bis zwei Sekunden.
|
||||
- Die Rückmeldung aus 1.9.5, die einen komplett ungültigen Inhaltsbereich melden sollte, ist
|
||||
wieder entfernt. Sie konnte nie auslösen: LVGL schickt diese Meldung an das Display, nicht
|
||||
an einzelne Elemente. Ihr Ausbleiben war also kein Beweis.
|
||||
|
||||
Version 1.9.6:
|
||||
- Die Darstellungseinstellungen haben einen eigenen Menüpunkt „Darstellung" bekommen. Sie
|
||||
standen bisher oben auf der Info-Seite, zwischen Sachen, mit denen sie nichts zu tun
|
||||
haben. Die Info-Seite zeigt jetzt nur noch Firmware-Stände und Verbindungsdaten.
|
||||
- Die Uhr im Standby ist auf dem 7-Zoll-Panel deutlich größer geworden: Die drei Stufen
|
||||
liegen jetzt bei 180, 270 und 360 Pixeln statt bei 120, 180 und 240. Auf dem 4,3-Zoll-
|
||||
Panel bleiben die bisherigen Stufen, dort passen größere schlicht nicht auf den Schirm.
|
||||
|
||||
Version 1.9.5:
|
||||
- Die festen Breiten aus 1.9.4 haben nicht gereicht: Auch die HÖHE muss festliegen. LVGL
|
||||
prüft beim Setzen eines Textes, ob sich die Eigengröße der Beschriftung geändert haben
|
||||
könnte - ist eines der beiden Maße frei, gilt das Layout des Elternteils als neu zu
|
||||
berechnen, und das macht die ganze Seite ungültig. Temperaturwerte, Sollwerte, die Werte
|
||||
der unteren Zeile und die Uhrzeit in der Kopfleiste haben jetzt feste Maße in beide
|
||||
Richtungen.
|
||||
- Die Uhrzeit hatte denselben Effekt in der Kopfleiste: Beim Wechsel der Minute wurde die
|
||||
Leiste samt Menü-Knopf neu berechnet. Das erklärt den Bereich „x 6..57, y 2..41", der in
|
||||
fast jedem Durchgang auftauchte.
|
||||
- Zusätzlich meldet die Firmware jetzt, wenn der Inhaltsbereich oder die Dashboard-Seite als
|
||||
Ganzes ungültig gemacht wird. Damit ist zu unterscheiden, ob eine einzelne Beschriftung
|
||||
den Bildaufbau auslöst oder gleich der komplette Bereich - zwei verschiedene Ursachen mit
|
||||
verschiedenen Gegenmitteln.
|
||||
|
||||
Version 1.9.4:
|
||||
- Die Messung mit Koordinaten hat den Verursacher benannt: Der ungültige Bereich war
|
||||
„x 0..1279, y 44..719" - also der gesamte Inhalt unterhalb der Kopfleiste, bei jeder
|
||||
Zustandsmeldung.
|
||||
- Grund: Die Anzeigewerte hatten keine feste Breite. Wächst oder schrumpft eine Beschriftung
|
||||
mit ihrem Inhalt - etwa von „92,4 °C" auf „100,1 °C" -, rechnet LVGL das Layout der
|
||||
gesamten Seite neu und macht sie dabei komplett ungültig. Es genügt also nicht, den Text
|
||||
nur bei echter Änderung zu setzen; er darf beim Ändern auch die Breite nicht verändern.
|
||||
- Temperaturwerte, Sollwerte und die Werte der unteren Zeile haben jetzt eine feste Breite
|
||||
mit zentriertem Text. Sichtbar ändert sich dadurch nichts - die Werte standen ohnehin
|
||||
mittig.
|
||||
|
||||
Version 1.9.3:
|
||||
- Fehlerbehebung: Bei geöffnetem Menü war der Seiteninhalt dahinter verschwunden. Der
|
||||
Vorhang des Menüs war in 1.8.7 deckend gemacht worden, um Zeichenlast zu sparen - dabei
|
||||
verdeckt er aber genau das, was sichtbar bleiben soll. Er ist wieder durchscheinend.
|
||||
- Weitere Stellen umgestellt, die bei jeder Zustandsmeldung neu zeichnen ließen, obwohl sich
|
||||
nichts geändert hatte: das Zustandsband der Darstellung „Band" (es spannt sich über die
|
||||
volle Breite und machte damit allein schon einen Streifen über den ganzen Bildschirm
|
||||
ungültig), die Heizleistungsbalken und das WLAN-Symbol.
|
||||
- Die Messung nennt jetzt zusätzlich die Lage der neu gezeichneten Bereiche. Die Größe
|
||||
allein sagt nicht, welcher Teil der Oberfläche das Neuzeichnen auslöst - die Koordinaten
|
||||
schon.
|
||||
|
||||
Version 1.9.2:
|
||||
- Ursache der Trägheit endlich gefunden. Die erweiterte Messung zeigte: „1 Bereich, 100 %
|
||||
der Fläche" - LVGL zeichnete bei jeder Zustandsmeldung den kompletten Bildschirm neu, also
|
||||
einmal pro Sekunde 240 bis 300 Millisekunden lang. Es war also kein Tempoproblem beim
|
||||
Zeichnen, sondern es wurde viel zu viel als „muss neu gezeichnet werden" gemeldet.
|
||||
- Grund: LVGL macht den Bereich einer Beschriftung ungültig, sobald ihr Text gesetzt wird -
|
||||
auch dann, wenn er sich gar nicht geändert hat. Dasselbe gilt für Farbwechsel. Auf dem
|
||||
Dashboard wurden im Sekundentakt Werte quer über den ganzen Bildschirm gesetzt: Uhrzeit
|
||||
oben, Temperaturen in der Mitte, Bezugswerte unten. LVGL fasst benachbarte ungültige
|
||||
Bereiche zu einem zusammen - und der umfasste dann die gesamte Fläche.
|
||||
- Alle regelmäßig gesetzten Werte werden jetzt vorher verglichen und nur bei echter Änderung
|
||||
neu geschrieben; für Farben gilt dasselbe. Da sich Temperaturen selten um ein Zehntelgrad
|
||||
ändern und der Sollwert praktisch nie, entfallen die meisten dieser Neuzeichnungen.
|
||||
- Das betrifft alle Bildschirmgrößen; auf den JC-Panels war es nur nie störend, weil dort ein
|
||||
Bildaufbau ein Bruchteil davon kostet.
|
||||
|
||||
Version 1.9.1:
|
||||
- Das direkte Zeichnen in den Bildspeicher aus 1.9.0 ist zurückgenommen: Es hat die
|
||||
Bildaufbauzeit nicht verkürzt (weiterhin 240 bis 300 ms) und stattdessen Bildfehler
|
||||
erzeugt, weil in denselben Speicher gezeichnet wird, aus dem gerade angezeigt wird.
|
||||
Damit ist auch klar, dass der Flaschenhals nicht im Kopieren liegt, sondern im Zeichnen
|
||||
selbst. Der Schalter WS7_DIRECT_FB bleibt samt Begründung erhalten.
|
||||
- Die Messung sagt jetzt zusätzlich, WIE VIEL neu gezeichnet wurde: Anzahl der Bereiche und
|
||||
ihr Anteil an der Gesamtfläche. Erst damit lässt sich unterscheiden, ob LVGL nur kleine
|
||||
Bereiche anfasst - dann ist das Zeichnen an sich zu langsam - oder ob jedes Mal der ganze
|
||||
Bildschirm neu entsteht, weil ihn etwas unnötig ungültig macht. Das sind zwei völlig
|
||||
verschiedene Ursachen mit verschiedenen Gegenmitteln.
|
||||
|
||||
Version 1.9.0:
|
||||
- Die Messung aus 1.8.8 hat die Ursache der Trägheit gefunden: Jeder Bildaufbau kostete
|
||||
240 bis 300 Millisekunden - dauerhaft, auch im Leerlauf. Fünf Sekunden für den
|
||||
|
||||
@@ -67,7 +67,7 @@ static void onState(const MachineState& st) {
|
||||
}
|
||||
if (bl < 0) bl = 0; if (bl > 100) bl = 100;
|
||||
if (bl != s_lastBacklight) {
|
||||
hal_backlight(bl);
|
||||
hal_backlight(bl); // meldet seine Dauer selbst, siehe jc_backlight_set()
|
||||
s_lastBacklight = bl;
|
||||
}
|
||||
}
|
||||
@@ -307,20 +307,37 @@ void setup() {
|
||||
// nicht (siehe WS7_DSI_RESTART).
|
||||
//
|
||||
// Deshalb startet der P4 sich nach einem Kaltstart genau einmal selbst neu, nachdem
|
||||
// der erste Hochlauf durch ist. Beim zweiten Durchlauf ist der Startgrund kein
|
||||
// Kaltstart mehr, die Bedingung greift also nicht erneut - eine Schleife ist
|
||||
// ausgeschlossen. Kostet rund drei Sekunden, aber nur beim Einschalten.
|
||||
// der erste Hochlauf durch ist. Kostet rund drei Sekunden, aber nur beim Einschalten.
|
||||
//
|
||||
// Frueher stuetzte sich die Absicherung dagegen allein auf den Startgrund: Beim zweiten
|
||||
// Durchlauf sei es kein Kaltstart mehr, eine Schleife also ausgeschlossen. Das stimmt
|
||||
// nicht - der Chip meldet auch nach dem selbst ausgeloesten Neustart wieder einen
|
||||
// Kaltstart, und dann startet er endlos neu. Genau das ist aufgetreten: Beleuchtung an,
|
||||
// nie ein Bild. Deshalb wird jetzt zusaetzlich vermerkt, dass der Neustart schon
|
||||
// stattgefunden hat; darauf ist Verlass, unabhaengig vom gemeldeten Startgrund.
|
||||
#if (JC_PANEL_TYPE == WS_PANEL_7H) && WS7_COLD_BOOT_RESTART
|
||||
if (esp_reset_reason() == ESP_RST_POWERON) {
|
||||
Preferences p;
|
||||
p.begin("bootguard", false);
|
||||
bool schonNeugestartet = p.getUChar("kaltneu", 0) != 0;
|
||||
if (schonNeugestartet) {
|
||||
// Zweiter Durchlauf: Vermerk loeschen, damit beim naechsten echten Einschalten
|
||||
// wieder genau ein Neustart erfolgt.
|
||||
p.putUChar("kaltneu", 0);
|
||||
p.end();
|
||||
esp_rom_printf("[Panel] Neustart bereits erfolgt - Hochlauf wird fortgesetzt\n");
|
||||
} else {
|
||||
p.putUChar("kaltneu", 1);
|
||||
// Der Fruehstart-Zaehler wurde oben bereits erhoeht. Diesen gewollten Neustart
|
||||
// darf er nicht mitzaehlen, sonst laeuft die Absturzsicherung nach ein paar
|
||||
// Einschaltvorgaengen in den Update-Modus.
|
||||
{ Preferences p; p.begin("bootguard", false); p.putUShort("early", 0); p.end(); }
|
||||
DBG_SERIAL.println(F("[Panel] Kaltstart - einmaliger Neustart fuer das Displaypanel"));
|
||||
DBG_SERIAL.flush();
|
||||
p.putUShort("early", 0);
|
||||
p.end();
|
||||
esp_rom_printf("[Panel] Kaltstart - einmaliger Neustart fuer das Displaypanel\n");
|
||||
delay(50);
|
||||
esp_restart();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
g_client.begin(); // UART starten, hello folgt automatisch in loop()
|
||||
|
||||
|
||||
@@ -235,9 +235,34 @@ void jc_backlight_set(int percent)
|
||||
if (percent > 100) percent = 100;
|
||||
if (percent < 0) percent = 0;
|
||||
uint8_t brightness = (uint8_t)((255 * percent) / 100);
|
||||
uint8_t wert = (uint8_t)(255 - brightness);
|
||||
int64_t t0 = esp_timer_get_time();
|
||||
|
||||
// Die Bridge uebernimmt eine neue Helligkeit nicht zuverlaessig beim ersten Mal. Der
|
||||
// Beispielcode von Waveshare setzt sie deshalb zweimal, mit einer Pause dazwischen,
|
||||
// ausdruecklich "sicherheitshalber". Uns fehlte diese Wiederholung: Das Bild stand
|
||||
// dann fertig da, blieb aber dunkel, bis die Uebernahme irgendwann doch griff - beim
|
||||
// Ein- und Ausschalten des Standby waren das mehrere Sekunden.
|
||||
//
|
||||
// Die Freigabe (0xAD) bleibt beim ersten Aufruf, danach nicht mehr: Sie erneut zu
|
||||
// setzen, waehrend die Beleuchtung laeuft, stoesst die Helligkeitsstufe der Bridge neu
|
||||
// an - der Beispielcode setzt sie darum ebenfalls nur ein einziges Mal.
|
||||
static bool freigegeben = false;
|
||||
if (!freigegeben) {
|
||||
ws7_bridge_write(0xAD, 0x01); // Panel-/Backlight-Freigabe
|
||||
ws7_bridge_write(0xAB, (uint8_t)(255 - brightness));
|
||||
vTaskDelay(pdMS_TO_TICKS(20)); // wie im Beispielcode: Bridge setzen lassen
|
||||
freigegeben = true;
|
||||
}
|
||||
|
||||
ws7_bridge_write(0xAB, wert);
|
||||
ws7_bridge_write(0xAA, 0x01); // Helligkeit uebernehmen
|
||||
vTaskDelay(pdMS_TO_TICKS(WS7_BACKLIGHT_LATCH_MS));
|
||||
ws7_bridge_write(0xAB, wert); // Wiederholung, siehe oben
|
||||
ws7_bridge_write(0xAA, 0x01);
|
||||
|
||||
esp_rom_printf("[HAL] %u ms: Helligkeit %d %% gesetzt, brauchte %u ms\n",
|
||||
(unsigned)(esp_timer_get_time() / 1000), percent,
|
||||
(unsigned)((esp_timer_get_time() - t0) / 1000));
|
||||
}
|
||||
|
||||
// =====================================================================================
|
||||
@@ -310,14 +335,26 @@ static bool ws7_touch_get_xy(esp_lcd_touch_handle_t tp, uint16_t *x, uint16_t *y
|
||||
bool got = s_touch_get_xy_orig(tp, x, y, strength, point_num, max_point_num);
|
||||
int64_t now = esp_timer_get_time();
|
||||
|
||||
// Unplausible Rohwerte gelten als Aussetzer, nicht als Beruehrung.
|
||||
// Unplausible Rohwerte gelten als Aussetzer, nicht als Beruehrung. Wie viele davon
|
||||
// anfallen, war bisher nirgends zu sehen - eine Beruehrung, deren Rohwerte lange
|
||||
// verworfen werden, sieht von aussen wie ein Display aus, das nicht reagiert.
|
||||
static uint32_t s_verworfen = 0;
|
||||
if (got && *point_num > 0 &&
|
||||
(x[0] > WS7_TOUCH_RAW_X_MAX || y[0] > WS7_TOUCH_RAW_Y_MAX)) {
|
||||
if (s_verworfen == 0)
|
||||
esp_rom_printf("[Touch] %u ms: Rohwert verworfen (x %u, y %u liegen ausserhalb)\n",
|
||||
(unsigned)(now / 1000), (unsigned)x[0], (unsigned)y[0]);
|
||||
s_verworfen++;
|
||||
got = false;
|
||||
*point_num = 0;
|
||||
}
|
||||
|
||||
if (got && *point_num > 0) {
|
||||
if (!s_touch_down)
|
||||
esp_rom_printf("[Touch] %u ms: Beruehrung erkannt bei x %u, y %u; %u Rohwerte vorher verworfen\n",
|
||||
(unsigned)(now / 1000), (unsigned)x[0], (unsigned)y[0],
|
||||
(unsigned)s_verworfen);
|
||||
s_verworfen = 0;
|
||||
s_touch_last_x = x[0];
|
||||
s_touch_last_y = y[0];
|
||||
s_touch_last_us = now;
|
||||
|
||||
@@ -374,8 +374,10 @@
|
||||
#define LV_USE_ASSERT_OBJ 0 /*Check the object's type and existence (e.g. not deleted). (Slow)*/
|
||||
|
||||
/*Add a custom handler when assert happens e.g. to restart the MCU*/
|
||||
#define LV_ASSERT_HANDLER_INCLUDE <stdint.h>
|
||||
#define LV_ASSERT_HANDLER while(1); /*Halt by default*/
|
||||
#define LV_ASSERT_HANDLER_INCLUDE <esp_rom_sys.h>
|
||||
// Frueher hielt LVGL hier stumm in einer Endlosschleife an - das Display stand, ohne dass
|
||||
// irgendwo etwas davon zu sehen war. Jetzt sagt es wenigstens, dass es angehalten hat.
|
||||
#define LV_ASSERT_HANDLER esp_rom_printf("[LVGL] Zusicherung verletzt - Zeichenablauf haelt an\n"); while(1);
|
||||
|
||||
/*-------------
|
||||
* Debug
|
||||
@@ -571,7 +573,9 @@
|
||||
LV_FONT_DECLARE(lv_font_maven_pro_bold_140) \
|
||||
LV_FONT_DECLARE(lv_font_clock_120) \
|
||||
LV_FONT_DECLARE(lv_font_clock_180) \
|
||||
LV_FONT_DECLARE(lv_font_clock_240)
|
||||
LV_FONT_DECLARE(lv_font_clock_240) \
|
||||
LV_FONT_DECLARE(lv_font_clock_270) \
|
||||
LV_FONT_DECLARE(lv_font_clock_360)
|
||||
|
||||
/*Always set a default font*/
|
||||
#define LV_FONT_DEFAULT &lv_font_maven_pro_14
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -39,10 +39,12 @@
|
||||
// nicht - siehe die ausfuehrliche Begruendung weiter unten beim Avoid-Tear-Schalter.
|
||||
// Auf 0 nur, wenn das Startverhalten erneut untersucht wird.
|
||||
#define WS7_SINGLE_FB 1
|
||||
// LVGL zeichnet direkt in den Bildspeicher, statt in einen eigenen Puffer zu zeichnen und
|
||||
// den danach zu kopieren. Spart pro Bild einen kompletten Durchgang durch 2,7 MB PSRAM
|
||||
// und laesst LVGL nur die geaenderten Bereiche neu zeichnen. Braucht WS7_SINGLE_FB.
|
||||
#define WS7_DIRECT_FB 1
|
||||
// LVGL zeichnet direkt in den Bildspeicher statt in einen eigenen Puffer, dessen Inhalt
|
||||
// danach kopiert wird. GEPRUEFT: bringt an diesem Panel nichts (die Bildaufbauzeit blieb bei
|
||||
// 240-300 ms) und erzeugt Bildfehler, weil in denselben Speicher gezeichnet wird, aus dem
|
||||
// gerade angezeigt wird. Der Flaschenhals liegt also nicht im Kopieren, sondern im Zeichnen
|
||||
// selbst. Bleibt als Schalter erhalten, damit der Versuch nicht erneut gemacht wird.
|
||||
#define WS7_DIRECT_FB 0
|
||||
#define WS7_PARALLEL_RENDER 1
|
||||
|
||||
#define EXAMPLE_LVGL_PORT_TASK_MAX_DELAY_MS 500 //range 2 to 2000
|
||||
@@ -180,6 +182,14 @@
|
||||
// auf I2C antwortet. Meldet sich 0x14 beim Start nicht, diesen Wert erhoehen.
|
||||
#define WS7_TOUCH_POWER_MS 120
|
||||
|
||||
// Pause zwischen den beiden Helligkeitsuebernahmen der Bridge. Sie uebernimmt eine neue
|
||||
// Helligkeit nicht zuverlaessig beim ersten Mal; der Beispielcode von Waveshare setzt sie
|
||||
// darum zweimal. Ohne die Wiederholung stand das Bild fertig da, blieb aber dunkel - beim
|
||||
// Wechsel in den und aus dem Standby mehrere Sekunden lang. Der Beispielcode wartet 100 ms;
|
||||
// weniger genuegt hier, weil die Wiederholung ohnehin folgt. Bleibt die Beleuchtung wieder
|
||||
// hinterher, diesen Wert erhoehen.
|
||||
#define WS7_BACKLIGHT_LATCH_MS 20
|
||||
|
||||
// Prueffarbbalken statt Oberflaeche anzeigen. Sie entstehen im DSI-Baustein selbst und
|
||||
// benutzen weder Bildspeicher noch LVGL. Damit laesst sich trennen, ob die Anzeigekette
|
||||
// bis zum Panel arbeitet (Balken sichtbar) oder nicht (schwarz). Nur zur Fehlersuche.
|
||||
|
||||
+265
-74
@@ -18,12 +18,15 @@
|
||||
#include <Arduino.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <Preferences.h> // Dashboard-Design P4-lokal merken (NVS)
|
||||
#include <esp_memory_utils.h> // esp_ptr_external_ram(): welcher Speicher einen Puffer traegt
|
||||
#include <esp_heap_caps.h> // Verlaufs-Historie im PSRAM allozieren (interner RAM ist knapp)
|
||||
#include "ui.h"
|
||||
#include <Preferences.h>
|
||||
#include "esp_system.h"
|
||||
#include "display_hal.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "lvgl_private.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Schriftgroesse
|
||||
@@ -125,8 +128,8 @@ static lv_obj_t* g_otaStatus = nullptr;
|
||||
static lv_obj_t* g_otaBytes = nullptr;
|
||||
|
||||
// Navigation
|
||||
enum { PG_DASH = 0, PG_CHART, PG_STATS, PG_TEMP, PG_BREW, PG_COLDEX, PG_SERVICE, PG_PROFILE, PG_LIGHT, PG_WIFI, PG_INFO, PG_COUNT };
|
||||
static const char* PAGE_NAMES[PG_COUNT] = { "Dashboard", "Verlauf", "Statistik", "Temperatur", "Brew-Control", "Cold Extraction", "Reinigung/Wartung", "Profile", "Licht", "WiFi", "Info" };
|
||||
enum { PG_DASH = 0, PG_CHART, PG_STATS, PG_TEMP, PG_BREW, PG_COLDEX, PG_SERVICE, PG_PROFILE, PG_LIGHT, PG_WIFI, PG_DISPLAY, PG_INFO, PG_COUNT };
|
||||
static const char* PAGE_NAMES[PG_COUNT] = { "Dashboard", "Verlauf", "Statistik", "Temperatur", "Brew-Control", "Cold Extraction", "Reinigung/Wartung", "Profile", "Licht", "WiFi", "Darstellung", "Info" };
|
||||
static lv_obj_t* g_content = nullptr;
|
||||
static lv_obj_t* g_pages[PG_COUNT] = { nullptr };
|
||||
static lv_obj_t* g_drawer = nullptr;
|
||||
@@ -176,6 +179,9 @@ enum TempDesign { TD_GEWICHTET = 0, TD_VERLAUF, TD_FLAECHEN, TD_BAND, TD_DESIGN_
|
||||
static uint8_t g_tempDesign = TD_BAND;
|
||||
static bool g_tempColored = false; // Temperaturzahl in der Zustandsfarbe statt weiss
|
||||
#define DASH_SPARK_POINTS 60 // eine Minute Verlauf, ein Punkt je Sekunde
|
||||
// Kleinster Ausschnitt der Verlaufskurve in Zehntelgrad. Ohne Untergrenze blaeht ein
|
||||
// ruhig geregelter Kessel jedes Zehntelgrad zum vollen Ausschlag auf.
|
||||
#define DASH_SPARK_MIN_SPAN 40 // 4,0 Grad
|
||||
static lv_obj_t* g_sparkW = nullptr; // Verlaufskurven der Darstellung TD_VERLAUF
|
||||
static lv_obj_t* g_sparkD = nullptr;
|
||||
static lv_chart_series_t* g_sparkSerW = nullptr;
|
||||
@@ -698,9 +704,17 @@ static lv_obj_t* g_clockSizeBtn[3] = {};
|
||||
|
||||
static const lv_font_t* clock_font() {
|
||||
switch (g_clockSize) {
|
||||
#if JC_PANEL_TYPE == WS_PANEL_7H
|
||||
// 7 Zoll, 1280x720: Hier war selbst die groesste Stufe noch zu klein.
|
||||
case UHR_KLEIN: return &lv_font_clock_180;
|
||||
case UHR_MITTEL: return &lv_font_clock_270;
|
||||
default: return &lv_font_clock_360;
|
||||
#else
|
||||
// 4,3 Zoll, 480x480: Groessere Stufen passen schlicht nicht auf das Panel.
|
||||
case UHR_KLEIN: return &lv_font_clock_120;
|
||||
case UHR_MITTEL: return &lv_font_clock_180;
|
||||
default: return &lv_font_clock_240;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,13 +722,10 @@ static void clock_size_apply() {
|
||||
if (g_standbyClock) lv_obj_set_style_text_font(g_standbyClock, clock_font(), 0);
|
||||
}
|
||||
|
||||
static void scroll_ohne_nachlauf(lv_obj_t* o) {
|
||||
#if JC_PANEL_TYPE == WS_PANEL_7H
|
||||
lv_obj_clear_flag(o, LV_OBJ_FLAG_SCROLL_MOMENTUM);
|
||||
#else
|
||||
(void)o;
|
||||
#endif
|
||||
}
|
||||
// Der Nachlauf beim Wischen war auf dem Waveshare-Panel eine Zeit lang abgeschaltet, weil
|
||||
// jedes Einzelbild waehrend des Schwungs den ganzen Schirm neu zeichnete. Seit die
|
||||
// Anzeigewerte feste Masse haben, faellt das weg - das Menue laeuft mit Nachlauf fluessig.
|
||||
static void scroll_ohne_nachlauf(lv_obj_t* o) { (void)o; }
|
||||
|
||||
static lv_obj_t* make_page(lv_obj_t* parent) {
|
||||
lv_obj_t* p = lv_obj_create(parent);
|
||||
@@ -919,7 +930,9 @@ static bool wake_choice_offered() {
|
||||
return g_state.cxWakeChoice ||
|
||||
(g_state.cxEnabled && g_state.cxArmable && g_state.cxAskOnWake);
|
||||
}
|
||||
static void standby_screen_cb(lv_event_t*) { wake_confirm_show(); } // Tipp auf Standby-Uhr -> nachfragen
|
||||
static void standby_screen_cb(lv_event_t*) { // Tipp auf Standby-Uhr -> nachfragen
|
||||
wake_confirm_show();
|
||||
}
|
||||
static void wake_cancel() { // Abbrechen -> zurueck in die Standby-Helligkeit
|
||||
wake_timeout_stop();
|
||||
wake_confirm_hide();
|
||||
@@ -984,7 +997,10 @@ static lv_color_t temp_state_color(float temp, float set) {
|
||||
static void temp_progress_set(lv_obj_t* bar, lv_obj_t* arc, lv_obj_t* bulb, int pct, lv_color_t col) {
|
||||
if (pct > 100) pct = 100; else if (pct < 0) pct = 0;
|
||||
if (bar) {
|
||||
lv_bar_set_value(bar, pct, LV_ANIM_OFF);
|
||||
// Wert und Farbe nur bei echter Aenderung setzen - beides macht den Balken sonst
|
||||
// bei jeder Zustandsmeldung ungueltig, obwohl sich meist nichts bewegt hat.
|
||||
if (lv_bar_get_value(bar) != pct) lv_bar_set_value(bar, pct, LV_ANIM_OFF);
|
||||
if (lv_color_to_u32(lv_obj_get_style_bg_color(bar, LV_PART_INDICATOR)) != lv_color_to_u32(col))
|
||||
lv_obj_set_style_bg_color(bar, col, LV_PART_INDICATOR);
|
||||
}
|
||||
if (arc) {
|
||||
@@ -1051,6 +1067,18 @@ static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accen
|
||||
lv_label_set_text(*big, "--.-");
|
||||
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*big, valueFont, 0);
|
||||
// Feste Breite, Text zentriert. Waechst oder schrumpft eine Beschriftung mit ihrem
|
||||
// Inhalt - etwa von "92,4 °C" auf "100,1 °C" -, rechnet LVGL das Flex-Layout der
|
||||
// gesamten Seite neu und macht sie damit komplett ungueltig. Genau das war im
|
||||
// Messprotokoll als "x 0..1279, y 44..719" zu sehen: der ganze Inhaltsbereich, bei
|
||||
// jeder Zustandsmeldung. Mit fester Breite bleibt nur die Beschriftung selbst ungueltig.
|
||||
lv_obj_set_width(*big, LV_PCT(100));
|
||||
lv_obj_set_style_text_align(*big, LV_TEXT_ALIGN_CENTER, 0);
|
||||
// Auch die HOEHE muss fest sein. LVGL prueft beim Setzen eines Textes, ob sich die
|
||||
// Eigengroesse der Beschriftung geaendert haben koennte - ist eines der beiden Masse
|
||||
// frei, gilt das Layout des Elternteils als neu zu berechnen, und das macht die ganze
|
||||
// Seite ungueltig. Erst mit festen Massen bleibt nur die Beschriftung selbst ungueltig.
|
||||
lv_obj_set_height(*big, lv_font_get_line_height(valueFont) + 6);
|
||||
// Grosse Zahlen etwas enger setzen. Bei dieser Groesse wirken die Werksabstaende
|
||||
// auseinandergezogen; ein paar Pixel weniger binden die Ziffern zu einer Zahl zusammen.
|
||||
if (valueFont == &lv_font_maven_pro_bold_140) lv_obj_set_style_text_letter_space(*big, -3, 0);
|
||||
@@ -1060,6 +1088,9 @@ static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accen
|
||||
lv_label_set_text(*setp, "Soll --.-");
|
||||
lv_obj_set_style_text_color(*setp, COL_TEXT_DIM, 0);
|
||||
lv_obj_set_style_text_font(*setp, font_text(), 0);
|
||||
lv_obj_set_width(*setp, LV_PCT(100));
|
||||
lv_obj_set_style_text_align(*setp, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_height(*setp, lv_font_get_line_height(font_text()) + 6);
|
||||
|
||||
*bar = lv_bar_create(c);
|
||||
lv_obj_set_size(*bar, LV_PCT(92), 8);
|
||||
@@ -1077,10 +1108,66 @@ static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accen
|
||||
// Flache Verlaufskurve unter einer Temperatur. Zeigt, ob die Regelung haelt - das ist die
|
||||
// eigentliche Frage an eine PID-Regelung, und eine Zahl kann sie grundsaetzlich nicht
|
||||
// beantworten. Gespeist wird sie aus derselben Sekundenabtastung wie die Verlaufsseite.
|
||||
// Gemeinsamer Ausschnitt fuer BEIDE Verlaufskurven.
|
||||
//
|
||||
// Zwei Anlaeufe waren vorher daneben. Erst hing der Ausschnitt am Sollwert - dann lag beim
|
||||
// Aufheizen jeder Messwert unterhalb des Fensters und wurde auf den unteren Rand geklemmt.
|
||||
// Danach zoomte jede Kurve auf ihre eigenen Werte - dann sass jede mittig in ihrem eigenen
|
||||
// Fenster, und Wasser bei 70 Grad lag genauso hoch wie Dampf bei 0. Die Hoehe sagte nichts.
|
||||
//
|
||||
// Jetzt teilen sich beide Kurven eine Skala, die sich nach den Werten beider zusammen
|
||||
// richtet. Damit ist die Hoehe wieder vergleichbar - der waermere Kessel liegt sichtbar
|
||||
// hoeher -, und die Skala bleibt so eng, wie es die Daten zulassen: Stehen beide Kessel
|
||||
// dicht beieinander, greift die Mindestspanne und schon Zehntelgrade sind zu sehen.
|
||||
static int32_t g_sparkMin = INT32_MIN; // zuletzt gesetzter Ausschnitt, fuer beide gleich
|
||||
static int32_t g_sparkMax = INT32_MIN;
|
||||
|
||||
static void spark_scan(lv_obj_t* ch, lv_chart_series_t* ser, int32_t* mn, int32_t* mx) {
|
||||
if (!ch || !ser) return;
|
||||
int32_t* pts = lv_chart_get_y_array(ch, ser);
|
||||
if (!pts) return;
|
||||
uint32_t n = lv_chart_get_point_count(ch);
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
if (pts[i] == LV_CHART_POINT_NONE) continue;
|
||||
if (pts[i] < *mn) *mn = pts[i];
|
||||
if (pts[i] > *mx) *mx = pts[i];
|
||||
}
|
||||
}
|
||||
|
||||
static void spark_ranges_fit() {
|
||||
int32_t mn = INT32_MAX, mx = INT32_MIN;
|
||||
spark_scan(g_sparkW, g_sparkSerW, &mn, &mx);
|
||||
spark_scan(g_sparkD, g_sparkSerD, &mn, &mx);
|
||||
if (mn > mx) return; // noch kein einziger Wert
|
||||
if (mx - mn < DASH_SPARK_MIN_SPAN) { // beide dicht beieinander: mittig halten
|
||||
int32_t mitte = (mn + mx) / 2;
|
||||
mn = mitte - DASH_SPARK_MIN_SPAN / 2;
|
||||
mx = mitte + DASH_SPARK_MIN_SPAN / 2;
|
||||
} else { // sonst etwas Luft nach oben und unten
|
||||
int32_t luft = (mx - mn) / 8;
|
||||
mn -= luft;
|
||||
mx += luft;
|
||||
}
|
||||
// Nur bei echter Aenderung setzen - lv_chart_set_range macht das Diagramm sonst bei
|
||||
// jeder Zustandsmeldung ungueltig, auch wenn sich der Ausschnitt gar nicht ruehrt.
|
||||
// Abfragen laesst sich der gesetzte Ausschnitt bei LVGL nicht, also wird er gemerkt.
|
||||
if (mn == g_sparkMin && mx == g_sparkMax) return;
|
||||
g_sparkMin = mn;
|
||||
g_sparkMax = mx;
|
||||
if (g_sparkW) lv_chart_set_range(g_sparkW, LV_CHART_AXIS_PRIMARY_Y, mn, mx);
|
||||
if (g_sparkD) lv_chart_set_range(g_sparkD, LV_CHART_AXIS_PRIMARY_Y, mn, mx);
|
||||
}
|
||||
|
||||
static lv_obj_t* tempSpark(lv_obj_t* parent, lv_color_t col, lv_chart_series_t** ser,
|
||||
float jetzt, float soll) {
|
||||
lv_obj_t* ch = lv_chart_create(parent);
|
||||
lv_obj_set_size(ch, LV_PCT(96), 64);
|
||||
// Die Kurve nimmt den Platz unterhalb der Zahlen ein, statt als schmaler Streifen in
|
||||
// der Mitte zu haengen. Sie beginnt damit weiter unten auf der Karte und hat deutlich
|
||||
// mehr Hoehe - Temperaturaenderungen sind so ueberhaupt erst zu erkennen.
|
||||
lv_obj_set_width(ch, LV_PCT(96));
|
||||
lv_obj_set_height(ch, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(ch, 1);
|
||||
lv_obj_set_style_min_height(ch, 90, 0);
|
||||
lv_chart_set_type(ch, LV_CHART_TYPE_LINE);
|
||||
lv_chart_set_point_count(ch, DASH_SPARK_POINTS);
|
||||
lv_chart_set_div_line_count(ch, 0, 0);
|
||||
@@ -1094,13 +1181,12 @@ static lv_obj_t* tempSpark(lv_obj_t* parent, lv_color_t col, lv_chart_series_t**
|
||||
lv_obj_clear_flag(ch, LV_OBJ_FLAG_SCROLLABLE);
|
||||
*ser = lv_chart_add_series(ch, col, LV_CHART_AXIS_PRIMARY_Y);
|
||||
|
||||
// Ausschnitt und Startwert sofort setzen. Ein frisch angelegtes Diagramm hat lauter
|
||||
// "kein Wert"-Punkte und zeichnet deshalb nichts - beim Umschalten der Darstellung
|
||||
// saehe man bis zur ersten Sekundenprobe eine leere Flaeche.
|
||||
int32_t sollT = (int32_t)(soll * 10.0f);
|
||||
lv_chart_set_range(ch, LV_CHART_AXIS_PRIMARY_Y, sollT - 60, sollT + 30);
|
||||
// Startwert sofort setzen. Ein frisch angelegtes Diagramm hat lauter "kein Wert"-Punkte
|
||||
// und zeichnet deshalb nichts - beim Umschalten der Darstellung saehe man bis zur
|
||||
// ersten Sekundenprobe eine leere Flaeche.
|
||||
(void)soll;
|
||||
lv_chart_set_all_value(ch, *ser, (int32_t)(jetzt * 10.0f));
|
||||
return ch;
|
||||
return ch; // Ausschnitt setzt spark_ranges_fit(), sobald beide Kurven stehen
|
||||
}
|
||||
|
||||
// Temperaturbereich gemaess aktiver Darstellung (neu) aufbauen - auch beim Umschalten
|
||||
@@ -1113,6 +1199,7 @@ static void build_temp_row_content() {
|
||||
bulbTempW = bulbTempD = nullptr;
|
||||
g_sparkW = g_sparkD = nullptr;
|
||||
g_sparkSerW = g_sparkSerD = nullptr;
|
||||
g_sparkMin = g_sparkMax = INT32_MIN; // gemerkter Ausschnitt gilt fuer die alten Kurven
|
||||
g_readyBand = g_readyBandLbl = nullptr;
|
||||
|
||||
const lv_color_t teal = lv_color_hex(0x80cbc4);
|
||||
@@ -1141,6 +1228,7 @@ static void build_temp_row_content() {
|
||||
lv_obj_t* cd = tempField(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
||||
1, &lv_font_maven_pro_bold_96, false, 0);
|
||||
g_sparkD = tempSpark(cd, COL_ACCENT, &g_sparkSerD, g_state.tempD, g_state.setD);
|
||||
spark_ranges_fit();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1205,6 +1293,10 @@ static lv_obj_t* infoCell(lv_obj_t* parent, const char* title, lv_obj_t** val, l
|
||||
lv_obj_set_style_text_color(*val, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*val, font_title(), 0);
|
||||
lv_obj_set_style_text_align(*val, LV_TEXT_ALIGN_CENTER, 0); // fuer mehrzeilige Werte
|
||||
// Feste Masse in BEIDE Richtungen - siehe die ausfuehrliche Begruendung in tempField.
|
||||
// Zwei Zeilen Platz, weil manche Werte zweizeilig sind ("32,4 g / 36,0 g").
|
||||
lv_obj_set_width(*val, LV_PCT(100));
|
||||
lv_obj_set_height(*val, lv_font_get_line_height(font_title()) * 2 + 6);
|
||||
return card;
|
||||
}
|
||||
// Tipp auf die Statuszeile: Wartung -> Serviceseite, Reinigung -> Sub-Screen,
|
||||
@@ -1376,7 +1468,7 @@ static void flush_targ() {
|
||||
static void targ_w_set(float v) {
|
||||
if (v < 0) v = 0; if (v > 135) v = 135;
|
||||
g_targW = v;
|
||||
if (lblTargW) lv_label_set_text(lblTargW, tempStr(g_targW, 0).c_str());
|
||||
if (lblTargW) label_set_if_changed(lblTargW, tempStr(g_targW, 0).c_str());
|
||||
if (g_arcW) lv_arc_set_value(g_arcW, (int32_t)(g_targW + 0.5f));
|
||||
g_targWDirty = true;
|
||||
schedule_targ_send();
|
||||
@@ -1384,7 +1476,7 @@ static void targ_w_set(float v) {
|
||||
static void targ_d_set(float v) {
|
||||
if (v < 0) v = 0; if (v > 200) v = 200;
|
||||
g_targD = v;
|
||||
if (lblTargD) lv_label_set_text(lblTargD, tempStr(g_targD, 0).c_str());
|
||||
if (lblTargD) label_set_if_changed(lblTargD, tempStr(g_targD, 0).c_str());
|
||||
if (g_arcD) lv_arc_set_value(g_arcD, (int32_t)(g_targD + 0.5f));
|
||||
g_targDDirty = true;
|
||||
schedule_targ_send();
|
||||
@@ -1636,19 +1728,13 @@ static void chart_duty_btn_cb(lv_event_t*) {
|
||||
}
|
||||
chart_redraw();
|
||||
|
||||
// Verlaufskurven des Dashboards (Darstellung "Verlauf") mitfuehren. Der Ausschnitt
|
||||
// haengt am Sollwert, damit die Abweichung sichtbar wird und nicht in der Skala
|
||||
// untergeht - eine feste Skala von 0 bis 130 Grad zeigte nur eine gerade Linie.
|
||||
if (g_sparkSerW && g_sparkW) {
|
||||
int32_t soll = (int32_t)(g_state.setW * 10.0f);
|
||||
lv_chart_set_range(g_sparkW, LV_CHART_AXIS_PRIMARY_Y, soll - 60, soll + 30);
|
||||
// Verlaufskurven des Dashboards (Darstellung "Verlauf") mitfuehren. Beide teilen sich
|
||||
// eine Skala, siehe spark_ranges_fit().
|
||||
if (g_sparkSerW && g_sparkW)
|
||||
lv_chart_set_next_value(g_sparkW, g_sparkSerW, (int32_t)(g_state.tempW * 10.0f));
|
||||
}
|
||||
if (g_sparkSerD && g_sparkD) {
|
||||
int32_t soll = (int32_t)(g_state.setD * 10.0f);
|
||||
lv_chart_set_range(g_sparkD, LV_CHART_AXIS_PRIMARY_Y, soll - 120, soll + 60);
|
||||
if (g_sparkSerD && g_sparkD)
|
||||
lv_chart_set_next_value(g_sparkD, g_sparkSerD, (int32_t)(g_state.tempD * 10.0f));
|
||||
}
|
||||
spark_ranges_fit(); // gemeinsame Skala, damit die Hoehen vergleichbar bleiben
|
||||
}
|
||||
static void build_chart(lv_obj_t* p) {
|
||||
lv_obj_clear_flag(p, LV_OBJ_FLAG_SCROLLABLE);
|
||||
@@ -3076,8 +3162,10 @@ static void brew_live_sw_cb(lv_event_t* e) {
|
||||
{ Preferences prefs; prefs.begin("ui", false); prefs.putBool("brewlive", g_brewLiveEnabled); prefs.end(); }
|
||||
if (!g_brewLiveEnabled) brew_live_hide(); // laeuft gerade ein Bezug: sofort ausblenden
|
||||
}
|
||||
static void build_info(lv_obj_t* p) {
|
||||
section_title(p, "Darstellung");
|
||||
// Eigener Menuepunkt "Darstellung". Die Einstellungen sassen frueher oben auf der
|
||||
// Info-Seite; dort standen sie zwischen Firmware-Staenden und Verbindungsdaten,
|
||||
// mit denen sie nichts zu tun haben.
|
||||
static void build_display(lv_obj_t* p) {
|
||||
lv_obj_t* dcard = th_card(p);
|
||||
lv_obj_set_width(dcard, LV_PCT(100));
|
||||
lv_obj_set_height(dcard, LV_SIZE_CONTENT);
|
||||
@@ -3130,6 +3218,9 @@ static void build_info(lv_obj_t* p) {
|
||||
sw_set(swBrewLive, g_brewLiveEnabled);
|
||||
lv_obj_add_event_cb(swBrewLive, brew_live_sw_cb, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
|
||||
}
|
||||
|
||||
static void build_info(lv_obj_t* p) {
|
||||
section_title(p, "Firmware-Stände & Verbindung");
|
||||
|
||||
lv_obj_t* card = th_card(p);
|
||||
@@ -3239,10 +3330,35 @@ static void eco_case_timer_cb(lv_timer_t*) {
|
||||
// =====================================================================================
|
||||
// Setzt den Labeltext nur, wenn er sich aendert -> verhindert unnoetige Invalidierung
|
||||
// (im Full-Refresh-Modus loest jede Aenderung ein komplettes Neuzeichnen aus).
|
||||
// LVGL macht bei jedem Setzen den Bereich der Beschriftung ungueltig - auch dann, wenn sich
|
||||
// der Text gar nicht geaendert hat. Auf dem Dashboard werden im Sekundentakt Werte quer ueber
|
||||
// den ganzen Bildschirm gesetzt; LVGL fasst die ungueltigen Bereiche zu einem zusammen, und
|
||||
// das ist dann die gesamte Flaeche. Gemessen waren das 240 bis 300 ms pro Sekunde, in denen
|
||||
// die Oberflaeche mit nichts anderem beschaeftigt war. Deshalb wird ueberall dort, wo sich
|
||||
// Werte nur selten aendern, vorher verglichen.
|
||||
static void label_set_if_changed(lv_obj_t* lbl, const char* txt) {
|
||||
if (!lbl || !txt) return;
|
||||
const char* cur = lv_label_get_text(lbl);
|
||||
if (!cur || strcmp(cur, txt) != 0) lv_label_set_text(lbl, txt);
|
||||
}
|
||||
|
||||
// Wie oben, aber mit Formatangabe.
|
||||
static void label_fmt_if_changed(lv_obj_t* lbl, const char* fmt, ...) {
|
||||
if (!lbl) return;
|
||||
char buf[96];
|
||||
va_list ap; va_start(ap, fmt);
|
||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||
va_end(ap);
|
||||
label_set_if_changed(lbl, buf);
|
||||
}
|
||||
|
||||
// Auch ein Farbwechsel macht den Bereich ungueltig. Gleiche Farbe -> nichts tun.
|
||||
static void label_color_if_changed(lv_obj_t* lbl, lv_color_t col) {
|
||||
if (!lbl) return;
|
||||
lv_color_t cur = lv_obj_get_style_text_color(lbl, LV_PART_MAIN);
|
||||
if (lv_color_to_u32(cur) != lv_color_to_u32(col))
|
||||
lv_obj_set_style_text_color(lbl, col, 0);
|
||||
}
|
||||
// Pre-Infusion-Phasenleiste aktualisieren (100-ms-Takt aus dash_timers_cb).
|
||||
// Die aktive Phase kommt bevorzugt von der S3 (piState = echte Statemachine, Quelle der
|
||||
// Wahrheit; Push-Latenz max. 250 ms). Sendet eine aeltere S3-Firmware das Feld noch nicht
|
||||
@@ -3464,11 +3580,73 @@ static bool g_uiReady = false;
|
||||
|
||||
static uint32_t g_refrStart = 0;
|
||||
|
||||
static void refr_start_cb(lv_event_t*) { g_refrStart = lv_tick_get(); }
|
||||
static uint32_t g_refrPixels = 0;
|
||||
static uint32_t g_refrAreas = 0;
|
||||
static lv_area_t g_refrArea[6];
|
||||
static uint8_t g_refrAreaCnt = 0;
|
||||
|
||||
// Beim Start eines Zeichenzyklus festhalten, WIE VIEL neu gezeichnet wird. Erst damit laesst
|
||||
// sich unterscheiden, ob LVGL nur kleine Bereiche anfasst - dann ist das Zeichnen an sich zu
|
||||
// langsam - oder ob jedes Mal der ganze Bildschirm neu entsteht, weil ihn etwas unnoetig
|
||||
// ungueltig macht.
|
||||
static void refr_start_cb(lv_event_t*) {
|
||||
g_refrStart = lv_tick_get();
|
||||
g_refrPixels = 0;
|
||||
g_refrAreas = 0;
|
||||
g_refrAreaCnt = 0;
|
||||
lv_display_t* d = lv_display_get_default();
|
||||
if (!d) return;
|
||||
for (uint16_t i = 0; i < d->inv_p; i++) {
|
||||
if (d->inv_area_joined[i]) continue;
|
||||
const lv_area_t* a = &d->inv_areas[i];
|
||||
g_refrPixels += (uint32_t)(a->x2 - a->x1 + 1) * (uint32_t)(a->y2 - a->y1 + 1);
|
||||
if (g_refrAreaCnt < 6) g_refrArea[g_refrAreaCnt++] = *a;
|
||||
g_refrAreas++;
|
||||
}
|
||||
}
|
||||
|
||||
static void refr_ready_cb(lv_event_t*) {
|
||||
uint32_t d = lv_tick_get() - g_refrStart;
|
||||
if (d >= REFR_WARN_MS) esp_rom_printf("[UI] Bildaufbau %u ms\n", (unsigned)d);
|
||||
if (d < REFR_WARN_MS) return;
|
||||
unsigned pct = (unsigned)((uint64_t)g_refrPixels * 100ULL / ((uint64_t)LCD_H_RES * LCD_V_RES));
|
||||
esp_rom_printf("[UI] %u ms: Bildaufbau %u ms, %u Bereiche, %u %% der Flaeche\n", (unsigned)millis(),
|
||||
(unsigned)d, (unsigned)g_refrAreas, pct);
|
||||
// Lage der Bereiche mit ausgeben. Erst daran ist zu erkennen, WELCHER Teil der
|
||||
// Oberflaeche das Neuzeichnen ausloest - die Groesse allein sagt das nicht.
|
||||
for (uint8_t i = 0; i < g_refrAreaCnt; i++)
|
||||
esp_rom_printf(" Bereich %u: x %d..%d, y %d..%d\n", (unsigned)i,
|
||||
(int)g_refrArea[i].x1, (int)g_refrArea[i].x2,
|
||||
(int)g_refrArea[i].y1, (int)g_refrArea[i].y2);
|
||||
}
|
||||
|
||||
// LVGL legt fuer JEDE Textglyphe einen eigenen Zwischenpuffer an - Breite mal Hoehe, ein
|
||||
// Byte je Bildpunkt. Bei der grossen Standby-Uhr sind das 190 x 256 = rund 48 KB pro Ziffer,
|
||||
// und mit zwei parallel arbeitenden Zeicheneinheiten fast 100 KB gleichzeitig. Der interne
|
||||
// LVGL-Speicher fasst nur 245 KB, wovon rund 98 KB am Stueck frei sind - es reichte knapp
|
||||
// nicht. Schlaegt die Anforderung fehl, haelt LVGL per Zusicherung in einer Endlosschleife
|
||||
// an: kein Absturz, keine Meldung, das Display steht einfach. Genau das war der Stillstand
|
||||
// beim Wechsel in den Standby.
|
||||
//
|
||||
// Diese Puffer wandern daher in den externen Speicher (PSRAM, 32 MB frei). Kleine Glyphen
|
||||
// bleiben im internen Speicher, weil der schneller ist und Text sonst ueberall langsamer
|
||||
// wuerde; nur die grossen gehen nach aussen.
|
||||
#define FONT_BUF_EXTERN_AB 16384 // ab dieser Groesse in den externen Speicher
|
||||
|
||||
static void* font_buf_malloc(size_t size, lv_color_format_t cf) {
|
||||
LV_UNUSED(cf);
|
||||
size += LV_DRAW_BUF_ALIGN - 1;
|
||||
if (size >= FONT_BUF_EXTERN_AB) {
|
||||
void* p = heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (p) return p;
|
||||
}
|
||||
return lv_malloc(size);
|
||||
}
|
||||
|
||||
static void font_buf_free(void* buf) {
|
||||
// Der externe Speicher liegt ausserhalb des LVGL-Bereichs; daran ist zu erkennen,
|
||||
// welcher der beiden Wege den Puffer vergeben hat.
|
||||
if (esp_ptr_external_ram(buf)) heap_caps_free(buf);
|
||||
else lv_free(buf);
|
||||
}
|
||||
|
||||
static void refr_monitor_install() {
|
||||
@@ -3588,6 +3766,11 @@ void ui_init(ProtocolClient* client) {
|
||||
lv_obj_set_style_text_color(g_clock, COL_TEXT, 0);
|
||||
lv_obj_set_style_pad_right(g_clock, 10, 0);
|
||||
lv_obj_set_style_text_font(g_clock, font_text(), 0);
|
||||
// Feste Masse, sonst rechnet LVGL beim Wechsel der Minute das Layout der Kopfleiste neu
|
||||
// und macht sie samt Menue-Knopf ungueltig (siehe tempField).
|
||||
lv_obj_set_width(g_clock, 130);
|
||||
lv_obj_set_height(g_clock, lv_font_get_line_height(font_text()) + 4);
|
||||
lv_obj_set_style_text_align(g_clock, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
|
||||
g_wifiIcon = lv_label_create(header);
|
||||
lv_label_set_text(g_wifiIcon, LV_SYMBOL_WIFI);
|
||||
@@ -3615,22 +3798,18 @@ void ui_init(ProtocolClient* client) {
|
||||
g_pages[PG_SERVICE] = make_page(g_content); build_service(g_pages[PG_SERVICE]);
|
||||
g_pages[PG_WIFI] = make_page(g_content); build_wifi(g_pages[PG_WIFI]);
|
||||
g_pages[PG_PROFILE] = make_page(g_content); build_profiles(g_pages[PG_PROFILE]);
|
||||
g_pages[PG_DISPLAY] = make_page(g_content); build_display(g_pages[PG_DISPLAY]);
|
||||
g_pages[PG_INFO] = make_page(g_content); build_info(g_pages[PG_INFO]);
|
||||
|
||||
// --- Schublade (Scrim + Menue-Panel) ---
|
||||
g_drawer = lv_obj_create(scr);
|
||||
lv_obj_set_size(g_drawer, LV_PCT(100), DISP_VER_RES - 44);
|
||||
lv_obj_set_pos(g_drawer, 0, 44);
|
||||
#if JC_PANEL_TYPE == WS_PANEL_7H
|
||||
// Deckend statt halbdurchsichtig - aus demselben Grund wie beim Aufweckdialog: Ein
|
||||
// durchscheinender Vorhang laesst LVGL die ganze Flaeche darunter mitzeichnen und
|
||||
// mischen. Auf dunklem Grund sieht ein dunkles Deckend praktisch genauso aus.
|
||||
lv_obj_set_style_bg_color(g_drawer, lv_color_hex(0x0d0d0d), 0);
|
||||
lv_obj_set_style_bg_opa(g_drawer, LV_OPA_COVER, 0);
|
||||
#else
|
||||
// Bewusst durchscheinend: Der Vorhang legt sich ueber die ganze Seite, und der Inhalt
|
||||
// dahinter soll sichtbar bleiben. Ein Versuch mit deckendem Vorhang (gegen die
|
||||
// Zeichenlast) hat den Seiteninhalt verschwinden lassen und ist zurueckgenommen.
|
||||
lv_obj_set_style_bg_color(g_drawer, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_bg_opa(g_drawer, LV_OPA_50, 0);
|
||||
#endif
|
||||
lv_obj_set_style_border_width(g_drawer, 0, 0);
|
||||
lv_obj_set_style_pad_all(g_drawer, 0, 0);
|
||||
lv_obj_set_style_radius(g_drawer, 0, 0);
|
||||
@@ -3880,7 +4059,13 @@ void ui_init(ProtocolClient* client) {
|
||||
show_page(PG_DASH);
|
||||
if (g_client) g_client->sendListProfiles();
|
||||
|
||||
refr_monitor_install();
|
||||
// Glyphenpuffer umlenken, bevor der erste Text gezeichnet wird.
|
||||
lv_draw_buf_handlers_t* fh = lv_draw_buf_get_font_handlers();
|
||||
fh->buf_malloc_cb = font_buf_malloc;
|
||||
fh->buf_free_cb = font_buf_free;
|
||||
#if WS7_PERF_MONITOR
|
||||
refr_monitor_install(); // nur zum Einmessen, siehe WS7_PERF_MONITOR
|
||||
#endif
|
||||
g_uiReady = true;
|
||||
}
|
||||
|
||||
@@ -3947,11 +4132,15 @@ static void ready_band_update(const MachineState& st) {
|
||||
else if (wOk) { txt = "Wasser bereit — Dampf heizt"; bg = 0x3a2a05; fg = COL_ACCENT; }
|
||||
else { txt = "Heizt auf"; bg = 0x3a2a05; fg = COL_ACCENT; }
|
||||
}
|
||||
lv_label_set_text(g_readyBandLbl, txt);
|
||||
lv_obj_set_style_text_color(g_readyBandLbl, fg, 0);
|
||||
// Das Band spannt sich ueber die volle Breite. Wuerde es bei jeder Zustandsmeldung neu
|
||||
// gesetzt, machte es allein schon einen Streifen ueber den ganzen Bildschirm ungueltig.
|
||||
label_set_if_changed(g_readyBandLbl, txt);
|
||||
label_color_if_changed(g_readyBandLbl, fg);
|
||||
if (lv_color_to_u32(lv_obj_get_style_bg_color(g_readyBand, LV_PART_MAIN)) != bg) {
|
||||
lv_obj_set_style_bg_color(g_readyBand, lv_color_hex(bg), 0);
|
||||
lv_obj_set_style_bg_opa(g_readyBand, LV_OPA_COVER, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
@@ -3973,12 +4162,14 @@ static void dash_brew_mode(bool on) {
|
||||
if (on == g_dashBrewMode) return; // nur bei echtem Wechsel neu anordnen
|
||||
g_dashBrewMode = on;
|
||||
if (!g_tempRow || !g_infoRow) return;
|
||||
lv_obj_set_flex_grow(g_tempRow, on ? 1 : 3);
|
||||
lv_obj_set_flex_grow(g_infoRow, on ? 3 : 2);
|
||||
// Die Schrift von Shot-Timer und Waage bleibt unveraendert. Frueher wechselte sie
|
||||
// waehrend des Bezugs auf den grossen fetten Schnitt - das wirkte gegenueber dem
|
||||
// restlichen Dashboard zu laut. Der Bereich bekommt weiterhin mehr Platz, die Zahlen
|
||||
// stehen dadurch freier, aber in derselben Schrift wie sonst auch.
|
||||
// Die Zeilenhoehen bleiben unveraendert. Frueher bekam die untere Zeile waehrend des
|
||||
// Bezugs deutlich mehr Platz - die kleinen Kacheln wurden dadurch enorm hoch und das
|
||||
// Dashboard sprang bei jedem Bezugsbeginn sichtbar um. Der Bezug hebt sich jetzt allein
|
||||
// ueber seine Inhalte hervor, nicht ueber die Groesse.
|
||||
(void)on;
|
||||
// Die Schrift von Shot-Timer und Waage bleibt ebenfalls unveraendert. Frueher wechselte
|
||||
// sie waehrend des Bezugs auf den grossen fetten Schnitt - das wirkte gegenueber dem
|
||||
// restlichen Dashboard zu laut.
|
||||
}
|
||||
|
||||
static void dash_brew_mode_tick(const MachineState& st) {
|
||||
@@ -4043,7 +4234,7 @@ void ui_update(const MachineState& st) {
|
||||
|
||||
// WLAN-Symbol
|
||||
bool wifiOk = st.wifiConnected && !st.apMode;
|
||||
if (g_wifiIcon) lv_obj_set_style_text_color(g_wifiIcon, wifiOk ? COL_OK : (st.apMode ? COL_WARN : COL_TEXT_MUT), 0);
|
||||
label_color_if_changed(g_wifiIcon, wifiOk ? COL_OK : (st.apMode ? COL_WARN : COL_TEXT_MUT));
|
||||
|
||||
// Uhrzeit. Angezeigt wird die der Hauptplatine; faellt sie voruebergehend aus, zaehlt
|
||||
// der P4 die zuletzt bekannte Zeit selbst weiter (siehe clock_text).
|
||||
@@ -4334,43 +4525,43 @@ void ui_update(const MachineState& st) {
|
||||
// Dashboard - Temperaturkarten (im Fehlerfall Warnsymbol + Klartext statt Zahl, wie OLED)
|
||||
if (lblTempW) {
|
||||
if (st.wasserSafetyShutdown || st.wasserSensorError) {
|
||||
lv_label_set_text(lblTempW, LV_SYMBOL_WARNING);
|
||||
lv_obj_set_style_text_color(lblTempW, COL_DANGER, 0);
|
||||
lv_label_set_text(lblSetW, st.wasserSafetyShutdown ? "Sicherheitsabsch." : "Sensorfehler!");
|
||||
lv_obj_set_style_text_color(lblSetW, COL_DANGER, 0);
|
||||
label_set_if_changed(lblTempW, LV_SYMBOL_WARNING);
|
||||
label_color_if_changed(lblTempW, COL_DANGER);
|
||||
label_set_if_changed(lblSetW, st.wasserSafetyShutdown ? "Sicherheitsabsch." : "Sensorfehler!");
|
||||
label_color_if_changed(lblSetW, COL_DANGER);
|
||||
temp_progress_set(barDutyW, arcTempW, bulbTempW, 0, COL_DANGER);
|
||||
} else {
|
||||
lv_label_set_text(lblTempW, tempStr(st.tempW, 1).c_str());
|
||||
label_set_if_changed(lblTempW, tempStr(st.tempW, 1).c_str());
|
||||
if (st.cxActive) {
|
||||
// Cold Extraction: der Sollwert ist bedeutungslos, es wird nicht geheizt.
|
||||
// Statt eines Zielbands, das nie erreicht wird, den Grund anzeigen.
|
||||
lv_obj_set_style_text_color(lblTempW, temp_value_color(lv_color_hex(0x1976d2)), 0);
|
||||
label_color_if_changed(lblTempW, temp_value_color(lv_color_hex(0x1976d2)));
|
||||
label_set_if_changed(lblSetW, "Cold Extraction - Heizen aus");
|
||||
lv_obj_set_style_text_color(lblSetW, lv_color_hex(0x1976d2), 0);
|
||||
label_color_if_changed(lblSetW, lv_color_hex(0x1976d2));
|
||||
temp_progress_set(barDutyW, arcTempW, bulbTempW, 0, lv_color_hex(0x1976d2));
|
||||
} else {
|
||||
// Ist-Wert faerbt sich weich Richtung Soll (Blau -> Gold -> Gruen im Zielband)
|
||||
lv_color_t colW = temp_state_color(st.tempW, st.setW);
|
||||
lv_obj_set_style_text_color(lblTempW, temp_value_color(colW), 0);
|
||||
lv_label_set_text(lblSetW, ("Soll " + tempStr(st.setW, 1)).c_str());
|
||||
lv_obj_set_style_text_color(lblSetW, COL_TEXT_DIM, 0);
|
||||
label_color_if_changed(lblTempW, temp_value_color(colW));
|
||||
label_set_if_changed(lblSetW, ("Soll " + tempStr(st.setW, 1)).c_str());
|
||||
label_color_if_changed(lblSetW, COL_TEXT_DIM);
|
||||
// Fortschritt = Ist/Soll in %, gedeckelt auf 100 (Ist >= Soll -> voll)
|
||||
int pctW = (st.setW > 0.0f) ? (int)(st.tempW / st.setW * 100.0f + 0.5f) : 0;
|
||||
temp_progress_set(barDutyW, arcTempW, bulbTempW, pctW, colW);
|
||||
}
|
||||
}
|
||||
if (st.dampfSafetyShutdown || st.dampfSensorError) {
|
||||
lv_label_set_text(lblTempD, LV_SYMBOL_WARNING);
|
||||
lv_obj_set_style_text_color(lblTempD, COL_DANGER, 0);
|
||||
lv_label_set_text(lblSetD, st.dampfSafetyShutdown ? "Sicherheitsabsch." : "Sensorfehler!");
|
||||
lv_obj_set_style_text_color(lblSetD, COL_DANGER, 0);
|
||||
label_set_if_changed(lblTempD, LV_SYMBOL_WARNING);
|
||||
label_color_if_changed(lblTempD, COL_DANGER);
|
||||
label_set_if_changed(lblSetD, st.dampfSafetyShutdown ? "Sicherheitsabsch." : "Sensorfehler!");
|
||||
label_color_if_changed(lblSetD, COL_DANGER);
|
||||
temp_progress_set(barDutyD, arcTempD, bulbTempD, 0, COL_DANGER);
|
||||
} else {
|
||||
lv_label_set_text(lblTempD, tempStr(st.tempD, 0).c_str());
|
||||
label_set_if_changed(lblTempD, tempStr(st.tempD, 0).c_str());
|
||||
lv_color_t colD = temp_state_color(st.tempD, st.setD);
|
||||
lv_obj_set_style_text_color(lblTempD, temp_value_color(colD), 0);
|
||||
lv_label_set_text(lblSetD, ("Soll " + tempStr(st.setD, 0)).c_str());
|
||||
lv_obj_set_style_text_color(lblSetD, COL_TEXT_DIM, 0);
|
||||
label_color_if_changed(lblTempD, temp_value_color(colD));
|
||||
label_set_if_changed(lblSetD, ("Soll " + tempStr(st.setD, 0)).c_str());
|
||||
label_color_if_changed(lblSetD, COL_TEXT_DIM);
|
||||
int pctD = (st.setD > 0.0f) ? (int)(st.tempD / st.setD * 100.0f + 0.5f) : 0;
|
||||
temp_progress_set(barDutyD, arcTempD, bulbTempD, pctD, colD);
|
||||
}
|
||||
@@ -4519,12 +4710,12 @@ void ui_update(const MachineState& st) {
|
||||
float wDisp = st.weight;
|
||||
if (wDisp > -0.05f && wDisp <= 0.0f) wDisp = 0.0f;
|
||||
if (!st.scaleEnabled) {
|
||||
lv_label_set_text(lblBezug, "--");
|
||||
label_set_if_changed(lblBezug, "--");
|
||||
} else if (bbwShot) {
|
||||
// Waehrend des Bezugs mit Brew-by-Weight: Ist oben, Ziel darunter (zweizeilig)
|
||||
lv_label_set_text_fmt(lblBezug, "%.1f g\n/ %.1f g", wDisp, shotTarget);
|
||||
label_fmt_if_changed(lblBezug, "%.1f g\n/ %.1f g", wDisp, shotTarget);
|
||||
} else {
|
||||
lv_label_set_text_fmt(lblBezug, "%.1f g", wDisp);
|
||||
label_fmt_if_changed(lblBezug, "%.1f g", wDisp);
|
||||
}
|
||||
// Fortschrittsbalken Gewicht/Ziel (nur waehrend BBW-Bezug)
|
||||
if (g_bbwBar) {
|
||||
|
||||
Reference in New Issue
Block a user