Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
785f64331d | ||
|
|
40aabe48bc | ||
|
|
ca3a9c1264 | ||
|
|
bcd9ecf0c8 | ||
|
|
e5c61d42d4 | ||
|
|
d77b0795ea |
@@ -1,3 +1,44 @@
|
||||
Version 1.8.1:
|
||||
- Die Bezugsanzeige ist da, und zwar für alle vier Darstellungen gemeinsam: Sobald ein
|
||||
Bezug oder Dampfbezug läuft, schrumpft der Temperaturbereich und die untere Zeile wächst.
|
||||
Shot-Timer und Gewicht werden dabei auf 96 Pixel vergrößert - während eines Bezugs zählen
|
||||
Zeit und Gewicht, die Kesseltemperaturen sind dann Nebensache.
|
||||
- Es gibt keine zweite Ansicht: Die Seite verschiebt nur das Gewicht zwischen ihren beiden
|
||||
Bereichen. Damit bleibt alles an seinem Platz, und es gibt nichts doppelt zu pflegen.
|
||||
- Der Wechsel hält nach dem Bezug noch vier Sekunden an. Ohne dieses Nachhalten würde die
|
||||
Seite bei jeder kurzen Unterbrechung hin- und herspringen - das wäre unruhiger als gar
|
||||
kein Wechsel.
|
||||
|
||||
Version 1.8.0:
|
||||
- Das Dashboard hat vier neue Darstellungen, die die bisherigen fünf ersetzen. Sie sind
|
||||
keine Varianten desselben Bildes, sondern vier Antworten auf die Frage, was die große
|
||||
Fläche des 7-Zöllers leisten soll:
|
||||
* Gewichtet - Wasser bekommt zwei Drittel der Fläche, Dampf ein Drittel. Beim Espresso
|
||||
zählt die Wassertemperatur; die Asymmetrie ist die Aussage.
|
||||
* Verlauf - unter jeder Temperatur eine flache Kurve der letzten Minute. Die eigentliche
|
||||
Frage an eine PID-Regelung ist nicht „wie warm", sondern „hält sie" - und das kann eine
|
||||
Zahl grundsätzlich nicht zeigen. Der Ausschnitt hängt am Sollwert, damit die Abweichung
|
||||
sichtbar wird statt in der Skala unterzugehen.
|
||||
* Flächen - keine Kartenkanten, zwei Felder mit einem Hauch Helligkeitsunterschied.
|
||||
* Band - ein farbiges Band über die volle Breite sagt den Zustand, bevor eine Zahl
|
||||
gelesen wird: bereit, heizt, Bezug, Cold Extraction oder Standby. Neue Vorgabe.
|
||||
- Dafür gibt es zwei neue Schriftgrade (96 und 140 Pixel). Sie enthalten nur Ziffern,
|
||||
Komma, Punkt, Minus und Gradzeichen - mit vollem Zeichensatz wären sie um ein Vielfaches
|
||||
größer, ohne etwas beizutragen. Die größte Textschrift hatte bisher 48 Pixel, was für die
|
||||
großen Zahlen nicht reichte.
|
||||
- Ältere Stände haben in den Einstellungen noch die Nummer einer der früheren Darstellungen
|
||||
gespeichert; liegt sie außerhalb, fällt sie auf die Vorgabe zurück.
|
||||
- Der Aufbau der Bezugsanzeige - untere Zeile wechselt während eines Bezugs auf große
|
||||
Timer- und Gewichtsanzeige - folgt als nächster Schritt.
|
||||
|
||||
Version 1.7.3:
|
||||
- Die Schriftgröße steht jetzt auf der Info-Seite im Abschnitt „Darstellung", zusammen mit
|
||||
der Wahl der Temperaturanzeige und dem Live-Bezugsschirm. Dort gehört sie hin: Es ist
|
||||
eine Einstellung dieses Displays, keine Wartungsaufgabe.
|
||||
- Die Seite Reinigung & Wartung hat damit wieder vier Karten in zwei Spalten.
|
||||
- Die Auswahl selbst ist unverändert: drei Stufen, Neustart nach der Auswahl.
|
||||
- Sie steht auf allen Panels zur Verfügung, nicht nur auf dem 7-Zöller.
|
||||
|
||||
Version 1.7.2:
|
||||
- Die Schriftgröße lässt sich jetzt einstellen: Klein, Mittel oder Groß, zu finden auf der
|
||||
Seite Reinigung & Wartung in der neuen Karte „Darstellung".
|
||||
|
||||
@@ -567,6 +567,8 @@
|
||||
LV_FONT_DECLARE(lv_font_maven_pro_28) \
|
||||
LV_FONT_DECLARE(lv_font_maven_pro_40) \
|
||||
LV_FONT_DECLARE(lv_font_maven_pro_48) \
|
||||
LV_FONT_DECLARE(lv_font_maven_pro_96) \
|
||||
LV_FONT_DECLARE(lv_font_maven_pro_140) \
|
||||
LV_FONT_DECLARE(lv_font_clock_240)
|
||||
|
||||
/*Always set a default font*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+256
-310
@@ -166,8 +166,15 @@ static void label_set_if_changed(lv_obj_t* lbl, const char* txt); // Definitio
|
||||
// TD_MINIMAL - rahmenlos, nur grosse Werte mit duenner Ist/Soll-Linie
|
||||
// TD_NEO - Soft-3D/Neumorph: Flaeche wirkt aus dem Hintergrund herausgedrueckt
|
||||
// TD_THERMO - vertikale Thermometer-Saeulen mit Kolben und Glanzstreifen
|
||||
enum TempDesign { TD_CARDS = 0, TD_GAUGE, TD_MINIMAL, TD_NEO, TD_THERMO, TD_DESIGN_COUNT };
|
||||
static uint8_t g_tempDesign = TD_GAUGE;
|
||||
enum TempDesign { TD_GEWICHTET = 0, TD_VERLAUF, TD_FLAECHEN, TD_BAND, TD_DESIGN_COUNT };
|
||||
static uint8_t g_tempDesign = TD_BAND;
|
||||
#define DASH_SPARK_POINTS 60 // eine Minute Verlauf, ein Punkt je Sekunde
|
||||
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;
|
||||
static lv_chart_series_t* g_sparkSerD = nullptr;
|
||||
static lv_obj_t* g_readyBand = nullptr; // Zustandsband der Darstellung TD_BAND
|
||||
static lv_obj_t* g_readyBandLbl = nullptr;
|
||||
static lv_obj_t* g_tempRow = nullptr; // Container; Inhalt wird je Design (neu) aufgebaut
|
||||
static lv_obj_t* lblTempW; static lv_obj_t* lblSetW; static lv_obj_t* barDutyW; // barDuty*: lv_bar (Karten/Minimal/Neo/Thermo-Saeule)
|
||||
static lv_obj_t* lblTempD; static lv_obj_t* lblSetD; static lv_obj_t* barDutyD;
|
||||
@@ -182,6 +189,10 @@ static lv_obj_t* g_profChip = nullptr;
|
||||
static lv_obj_t* g_profPicker = nullptr; // Schnellwahl-Overlay (Vollbild-Abdunkelung)
|
||||
static lv_obj_t* g_profPickerList = nullptr; // Button-Liste im Overlay
|
||||
static lv_obj_t* g_profPickerInfo = nullptr; // "Lade Profile..."-Hinweis im Overlay
|
||||
static lv_obj_t* g_infoRow = nullptr; // untere Zeile; waechst waehrend eines Bezugs
|
||||
static bool g_dashBrewMode = false;
|
||||
static const lv_font_t* g_shotFontNormal = nullptr;
|
||||
static const lv_font_t* g_bezugFontNormal = nullptr;
|
||||
static lv_obj_t* cellShot; static lv_obj_t* lblShotTimer; static lv_obj_t* g_bbtBar = nullptr;
|
||||
static lv_obj_t* cellSteam; static lv_obj_t* lblSteamTimer; static lv_obj_t* g_sbtBar = nullptr;
|
||||
static lv_obj_t* cellBezug; static lv_obj_t* lblBezug; static lv_obj_t* g_bbwBar = nullptr;
|
||||
@@ -798,7 +809,7 @@ static void temp_progress_set(lv_obj_t* bar, lv_obj_t* arc, lv_obj_t* bulb, int
|
||||
if (pct > 100) pct = 100; else if (pct < 0) pct = 0;
|
||||
if (bar) {
|
||||
lv_bar_set_value(bar, pct, LV_ANIM_OFF);
|
||||
if (g_tempDesign != TD_CARDS) lv_obj_set_style_bg_color(bar, col, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_bg_color(bar, col, LV_PART_INDICATOR);
|
||||
}
|
||||
if (arc) {
|
||||
lv_arc_set_value(arc, pct);
|
||||
@@ -806,298 +817,91 @@ static void temp_progress_set(lv_obj_t* bar, lv_obj_t* arc, lv_obj_t* bulb, int
|
||||
}
|
||||
if (bulb) lv_obj_set_style_bg_color(bulb, col, 0);
|
||||
}
|
||||
static void tempCard(lv_obj_t* parent, const char* title, lv_color_t accent,
|
||||
lv_obj_t** big, lv_obj_t** setp, lv_obj_t** bar) {
|
||||
lv_obj_t* card = th_card(parent);
|
||||
lv_obj_set_size(card, LV_PCT(49), LV_PCT(100));
|
||||
lv_obj_set_flex_flow(card, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(card, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_clear_flag(card, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(card, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Temperatur-Seite
|
||||
lv_obj_add_event_cb(card, temp_card_cb, LV_EVENT_CLICKED, nullptr);
|
||||
lv_obj_t* t = lv_label_create(card);
|
||||
lv_label_set_text(t, title);
|
||||
lv_obj_set_style_text_color(t, accent, 0);
|
||||
lv_obj_set_style_text_font(t, font_text(), 0);
|
||||
*big = lv_label_create(card);
|
||||
lv_label_set_text(*big, "--.-");
|
||||
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*big, &lv_font_maven_pro_48, 0);
|
||||
*setp = lv_label_create(card);
|
||||
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);
|
||||
*bar = lv_bar_create(card);
|
||||
lv_obj_set_size(*bar, LV_PCT(92), 12);
|
||||
lv_obj_set_style_bg_color(*bar, lv_color_hex(0x3a3a3a), 0); // sichtbarer Track (auch bei 0 %)
|
||||
lv_obj_set_style_bg_opa(*bar, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_color(*bar, COL_BORDER, 0);
|
||||
lv_obj_set_style_border_width(*bar, 1, 0);
|
||||
lv_obj_set_style_radius(*bar, 6, 0);
|
||||
lv_obj_set_style_bg_color(*bar, accent, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_radius(*bar, 6, LV_PART_INDICATOR);
|
||||
lv_bar_set_range(*bar, 0, 100);
|
||||
lv_bar_set_value(*bar, 0, LV_ANIM_OFF);
|
||||
}
|
||||
// Rundinstrument im Manometer-Look (Design TD_GAUGE): freistehend ohne Kartenrahmen.
|
||||
// Leichte 3D-Wirkung ueber einen "Metall"-Bezel (vertikaler Verlauf hell -> dunkel) mit
|
||||
// weichem Schlagschatten und ein leicht aufgehelltes Zifferblatt darunter. Der 270-Grad-
|
||||
// Bogen zeigt Ist/Soll in % und faerbt sich mit der Zustandsfarbe des Ist-Werts.
|
||||
static void tempGauge(lv_obj_t* parent, const char* title, lv_color_t accent,
|
||||
lv_obj_t** big, lv_obj_t** setp, lv_obj_t** arc) {
|
||||
lv_obj_t* holder = lv_obj_create(parent);
|
||||
lv_obj_set_size(holder, LV_PCT(49), LV_PCT(100));
|
||||
lv_obj_set_style_bg_opa(holder, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(holder, 0, 0);
|
||||
lv_obj_set_style_pad_all(holder, 0, 0);
|
||||
lv_obj_clear_flag(holder, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(holder, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Temperatur-Seite
|
||||
lv_obj_add_event_cb(holder, temp_card_cb, LV_EVENT_CLICKED, nullptr);
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Temperaturbereich des Dashboards - vier Darstellungen
|
||||
//
|
||||
// Gemeinsam ist allen: zwei Kessel, die Zahl ist das Erste, was man sieht. Unterschiedlich
|
||||
// ist, was die Flaeche zusaetzlich leistet.
|
||||
//
|
||||
// Die grossen Zahlen brauchen Schriftgrade, die es vorher nicht gab (96 und 140 Pixel).
|
||||
// Diese beiden Schriften enthalten nur Ziffern, Komma, Punkt, Minus und Gradzeichen - mit
|
||||
// vollem Zeichensatz waeren sie um ein Vielfaches groesser, ohne etwas beizutragen.
|
||||
// ------------------------------------------------------------------------------------
|
||||
|
||||
// Bezel-Ring: Verlauf von hell (oben) nach dunkel (unten) + Schatten = Metall-Optik
|
||||
lv_obj_t* bezel = lv_obj_create(holder);
|
||||
lv_obj_set_size(bezel, 188, 188);
|
||||
lv_obj_center(bezel);
|
||||
lv_obj_set_style_radius(bezel, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_bg_color(bezel, lv_color_hex(0x5c5c5c), 0);
|
||||
lv_obj_set_style_bg_grad_color(bezel, lv_color_hex(0x141414), 0);
|
||||
lv_obj_set_style_bg_grad_dir(bezel, LV_GRAD_DIR_VER, 0);
|
||||
lv_obj_set_style_border_width(bezel, 0, 0);
|
||||
lv_obj_set_style_pad_all(bezel, 0, 0);
|
||||
lv_obj_set_style_shadow_width(bezel, 16, 0);
|
||||
lv_obj_set_style_shadow_offset_y(bezel, 5, 0);
|
||||
lv_obj_set_style_shadow_color(bezel, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_shadow_opa(bezel, LV_OPA_60, 0);
|
||||
lv_obj_clear_flag(bezel, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(bezel, LV_OBJ_FLAG_CLICKABLE); // Tipp faellt zum Holder durch
|
||||
// Ein Kesselfeld. 'grow' verteilt die Breite zwischen den beiden, 'valueFont' bestimmt die
|
||||
// Groesse der Zahl, 'flat' laesst den Kartenrahmen weg und faerbt stattdessen die Flaeche.
|
||||
static lv_obj_t* tempField(lv_obj_t* parent, const char* title, lv_color_t accent,
|
||||
lv_obj_t** big, lv_obj_t** setp, lv_obj_t** bar,
|
||||
uint8_t grow, const lv_font_t* valueFont,
|
||||
bool flat, uint32_t flatBg) {
|
||||
lv_obj_t* c;
|
||||
if (flat) {
|
||||
c = lv_obj_create(parent);
|
||||
lv_obj_set_style_bg_color(c, lv_color_hex(flatBg), 0);
|
||||
lv_obj_set_style_bg_opa(c, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(c, 0, 0);
|
||||
lv_obj_set_style_radius(c, 0, 0);
|
||||
lv_obj_set_style_pad_all(c, 14, 0);
|
||||
} else {
|
||||
c = th_card(parent);
|
||||
lv_obj_set_style_pad_all(c, 12, 0);
|
||||
}
|
||||
lv_obj_set_height(c, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(c, grow);
|
||||
lv_obj_set_flex_flow(c, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(c, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_clear_flag(c, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(c, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Temperatur-Seite
|
||||
lv_obj_add_event_cb(c, temp_card_cb, LV_EVENT_CLICKED, nullptr);
|
||||
|
||||
// Zifferblatt: leicht "vertieft" (Verlauf dunkel oben -> etwas heller unten)
|
||||
lv_obj_t* face = lv_obj_create(bezel);
|
||||
lv_obj_set_size(face, 174, 174);
|
||||
lv_obj_center(face);
|
||||
lv_obj_set_style_radius(face, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_bg_color(face, lv_color_hex(0x0c0c0c), 0);
|
||||
lv_obj_set_style_bg_grad_color(face, lv_color_hex(0x232323), 0);
|
||||
lv_obj_set_style_bg_grad_dir(face, LV_GRAD_DIR_VER, 0);
|
||||
lv_obj_set_style_border_width(face, 0, 0);
|
||||
lv_obj_set_style_pad_all(face, 0, 0);
|
||||
lv_obj_clear_flag(face, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(face, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
// 270-Grad-Bogen (Luecke unten): reine Anzeige, kein Griff, nicht bedienbar
|
||||
*arc = lv_arc_create(face);
|
||||
lv_obj_set_size(*arc, 158, 158);
|
||||
lv_obj_center(*arc);
|
||||
lv_arc_set_rotation(*arc, 135);
|
||||
lv_arc_set_bg_angles(*arc, 0, 270);
|
||||
lv_arc_set_range(*arc, 0, 100);
|
||||
lv_arc_set_value(*arc, 0);
|
||||
lv_obj_remove_style(*arc, nullptr, LV_PART_KNOB);
|
||||
lv_obj_clear_flag(*arc, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_set_style_arc_width(*arc, 12, LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_color(*arc, lv_color_hex(0x2e2e2e), LV_PART_MAIN);
|
||||
lv_obj_set_style_arc_width(*arc, 12, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_color(*arc, accent, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_arc_rounded(*arc, true, LV_PART_INDICATOR);
|
||||
|
||||
lv_obj_t* t = lv_label_create(face);
|
||||
lv_obj_t* t = lv_label_create(c);
|
||||
lv_label_set_text(t, title);
|
||||
lv_obj_set_style_text_color(t, accent, 0);
|
||||
lv_obj_set_style_text_font(t, font_small(), 0);
|
||||
lv_obj_align(t, LV_ALIGN_CENTER, 0, -48);
|
||||
*big = lv_label_create(face);
|
||||
|
||||
*big = lv_label_create(c);
|
||||
lv_label_set_text(*big, "--.-");
|
||||
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*big, &lv_font_maven_pro_40, 0);
|
||||
lv_obj_align(*big, LV_ALIGN_CENTER, 0, -2);
|
||||
// Soll-Wert sitzt in der Bogen-Luecke unten (dort ist die volle Breite frei)
|
||||
*setp = lv_label_create(face);
|
||||
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_small(), 0);
|
||||
lv_obj_align(*setp, LV_ALIGN_CENTER, 0, 62);
|
||||
}
|
||||
// Minimal-Design (TD_MINIMAL): komplett rahmenlos - nur grosser Ist-Wert in der
|
||||
// Zustandsfarbe, darunter eine duenne Ist/Soll-Linie und der Soll-Wert. Sehr ruhig.
|
||||
static void tempMinimal(lv_obj_t* parent, const char* title, lv_color_t accent,
|
||||
lv_obj_t** big, lv_obj_t** setp, lv_obj_t** bar) {
|
||||
lv_obj_t* holder = lv_obj_create(parent);
|
||||
lv_obj_set_size(holder, LV_PCT(49), LV_PCT(100));
|
||||
lv_obj_set_style_bg_opa(holder, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(holder, 0, 0);
|
||||
lv_obj_set_style_pad_all(holder, 0, 0);
|
||||
lv_obj_set_style_pad_row(holder, 10, 0);
|
||||
lv_obj_set_flex_flow(holder, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(holder, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_clear_flag(holder, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(holder, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Temperatur-Seite
|
||||
lv_obj_add_event_cb(holder, temp_card_cb, LV_EVENT_CLICKED, nullptr);
|
||||
lv_obj_t* t = lv_label_create(holder);
|
||||
lv_label_set_text(t, title);
|
||||
lv_obj_set_style_text_color(t, accent, 0);
|
||||
lv_obj_set_style_text_font(t, font_text(), 0);
|
||||
*big = lv_label_create(holder);
|
||||
lv_label_set_text(*big, "--.-");
|
||||
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*big, &lv_font_maven_pro_48, 0);
|
||||
*bar = lv_bar_create(holder); // duenne Ist/Soll-Linie
|
||||
lv_obj_set_size(*bar, LV_PCT(64), 4);
|
||||
lv_obj_set_style_bg_color(*bar, lv_color_hex(0x2a2a2a), 0);
|
||||
lv_obj_set_style_bg_opa(*bar, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(*bar, 0, 0);
|
||||
lv_obj_set_style_radius(*bar, 2, 0);
|
||||
lv_obj_set_style_bg_color(*bar, accent, LV_PART_INDICATOR); // folgt spaeter der Zustandsfarbe
|
||||
lv_obj_set_style_radius(*bar, 2, LV_PART_INDICATOR);
|
||||
lv_bar_set_range(*bar, 0, 100);
|
||||
lv_bar_set_value(*bar, 0, LV_ANIM_OFF);
|
||||
*setp = lv_label_create(holder);
|
||||
lv_obj_set_style_text_font(*big, valueFont, 0);
|
||||
|
||||
*setp = lv_label_create(c);
|
||||
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);
|
||||
}
|
||||
// Soft-3D/Neumorph (TD_NEO): Flaeche fast im Hintergrundton, wirkt herausgedrueckt.
|
||||
// LVGL kann nur einen Schatten je Objekt, daher zwei verschachtelte Objekte:
|
||||
// aussen dunkler Schatten unten rechts, innen heller "Lichtschein" oben links.
|
||||
static void tempNeo(lv_obj_t* parent, const char* title, lv_color_t accent,
|
||||
lv_obj_t** big, lv_obj_t** setp, lv_obj_t** bar) {
|
||||
lv_obj_t* shell = lv_obj_create(parent);
|
||||
lv_obj_set_size(shell, LV_PCT(48), LV_PCT(100));
|
||||
lv_obj_set_style_radius(shell, 20, 0);
|
||||
lv_obj_set_style_bg_color(shell, lv_color_hex(0x171717), 0);
|
||||
lv_obj_set_style_bg_opa(shell, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(shell, 0, 0);
|
||||
lv_obj_set_style_pad_all(shell, 0, 0);
|
||||
lv_obj_set_style_shadow_width(shell, 14, 0);
|
||||
lv_obj_set_style_shadow_offset_x(shell, 6, 0);
|
||||
lv_obj_set_style_shadow_offset_y(shell, 6, 0);
|
||||
lv_obj_set_style_shadow_color(shell, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_shadow_opa(shell, LV_OPA_70, 0);
|
||||
lv_obj_clear_flag(shell, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(shell, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Temperatur-Seite
|
||||
lv_obj_add_event_cb(shell, temp_card_cb, LV_EVENT_CLICKED, nullptr);
|
||||
|
||||
lv_obj_t* inner = lv_obj_create(shell);
|
||||
lv_obj_set_size(inner, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_radius(inner, 20, 0);
|
||||
lv_obj_set_style_bg_color(inner, lv_color_hex(0x1e1e1e), 0); // leicht gewoelbt: oben etwas heller
|
||||
lv_obj_set_style_bg_grad_color(inner, lv_color_hex(0x121212), 0);
|
||||
lv_obj_set_style_bg_grad_dir(inner, LV_GRAD_DIR_VER, 0);
|
||||
lv_obj_set_style_border_width(inner, 0, 0);
|
||||
lv_obj_set_style_shadow_width(inner, 14, 0);
|
||||
lv_obj_set_style_shadow_offset_x(inner, -6, 0);
|
||||
lv_obj_set_style_shadow_offset_y(inner, -6, 0);
|
||||
lv_obj_set_style_shadow_color(inner, lv_color_hex(0x3c3c3c), 0);
|
||||
lv_obj_set_style_shadow_opa(inner, LV_OPA_50, 0);
|
||||
lv_obj_set_style_pad_row(inner, 8, 0);
|
||||
lv_obj_set_flex_flow(inner, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(inner, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_clear_flag(inner, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(inner, LV_OBJ_FLAG_CLICKABLE); // Tipp faellt zur Shell durch
|
||||
|
||||
lv_obj_t* t = lv_label_create(inner);
|
||||
lv_label_set_text(t, title);
|
||||
lv_obj_set_style_text_color(t, accent, 0);
|
||||
lv_obj_set_style_text_font(t, font_text(), 0);
|
||||
*big = lv_label_create(inner);
|
||||
lv_label_set_text(*big, "--.-");
|
||||
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*big, &lv_font_maven_pro_48, 0);
|
||||
*setp = lv_label_create(inner);
|
||||
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);
|
||||
*bar = lv_bar_create(inner); // "eingelassener" Balken: Track dunkler als Flaeche
|
||||
lv_obj_set_size(*bar, LV_PCT(78), 10);
|
||||
lv_obj_set_style_bg_color(*bar, lv_color_hex(0x0a0a0a), 0);
|
||||
*bar = lv_bar_create(c);
|
||||
lv_obj_set_size(*bar, LV_PCT(92), 8);
|
||||
lv_obj_set_style_bg_color(*bar, lv_color_hex(0x2c2c2c), 0);
|
||||
lv_obj_set_style_bg_opa(*bar, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(*bar, 0, 0);
|
||||
lv_obj_set_style_radius(*bar, 5, 0);
|
||||
lv_obj_set_style_bg_color(*bar, accent, LV_PART_INDICATOR); // folgt spaeter der Zustandsfarbe
|
||||
lv_obj_set_style_radius(*bar, 5, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_radius(*bar, 4, 0);
|
||||
lv_obj_set_style_bg_color(*bar, accent, LV_PART_INDICATOR);
|
||||
lv_obj_set_style_radius(*bar, 4, LV_PART_INDICATOR);
|
||||
lv_bar_set_range(*bar, 0, 100);
|
||||
lv_bar_set_value(*bar, 0, LV_ANIM_OFF);
|
||||
return c;
|
||||
}
|
||||
// Thermometer-Saeulen (TD_THERMO): vertikale Saeule (lv_bar waechst bei Hochformat von
|
||||
// unten), Glanzstreifen als Glas-Effekt, runder Kolben unten - alles rahmenlos.
|
||||
static void tempThermo(lv_obj_t* parent, const char* title, lv_color_t accent,
|
||||
lv_obj_t** big, lv_obj_t** setp, lv_obj_t** bar, lv_obj_t** bulb) {
|
||||
lv_obj_t* holder = lv_obj_create(parent);
|
||||
lv_obj_set_size(holder, LV_PCT(49), LV_PCT(100));
|
||||
lv_obj_set_style_bg_opa(holder, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(holder, 0, 0);
|
||||
lv_obj_set_style_pad_all(holder, 0, 0);
|
||||
lv_obj_set_style_pad_column(holder, 14, 0);
|
||||
lv_obj_set_flex_flow(holder, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_set_flex_align(holder, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_clear_flag(holder, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_add_flag(holder, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Temperatur-Seite
|
||||
lv_obj_add_event_cb(holder, temp_card_cb, LV_EVENT_CLICKED, nullptr);
|
||||
|
||||
lv_obj_t* th = lv_obj_create(holder); // Saeule + Kolben (feste Groesse)
|
||||
lv_obj_set_size(th, 48, 190);
|
||||
lv_obj_set_style_bg_opa(th, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(th, 0, 0);
|
||||
lv_obj_set_style_pad_all(th, 0, 0);
|
||||
lv_obj_clear_flag(th, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(th, LV_OBJ_FLAG_CLICKABLE);
|
||||
*bar = lv_bar_create(th); // hochkant -> fuellt sich von unten
|
||||
lv_obj_set_size(*bar, 20, 158);
|
||||
lv_obj_align(*bar, LV_ALIGN_TOP_MID, 0, 0);
|
||||
lv_obj_set_style_bg_color(*bar, lv_color_hex(0x262626), 0);
|
||||
lv_obj_set_style_bg_opa(*bar, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(*bar, 0, 0);
|
||||
lv_obj_set_style_radius(*bar, 10, 0);
|
||||
lv_obj_set_style_bg_color(*bar, accent, LV_PART_INDICATOR); // folgt spaeter der Zustandsfarbe
|
||||
lv_obj_set_style_radius(*bar, 10, LV_PART_INDICATOR);
|
||||
lv_bar_set_range(*bar, 0, 100);
|
||||
lv_bar_set_value(*bar, 0, LV_ANIM_OFF);
|
||||
lv_obj_t* gloss = lv_obj_create(th); // Glanzstreifen (Glas-Effekt)
|
||||
lv_obj_set_size(gloss, 4, 138);
|
||||
lv_obj_align(gloss, LV_ALIGN_TOP_MID, -5, 8);
|
||||
lv_obj_set_style_bg_color(gloss, lv_color_hex(0xffffff), 0);
|
||||
lv_obj_set_style_bg_opa(gloss, LV_OPA_20, 0);
|
||||
lv_obj_set_style_border_width(gloss, 0, 0);
|
||||
lv_obj_set_style_radius(gloss, 2, 0);
|
||||
lv_obj_clear_flag(gloss, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(gloss, LV_OBJ_FLAG_CLICKABLE);
|
||||
*bulb = lv_obj_create(th); // Kolben (ueberlappt die Saeule leicht)
|
||||
lv_obj_set_size(*bulb, 36, 36);
|
||||
lv_obj_align(*bulb, LV_ALIGN_BOTTOM_MID, 0, 0);
|
||||
lv_obj_set_style_radius(*bulb, LV_RADIUS_CIRCLE, 0);
|
||||
lv_obj_set_style_bg_color(*bulb, accent, 0); // folgt spaeter der Zustandsfarbe
|
||||
lv_obj_set_style_bg_opa(*bulb, LV_OPA_COVER, 0);
|
||||
lv_obj_set_style_border_width(*bulb, 0, 0);
|
||||
lv_obj_set_style_shadow_width(*bulb, 10, 0);
|
||||
lv_obj_set_style_shadow_offset_y(*bulb, 3, 0);
|
||||
lv_obj_set_style_shadow_color(*bulb, lv_color_hex(0x000000), 0);
|
||||
lv_obj_set_style_shadow_opa(*bulb, LV_OPA_40, 0);
|
||||
lv_obj_clear_flag(*bulb, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(*bulb, LV_OBJ_FLAG_CLICKABLE);
|
||||
|
||||
lv_obj_t* col = lv_obj_create(holder); // Textspalte neben der Saeule
|
||||
lv_obj_set_size(col, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
|
||||
lv_obj_set_style_bg_opa(col, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(col, 0, 0);
|
||||
lv_obj_set_style_pad_all(col, 0, 0);
|
||||
lv_obj_set_style_pad_row(col, 6, 0);
|
||||
lv_obj_set_flex_flow(col, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(col, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER);
|
||||
lv_obj_clear_flag(col, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_clear_flag(col, LV_OBJ_FLAG_CLICKABLE);
|
||||
lv_obj_t* t = lv_label_create(col);
|
||||
lv_label_set_text(t, title);
|
||||
lv_obj_set_style_text_color(t, accent, 0);
|
||||
lv_obj_set_style_text_font(t, font_text(), 0);
|
||||
*big = lv_label_create(col);
|
||||
lv_label_set_text(*big, "--.-");
|
||||
lv_obj_set_style_text_color(*big, COL_TEXT, 0);
|
||||
lv_obj_set_style_text_font(*big, &lv_font_maven_pro_48, 0);
|
||||
*setp = lv_label_create(col);
|
||||
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);
|
||||
// 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.
|
||||
static lv_obj_t* tempSpark(lv_obj_t* parent, lv_color_t col, lv_chart_series_t** ser) {
|
||||
lv_obj_t* ch = lv_chart_create(parent);
|
||||
lv_obj_set_size(ch, LV_PCT(96), 72);
|
||||
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);
|
||||
lv_obj_set_style_bg_opa(ch, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(ch, 0, 0);
|
||||
lv_obj_set_style_pad_all(ch, 0, 0);
|
||||
lv_obj_set_style_size(ch, 0, 0, LV_PART_INDICATOR); // keine Punktmarkierungen
|
||||
lv_obj_set_style_line_width(ch, 3, LV_PART_ITEMS);
|
||||
lv_obj_clear_flag(ch, LV_OBJ_FLAG_SCROLLABLE);
|
||||
*ser = lv_chart_add_series(ch, col, LV_CHART_AXIS_PRIMARY_Y);
|
||||
return ch;
|
||||
}
|
||||
// Temperaturzeile gemaess aktivem Design (neu) befuellen - auch beim Umschalten zur Laufzeit
|
||||
|
||||
// Temperaturbereich gemaess aktiver Darstellung (neu) aufbauen - auch beim Umschalten
|
||||
static void build_temp_row_content() {
|
||||
if (!g_tempRow) return;
|
||||
lv_obj_clean(g_tempRow);
|
||||
@@ -1105,32 +909,82 @@ static void build_temp_row_content() {
|
||||
lblTempD = lblSetD = barDutyD = nullptr;
|
||||
arcTempW = arcTempD = nullptr;
|
||||
bulbTempW = bulbTempD = nullptr;
|
||||
// Nur Soft-3D braucht Innenabstand, damit die weichen Schatten nicht am Rand abgeschnitten werden
|
||||
lv_obj_set_style_pad_hor(g_tempRow, (g_tempDesign == TD_NEO) ? 12 : 0, 0);
|
||||
lv_obj_set_style_pad_ver(g_tempRow, (g_tempDesign == TD_NEO) ? 12 : 0, 0);
|
||||
g_sparkW = g_sparkD = nullptr;
|
||||
g_sparkSerW = g_sparkSerD = nullptr;
|
||||
g_readyBand = g_readyBandLbl = nullptr;
|
||||
|
||||
const lv_color_t teal = lv_color_hex(0x80cbc4);
|
||||
lv_obj_set_style_pad_all(g_tempRow, 0, 0);
|
||||
lv_obj_set_style_pad_column(g_tempRow, 12, 0);
|
||||
lv_obj_set_style_pad_row(g_tempRow, 10, 0);
|
||||
lv_obj_set_flex_flow(g_tempRow, LV_FLEX_FLOW_ROW);
|
||||
|
||||
switch (g_tempDesign) {
|
||||
case TD_GAUGE:
|
||||
tempGauge(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &arcTempW);
|
||||
tempGauge(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &arcTempD);
|
||||
|
||||
case TD_GEWICHTET: {
|
||||
// Beim Espresso zaehlt die Wassertemperatur; der Dampfkessel ist Nebenwert. Also
|
||||
// zwei Drittel Flaeche fuer Wasser, ein Drittel fuer Dampf - die Asymmetrie ist die
|
||||
// Aussage, nicht ein Versehen.
|
||||
tempField(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW,
|
||||
2, &lv_font_maven_pro_140, false, 0);
|
||||
tempField(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
||||
1, &lv_font_maven_pro_48, false, 0);
|
||||
break;
|
||||
case TD_MINIMAL:
|
||||
tempMinimal(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW);
|
||||
tempMinimal(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD);
|
||||
}
|
||||
|
||||
case TD_VERLAUF: {
|
||||
lv_obj_t* cw = tempField(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW,
|
||||
1, &lv_font_maven_pro_96, false, 0);
|
||||
g_sparkW = tempSpark(cw, COL_OK, &g_sparkSerW);
|
||||
lv_obj_t* cd = tempField(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
||||
1, &lv_font_maven_pro_96, false, 0);
|
||||
g_sparkD = tempSpark(cd, COL_ACCENT, &g_sparkSerD);
|
||||
break;
|
||||
case TD_NEO:
|
||||
tempNeo(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW);
|
||||
tempNeo(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD);
|
||||
}
|
||||
|
||||
case TD_FLAECHEN: {
|
||||
// Keine Kartenkanten: Der Bereich ist in zwei Felder geteilt, getrennt nur durch
|
||||
// einen Hauch Helligkeitsunterschied.
|
||||
tempField(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW,
|
||||
1, &lv_font_maven_pro_140, true, 0x0d0d0d);
|
||||
tempField(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
||||
1, &lv_font_maven_pro_140, true, 0x151515);
|
||||
lv_obj_set_style_pad_column(g_tempRow, 0, 0); // Felder stossen direkt aneinander
|
||||
break;
|
||||
case TD_THERMO:
|
||||
tempThermo(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW, &bulbTempW);
|
||||
tempThermo(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD, &bulbTempD);
|
||||
break;
|
||||
default:
|
||||
tempCard(g_tempRow, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW);
|
||||
tempCard(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD);
|
||||
}
|
||||
|
||||
default: { // TD_BAND
|
||||
// Ein farbiges Band ueber die volle Breite sagt den Zustand, bevor man eine Zahl
|
||||
// liest. Deshalb hier eine Spalte: Band oben, darunter die beiden Kessel.
|
||||
lv_obj_set_flex_flow(g_tempRow, LV_FLEX_FLOW_COLUMN);
|
||||
g_readyBand = lv_obj_create(g_tempRow);
|
||||
lv_obj_set_width(g_readyBand, LV_PCT(100));
|
||||
lv_obj_set_height(g_readyBand, 34);
|
||||
lv_obj_set_style_radius(g_readyBand, 8, 0);
|
||||
lv_obj_set_style_border_width(g_readyBand, 0, 0);
|
||||
lv_obj_set_style_pad_all(g_readyBand, 0, 0);
|
||||
lv_obj_clear_flag(g_readyBand, LV_OBJ_FLAG_SCROLLABLE);
|
||||
g_readyBandLbl = lv_label_create(g_readyBand);
|
||||
lv_obj_set_style_text_font(g_readyBandLbl, font_text(), 0);
|
||||
lv_label_set_text(g_readyBandLbl, "");
|
||||
lv_obj_center(g_readyBandLbl);
|
||||
|
||||
lv_obj_t* inner = lv_obj_create(g_tempRow);
|
||||
lv_obj_set_width(inner, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(inner, 1);
|
||||
lv_obj_set_style_bg_opa(inner, LV_OPA_TRANSP, 0);
|
||||
lv_obj_set_style_border_width(inner, 0, 0);
|
||||
lv_obj_set_style_pad_all(inner, 0, 0);
|
||||
lv_obj_set_style_pad_column(inner, 12, 0);
|
||||
lv_obj_set_flex_flow(inner, LV_FLEX_FLOW_ROW);
|
||||
lv_obj_clear_flag(inner, LV_OBJ_FLAG_SCROLLABLE);
|
||||
tempField(inner, "WASSER", COL_ACCENT, &lblTempW, &lblSetW, &barDutyW,
|
||||
1, &lv_font_maven_pro_96, false, 0);
|
||||
tempField(inner, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
||||
1, &lv_font_maven_pro_96, false, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static lv_obj_t* infoCell(lv_obj_t* parent, const char* title, lv_obj_t** val, lv_color_t accent, lv_obj_t** titleOut = nullptr) {
|
||||
lv_obj_t* card = th_card(parent);
|
||||
@@ -1225,6 +1079,7 @@ static void build_dashboard(lv_obj_t* p) {
|
||||
|
||||
// Info-Zeile: Timer / Bezug / Eco-Countdown / Gehaeuse (teilen sich die Breite)
|
||||
lv_obj_t* ir = lv_obj_create(p);
|
||||
g_infoRow = ir;
|
||||
lv_obj_set_width(ir, LV_PCT(100));
|
||||
lv_obj_set_flex_grow(ir, 2);
|
||||
lv_obj_set_style_bg_opa(ir, LV_OPA_TRANSP, 0); lv_obj_set_style_border_width(ir, 0, 0);
|
||||
@@ -1260,6 +1115,10 @@ static void build_dashboard(lv_obj_t* p) {
|
||||
lv_bar_set_range(g_bbwBar, 0, 100);
|
||||
lv_bar_set_value(g_bbwBar, 0, LV_ANIM_OFF);
|
||||
lv_obj_add_flag(g_bbwBar, LV_OBJ_FLAG_HIDDEN);
|
||||
// Normalschriften merken, damit der Bezugsmodus sie wieder herstellen kann
|
||||
g_shotFontNormal = lv_obj_get_style_text_font(lblShotTimer, LV_PART_MAIN);
|
||||
g_bezugFontNormal = lv_obj_get_style_text_font(lblBezug, LV_PART_MAIN);
|
||||
|
||||
cellFlow = infoCell(ir, "FLOW", &lblFlow, lv_color_hex(0x64b5f6));
|
||||
lv_obj_add_flag(cellFlow, LV_OBJ_FLAG_CLICKABLE); // antippbar -> Brew-Control
|
||||
lv_obj_add_event_cb(cellFlow, brew_cell_cb, LV_EVENT_CLICKED, nullptr);
|
||||
@@ -1578,6 +1437,20 @@ static void chart_duty_btn_cb(lv_event_t*) {
|
||||
else lv_obj_add_flag(g_legDuty, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
lv_chart_set_next_value(g_sparkD, g_sparkSerD, (int32_t)(g_state.tempD * 10.0f));
|
||||
}
|
||||
}
|
||||
static void build_chart(lv_obj_t* p) {
|
||||
lv_obj_clear_flag(p, LV_OBJ_FLAG_SCROLLABLE);
|
||||
@@ -2585,20 +2458,9 @@ static void build_service(lv_obj_t* p) {
|
||||
lv_obj_add_event_cb(cb, cln_open, LV_EVENT_CLICKED, nullptr);
|
||||
|
||||
|
||||
lv_obj_t* cFont = group_card(p, "Darstellung",
|
||||
"Schriftgröße dieses Displays. Wirkt nach einem Neustart, der sofort erfolgt.");
|
||||
lv_obj_t* rowF = row(cFont, nullptr);
|
||||
static const char* FONT_NAMEN[3] = { "Klein", "Mittel", "Groß" };
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
lv_obj_t* fb = (i == g_fontStep) ? th_accent_button(rowF, FONT_NAMEN[i])
|
||||
: th_button(rowF, FONT_NAMEN[i], COL_CARD2, COL_TEXT);
|
||||
lv_obj_add_event_cb(fb, font_pick_cb, LV_EVENT_CLICKED, (void*)(intptr_t)i);
|
||||
}
|
||||
|
||||
page_grid(p, PAGE_COLS_2, PAGE_ROWS_2C);
|
||||
grid_at(cMaint, 0, 0); grid_at(cFlush, 1, 0);
|
||||
grid_at(cLight, 0, 1); grid_at(cCln, 1, 1);
|
||||
grid_at(cFont, 0, 2, 2);
|
||||
#else
|
||||
section_title(p, "Reinigung & Wartung");
|
||||
|
||||
@@ -2972,7 +2834,7 @@ static void info_block(lv_obj_t* card, const char* title, lv_obj_t** valOut, con
|
||||
if (valOut) *valOut = v;
|
||||
}
|
||||
// --- Darstellung: Dashboard-Temperaturdesign umschalten (P4-lokal, in NVS gespeichert) ---
|
||||
static const char* TEMP_DESIGN_NAMES[TD_DESIGN_COUNT] = { "Klassisch", "Instrumente", "Minimal", "Soft-3D", "Thermometer" };
|
||||
static const char* TEMP_DESIGN_NAMES[TD_DESIGN_COUNT] = { "Gewichtet", "Verlauf", "Flächen", "Band" };
|
||||
static void design_btns_refresh() {
|
||||
for (int i = 0; i < TD_DESIGN_COUNT; i++) {
|
||||
if (!g_designBtn[i]) continue;
|
||||
@@ -3016,6 +2878,19 @@ static void build_info(lv_obj_t* p) {
|
||||
lv_obj_add_event_cb(g_designBtn[i], design_btn_cb, LV_EVENT_CLICKED, (void*)(intptr_t)i);
|
||||
}
|
||||
design_btns_refresh();
|
||||
lv_obj_t* fl = lv_label_create(dcard);
|
||||
lv_label_set_text(fl, "Schriftgröße (Neustart des Displays)");
|
||||
lv_obj_set_style_text_color(fl, COL_TEXT_DIM, 0);
|
||||
lv_obj_t* frow = row(dcard, nullptr);
|
||||
lv_obj_set_style_pad_column(frow, 8, 0);
|
||||
static const char* FONT_NAMEN[3] = { "Klein", "Mittel", "Groß" };
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
lv_obj_t* fb = (i == g_fontStep) ? th_accent_button(frow, FONT_NAMEN[i])
|
||||
: th_button(frow, FONT_NAMEN[i], COL_CARD2, COL_TEXT);
|
||||
lv_obj_set_flex_grow(fb, 1);
|
||||
lv_obj_add_event_cb(fb, font_pick_cb, LV_EVENT_CLICKED, (void*)(intptr_t)i);
|
||||
}
|
||||
|
||||
swBrewLive = add_switch(dcard, "Live-Bezugsschirm (Vollbild während des Bezugs)");
|
||||
sw_set(swBrewLive, g_brewLiveEnabled);
|
||||
lv_obj_add_event_cb(swBrewLive, brew_live_sw_cb, LV_EVENT_VALUE_CHANGED, nullptr);
|
||||
@@ -3360,13 +3235,16 @@ void ui_init(ProtocolClient* client) {
|
||||
}
|
||||
|
||||
{ Preferences prefs; prefs.begin("ui", false);
|
||||
g_tempDesign = prefs.getUChar("tempdsgn", TD_GAUGE);
|
||||
// Vorgabe ist jetzt TD_BAND. Aeltere Staende haben hier Werte der frueheren fuenf
|
||||
// Darstellungen stehen - liegt der Wert ausserhalb, faellt er auf die Vorgabe zurueck.
|
||||
g_tempDesign = prefs.getUChar("tempdsgn", TD_BAND);
|
||||
if (g_tempDesign >= TD_DESIGN_COUNT) g_tempDesign = TD_BAND;
|
||||
g_brewLiveEnabled = prefs.getBool("brewlive", true);
|
||||
g_chartWin = prefs.getUChar("chartwin", 0);
|
||||
if (g_chartWin > 3) g_chartWin = 0;
|
||||
g_chartDuty = prefs.getBool("chartduty", false);
|
||||
prefs.end();
|
||||
if (g_tempDesign >= TD_DESIGN_COUNT) g_tempDesign = TD_GAUGE; }
|
||||
}
|
||||
|
||||
font_step_load(); // gewaehlte Schriftgroesse, bevor irgendetwas angelegt wird
|
||||
|
||||
@@ -3763,6 +3641,70 @@ static void appendTuneLive(String& out, const char* kreis, uint32_t elapsedMs,
|
||||
// =====================================================================================
|
||||
// Live-Aktualisierung
|
||||
// =====================================================================================
|
||||
|
||||
// Zustandsband der Darstellung TD_BAND. Es beantwortet die haeufigste Frage - ist sie
|
||||
// bereit? - ohne dass eine Zahl gelesen werden muss.
|
||||
static void ready_band_update(const MachineState& st) {
|
||||
if (!g_readyBand || !g_readyBandLbl) return;
|
||||
const char* txt;
|
||||
uint32_t bg;
|
||||
lv_color_t fg;
|
||||
if (st.standbyActive) {
|
||||
txt = "Standby"; bg = 0x1e1e1e; fg = COL_TEXT_MUT;
|
||||
} else if (st.shotActive) {
|
||||
txt = "Bezug läuft"; bg = 0x3a2a05; fg = COL_ACCENT;
|
||||
} else if (st.cxActive) {
|
||||
txt = "Cold Extraction"; bg = 0x0d2b33; fg = lv_color_hex(0x80cbc4);
|
||||
} else {
|
||||
bool wOk = fabsf(st.tempW - st.setW) <= 1.0f;
|
||||
bool dOk = st.steamHeatDisabled || fabsf(st.tempD - st.setD) <= 3.0f;
|
||||
if (wOk && dOk) { txt = "Bereit — beide Kessel auf Temperatur"; bg = 0x11301a; fg = COL_OK; }
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------
|
||||
// Bezugsanzeige: die untere Zeile wechselt ihren Zustand
|
||||
//
|
||||
// Im Ruhezustand ist der Temperaturbereich das Wichtigste - die haeufigste Frage lautet
|
||||
// "ist sie bereit?". Waehrend eines Bezugs kehrt sich das um: Dann zaehlen Zeit und
|
||||
// Gewicht, und die Kesseltemperaturen sind Nebensache. Statt zweier getrennter Ansichten
|
||||
// verschiebt die Seite nur das Gewicht zwischen ihren beiden Bereichen und vergroessert
|
||||
// die beiden Zahlen, auf die es dann ankommt.
|
||||
//
|
||||
// Der Wechsel haelt nach dem Bezug noch kurz an. Ohne dieses Nachhalten wuerde die Seite
|
||||
// bei jeder kurzen Unterbrechung hin- und herspringen - das waere unruhiger als gar kein
|
||||
// Wechsel.
|
||||
// ------------------------------------------------------------------------------------
|
||||
#define DASH_BREW_HOLD_MS 4000
|
||||
|
||||
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);
|
||||
if (lblShotTimer && g_shotFontNormal)
|
||||
lv_obj_set_style_text_font(lblShotTimer, on ? &lv_font_maven_pro_96 : g_shotFontNormal, 0);
|
||||
if (lblBezug && g_bezugFontNormal)
|
||||
lv_obj_set_style_text_font(lblBezug, on ? &lv_font_maven_pro_96 : g_bezugFontNormal, 0);
|
||||
}
|
||||
|
||||
static void dash_brew_mode_tick(const MachineState& st) {
|
||||
static bool war = false; // schon einmal ein Bezug gesehen?
|
||||
static uint32_t zuletzt = 0;
|
||||
bool aktiv = st.shotActive || st.steamCircuitActive;
|
||||
uint32_t jetzt = lv_tick_get();
|
||||
if (aktiv) { war = true; zuletzt = jetzt; }
|
||||
dash_brew_mode(aktiv || (war && (uint32_t)(jetzt - zuletzt) < DASH_BREW_HOLD_MS));
|
||||
}
|
||||
|
||||
void ui_update(const MachineState& st) {
|
||||
if (!g_uiReady) return;
|
||||
|
||||
@@ -4102,6 +4044,10 @@ void ui_update(const MachineState& st) {
|
||||
int pctD = (st.setD > 0.0f) ? (int)(st.tempD / st.setD * 100.0f + 0.5f) : 0;
|
||||
temp_progress_set(barDutyD, arcTempD, bulbTempD, pctD, colD);
|
||||
}
|
||||
ready_band_update(st);
|
||||
dash_brew_mode_tick(st);
|
||||
if (false) {
|
||||
}
|
||||
}
|
||||
// "BEREIT"-Pille im Header: Wasser im Zielband (und Dampf, sofern er heizt), kein
|
||||
// Fehler/Standby/Eco und kein laufender Aufheiz-Countdown. Mit Hysterese gegen
|
||||
|
||||
Reference in New Issue
Block a user