|
|
@@ -179,6 +179,9 @@ enum TempDesign { TD_GEWICHTET = 0, TD_VERLAUF, TD_FLAECHEN, TD_BAND, TD_DESIGN_
|
|
|
|
static uint8_t g_tempDesign = TD_BAND;
|
|
|
|
static uint8_t g_tempDesign = TD_BAND;
|
|
|
|
static bool g_tempColored = false; // Temperaturzahl in der Zustandsfarbe statt weiss
|
|
|
|
static bool g_tempColored = false; // Temperaturzahl in der Zustandsfarbe statt weiss
|
|
|
|
#define DASH_SPARK_POINTS 60 // eine Minute Verlauf, ein Punkt je Sekunde
|
|
|
|
#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_sparkW = nullptr; // Verlaufskurven der Darstellung TD_VERLAUF
|
|
|
|
static lv_obj_t* g_sparkD = nullptr;
|
|
|
|
static lv_obj_t* g_sparkD = nullptr;
|
|
|
|
static lv_chart_series_t* g_sparkSerW = nullptr;
|
|
|
|
static lv_chart_series_t* g_sparkSerW = nullptr;
|
|
|
@@ -719,13 +722,10 @@ static void clock_size_apply() {
|
|
|
|
if (g_standbyClock) lv_obj_set_style_text_font(g_standbyClock, clock_font(), 0);
|
|
|
|
if (g_standbyClock) lv_obj_set_style_text_font(g_standbyClock, clock_font(), 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void scroll_ohne_nachlauf(lv_obj_t* o) {
|
|
|
|
// Der Nachlauf beim Wischen war auf dem Waveshare-Panel eine Zeit lang abgeschaltet, weil
|
|
|
|
#if JC_PANEL_TYPE == WS_PANEL_7H
|
|
|
|
// jedes Einzelbild waehrend des Schwungs den ganzen Schirm neu zeichnete. Seit die
|
|
|
|
lv_obj_clear_flag(o, LV_OBJ_FLAG_SCROLL_MOMENTUM);
|
|
|
|
// Anzeigewerte feste Masse haben, faellt das weg - das Menue laeuft mit Nachlauf fluessig.
|
|
|
|
#else
|
|
|
|
static void scroll_ohne_nachlauf(lv_obj_t* o) { (void)o; }
|
|
|
|
(void)o;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static lv_obj_t* make_page(lv_obj_t* parent) {
|
|
|
|
static lv_obj_t* make_page(lv_obj_t* parent) {
|
|
|
|
lv_obj_t* p = lv_obj_create(parent);
|
|
|
|
lv_obj_t* p = lv_obj_create(parent);
|
|
|
@@ -931,12 +931,7 @@ static bool wake_choice_offered() {
|
|
|
|
(g_state.cxEnabled && g_state.cxArmable && g_state.cxAskOnWake);
|
|
|
|
(g_state.cxEnabled && g_state.cxArmable && g_state.cxAskOnWake);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void standby_screen_cb(lv_event_t*) { // Tipp auf Standby-Uhr -> nachfragen
|
|
|
|
static void standby_screen_cb(lv_event_t*) { // Tipp auf Standby-Uhr -> nachfragen
|
|
|
|
// Vermessen: Vom Tippen bis zur sichtbaren Rueckfrage vergehen rund fuenf Sekunden.
|
|
|
|
|
|
|
|
uint32_t t0 = millis();
|
|
|
|
|
|
|
|
esp_rom_printf("[Touch] %u ms: Tipp auf die Standby-Uhr erkannt\n", (unsigned)t0);
|
|
|
|
|
|
|
|
wake_confirm_show();
|
|
|
|
wake_confirm_show();
|
|
|
|
esp_rom_printf("[Touch] %u ms: Rueckfrage aufgebaut, brauchte %u ms\n",
|
|
|
|
|
|
|
|
(unsigned)millis(), (unsigned)(millis() - t0));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void wake_cancel() { // Abbrechen -> zurueck in die Standby-Helligkeit
|
|
|
|
static void wake_cancel() { // Abbrechen -> zurueck in die Standby-Helligkeit
|
|
|
|
wake_timeout_stop();
|
|
|
|
wake_timeout_stop();
|
|
|
@@ -1113,10 +1108,77 @@ 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
|
|
|
|
// 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
|
|
|
|
// eigentliche Frage an eine PID-Regelung, und eine Zahl kann sie grundsaetzlich nicht
|
|
|
|
// beantworten. Gespeist wird sie aus derselben Sekundenabtastung wie die Verlaufsseite.
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Kurz nach einem Standby-Wechsel sackt die Wassertemperatur fuer einen Sekundenbruchteil
|
|
|
|
|
|
|
|
// ab. In genau diesem Moment schalten die Heizungen, und der Wassersensor ist ein NTC am
|
|
|
|
|
|
|
|
// ADC - ein Kessel kann binnen einer Sekunde nicht um Grade einbrechen, die Delle ist also
|
|
|
|
|
|
|
|
// eine Stoerung der Messung, kein Vorgang an der Maschine. Fuer die Dauer des Uebergangs
|
|
|
|
|
|
|
|
// schreiben die Verlaufskurven deshalb den letzten Wert von vor dem Wechsel weiter. Die
|
|
|
|
|
|
|
|
// angezeigten Zahlen bleiben unangetastet - was gemessen wird, steht dort weiter drin.
|
|
|
|
|
|
|
|
#define KURVEN_SPERRE_MS 6000
|
|
|
|
|
|
|
|
static uint32_t g_kurvenSperreBis = 0; // millis(); bis dahin Werte halten
|
|
|
|
|
|
|
|
static float g_haltW = 0.0f;
|
|
|
|
|
|
|
|
static float g_haltD = 0.0f;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
static lv_obj_t* tempSpark(lv_obj_t* parent, lv_color_t col, lv_chart_series_t** ser,
|
|
|
|
float jetzt, float soll) {
|
|
|
|
float jetzt, float soll) {
|
|
|
|
lv_obj_t* ch = lv_chart_create(parent);
|
|
|
|
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_type(ch, LV_CHART_TYPE_LINE);
|
|
|
|
lv_chart_set_point_count(ch, DASH_SPARK_POINTS);
|
|
|
|
lv_chart_set_point_count(ch, DASH_SPARK_POINTS);
|
|
|
|
lv_chart_set_div_line_count(ch, 0, 0);
|
|
|
|
lv_chart_set_div_line_count(ch, 0, 0);
|
|
|
@@ -1130,13 +1192,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);
|
|
|
|
lv_obj_clear_flag(ch, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
*ser = lv_chart_add_series(ch, col, LV_CHART_AXIS_PRIMARY_Y);
|
|
|
|
*ser = lv_chart_add_series(ch, col, LV_CHART_AXIS_PRIMARY_Y);
|
|
|
|
|
|
|
|
|
|
|
|
// Ausschnitt und Startwert sofort setzen. Ein frisch angelegtes Diagramm hat lauter
|
|
|
|
// Startwert sofort setzen. Ein frisch angelegtes Diagramm hat lauter "kein Wert"-Punkte
|
|
|
|
// "kein Wert"-Punkte und zeichnet deshalb nichts - beim Umschalten der Darstellung
|
|
|
|
// und zeichnet deshalb nichts - beim Umschalten der Darstellung saehe man bis zur
|
|
|
|
// saehe man bis zur ersten Sekundenprobe eine leere Flaeche.
|
|
|
|
// ersten Sekundenprobe eine leere Flaeche.
|
|
|
|
int32_t sollT = (int32_t)(soll * 10.0f);
|
|
|
|
(void)soll;
|
|
|
|
lv_chart_set_range(ch, LV_CHART_AXIS_PRIMARY_Y, sollT - 60, sollT + 30);
|
|
|
|
|
|
|
|
lv_chart_set_all_value(ch, *ser, (int32_t)(jetzt * 10.0f));
|
|
|
|
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
|
|
|
|
// Temperaturbereich gemaess aktiver Darstellung (neu) aufbauen - auch beim Umschalten
|
|
|
@@ -1149,6 +1210,7 @@ static void build_temp_row_content() {
|
|
|
|
bulbTempW = bulbTempD = nullptr;
|
|
|
|
bulbTempW = bulbTempD = nullptr;
|
|
|
|
g_sparkW = g_sparkD = nullptr;
|
|
|
|
g_sparkW = g_sparkD = nullptr;
|
|
|
|
g_sparkSerW = g_sparkSerD = nullptr;
|
|
|
|
g_sparkSerW = g_sparkSerD = nullptr;
|
|
|
|
|
|
|
|
g_sparkMin = g_sparkMax = INT32_MIN; // gemerkter Ausschnitt gilt fuer die alten Kurven
|
|
|
|
g_readyBand = g_readyBandLbl = nullptr;
|
|
|
|
g_readyBand = g_readyBandLbl = nullptr;
|
|
|
|
|
|
|
|
|
|
|
|
const lv_color_t teal = lv_color_hex(0x80cbc4);
|
|
|
|
const lv_color_t teal = lv_color_hex(0x80cbc4);
|
|
|
@@ -1177,6 +1239,7 @@ static void build_temp_row_content() {
|
|
|
|
lv_obj_t* cd = tempField(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
|
|
|
lv_obj_t* cd = tempField(g_tempRow, "DAMPF", teal, &lblTempD, &lblSetD, &barDutyD,
|
|
|
|
1, &lv_font_maven_pro_bold_96, false, 0);
|
|
|
|
1, &lv_font_maven_pro_bold_96, false, 0);
|
|
|
|
g_sparkD = tempSpark(cd, COL_ACCENT, &g_sparkSerD, g_state.tempD, g_state.setD);
|
|
|
|
g_sparkD = tempSpark(cd, COL_ACCENT, &g_sparkSerD, g_state.tempD, g_state.setD);
|
|
|
|
|
|
|
|
spark_ranges_fit();
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@@ -1675,20 +1738,6 @@ static void chart_duty_btn_cb(lv_event_t*) {
|
|
|
|
else lv_obj_add_flag(g_legDuty, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
else lv_obj_add_flag(g_legDuty, LV_OBJ_FLAG_HIDDEN);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
chart_redraw();
|
|
|
|
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) {
|
|
|
|
static void build_chart(lv_obj_t* p) {
|
|
|
|
lv_obj_clear_flag(p, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
|
lv_obj_clear_flag(p, LV_OBJ_FLAG_SCROLLABLE);
|
|
|
@@ -1913,11 +1962,31 @@ static void chart_redraw() {
|
|
|
|
lv_chart_refresh(g_chart);
|
|
|
|
lv_chart_refresh(g_chart);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void chart_sample_cb(lv_timer_t*) {
|
|
|
|
static void chart_sample_cb(lv_timer_t*) {
|
|
|
|
|
|
|
|
// Verlaufskurven des Dashboards (Darstellung "Verlauf") fortschreiben. Das stand
|
|
|
|
|
|
|
|
// frueher am Ende von chart_duty_btn_cb - also im Callback eines Knopfes auf der
|
|
|
|
|
|
|
|
// Verlauf-SEITE. Die Kurven wurden dadurch nur fortgeschrieben, wenn jemand genau
|
|
|
|
|
|
|
|
// diesen Knopf drueckte; sonst zeigten sie unveraendert den Wert, der beim Aufbau
|
|
|
|
|
|
|
|
// der Darstellung gerade anlag. Beide Linien lagen deshalb flach und identisch.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// Bewusst vor dem Ausstieg unten: Die Kurven im Dashboard haengen nicht daran, ob
|
|
|
|
|
|
|
|
// die Verlauf-Seite mit ihrem grossen Diagramm schon aufgebaut ist.
|
|
|
|
|
|
|
|
// Sperrfrist nach einem Standby-Wechsel: letzten Wert halten statt der frischen Probe.
|
|
|
|
|
|
|
|
bool sperre = g_kurvenSperreBis != 0 && (int32_t)(millis() - g_kurvenSperreBis) < 0;
|
|
|
|
|
|
|
|
if (!sperre) { g_haltW = g_state.tempW; g_haltD = g_state.tempD; }
|
|
|
|
|
|
|
|
const float probeW = sperre ? g_haltW : g_state.tempW;
|
|
|
|
|
|
|
|
const float probeD = sperre ? g_haltD : g_state.tempD;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (g_sparkSerW && g_sparkW)
|
|
|
|
|
|
|
|
lv_chart_set_next_value(g_sparkW, g_sparkSerW, (int32_t)(probeW * 10.0f));
|
|
|
|
|
|
|
|
if (g_sparkSerD && g_sparkD)
|
|
|
|
|
|
|
|
lv_chart_set_next_value(g_sparkD, g_sparkSerD, (int32_t)(probeD * 10.0f));
|
|
|
|
|
|
|
|
spark_ranges_fit(); // gemeinsame Skala, damit die Hoehen vergleichbar bleiben
|
|
|
|
|
|
|
|
|
|
|
|
if (!g_chart || !g_hist) return;
|
|
|
|
if (!g_chart || !g_hist) return;
|
|
|
|
// 1-s-Probe in die 60-min-Historie (Ringpuffer); Anzeige zeichnet chart_redraw
|
|
|
|
// 1-s-Probe in die 60-min-Historie (Ringpuffer); Anzeige zeichnet chart_redraw
|
|
|
|
bool caseOn = g_state.caseSensorEnabled && g_state.hasCaseTemp;
|
|
|
|
bool caseOn = g_state.caseSensorEnabled && g_state.hasCaseTemp;
|
|
|
|
g_hist->w[g_histPos] = (int16_t)(g_state.tempW * 10.0f + 0.5f);
|
|
|
|
g_hist->w[g_histPos] = (int16_t)(probeW * 10.0f + 0.5f);
|
|
|
|
g_hist->d[g_histPos] = (int16_t)(g_state.tempD * 10.0f + 0.5f);
|
|
|
|
g_hist->d[g_histPos] = (int16_t)(probeD * 10.0f + 0.5f);
|
|
|
|
g_hist->c[g_histPos] = caseOn ? (int16_t)(g_state.caseTemp * 10.0f + 0.5f) : CHART_HIST_NONE;
|
|
|
|
g_hist->c[g_histPos] = caseOn ? (int16_t)(g_state.caseTemp * 10.0f + 0.5f) : CHART_HIST_NONE;
|
|
|
|
float dw = g_state.dutyW, dd = g_state.dutyD;
|
|
|
|
float dw = g_state.dutyW, dd = g_state.dutyD;
|
|
|
|
g_hist->dutyW[g_histPos] = (uint8_t)(dw < 0.0f ? 0 : (dw > 100.0f ? 100 : (int)(dw + 0.5f)));
|
|
|
|
g_hist->dutyW[g_histPos] = (uint8_t)(dw < 0.0f ? 0 : (dw > 100.0f ? 100 : (int)(dw + 0.5f)));
|
|
|
@@ -3573,13 +3642,6 @@ static void refr_ready_cb(lv_event_t*) {
|
|
|
|
(int)g_refrArea[i].y1, (int)g_refrArea[i].y2);
|
|
|
|
(int)g_refrArea[i].y1, (int)g_refrArea[i].y2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void ui_heartbeat_cb(lv_timer_t*) {
|
|
|
|
|
|
|
|
lv_mem_monitor_t m; lv_mem_monitor(&m);
|
|
|
|
|
|
|
|
esp_rom_printf("[UI] %u ms: Herzschlag, LVGL-Speicher frei %u von %u Byte, groesster Block %u\n",
|
|
|
|
|
|
|
|
(unsigned)millis(), (unsigned)m.free_size, (unsigned)m.total_size,
|
|
|
|
|
|
|
|
(unsigned)m.free_biggest_size);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// LVGL legt fuer JEDE Textglyphe einen eigenen Zwischenpuffer an - Breite mal Hoehe, ein
|
|
|
|
// 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,
|
|
|
|
// 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
|
|
|
|
// und mit zwei parallel arbeitenden Zeicheneinheiten fast 100 KB gleichzeitig. Der interne
|
|
|
@@ -4024,8 +4086,9 @@ void ui_init(ProtocolClient* client) {
|
|
|
|
lv_draw_buf_handlers_t* fh = lv_draw_buf_get_font_handlers();
|
|
|
|
lv_draw_buf_handlers_t* fh = lv_draw_buf_get_font_handlers();
|
|
|
|
fh->buf_malloc_cb = font_buf_malloc;
|
|
|
|
fh->buf_malloc_cb = font_buf_malloc;
|
|
|
|
fh->buf_free_cb = font_buf_free;
|
|
|
|
fh->buf_free_cb = font_buf_free;
|
|
|
|
refr_monitor_install();
|
|
|
|
#if WS7_PERF_MONITOR
|
|
|
|
lv_timer_create(ui_heartbeat_cb, 2000, nullptr);
|
|
|
|
refr_monitor_install(); // nur zum Einmessen, siehe WS7_PERF_MONITOR
|
|
|
|
|
|
|
|
#endif
|
|
|
|
g_uiReady = true;
|
|
|
|
g_uiReady = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@@ -4212,19 +4275,23 @@ void ui_update(const MachineState& st) {
|
|
|
|
// Standby-Uhr-Overlay (Backlight wird in onState gesteuert). Uebergaenge werden weich
|
|
|
|
// Standby-Uhr-Overlay (Backlight wird in onState gesteuert). Uebergaenge werden weich
|
|
|
|
// gefadet: Einschlafen blendet die Uhr ein, Aufwecken blendet sie aus. Nur bei echtem
|
|
|
|
// gefadet: Einschlafen blendet die Uhr ein, Aufwecken blendet sie aus. Nur bei echtem
|
|
|
|
// Statuswechsel animieren (g_standbyShown), sonst nur Uhrzeit/Vordergrund aktualisieren.
|
|
|
|
// Statuswechsel animieren (g_standbyShown), sonst nur Uhrzeit/Vordergrund aktualisieren.
|
|
|
|
|
|
|
|
// Standby-Wechsel merken: die Verlaufskurven halten danach kurz ihren letzten Wert,
|
|
|
|
|
|
|
|
// damit die Messstoerung beim Schalten der Heizungen keine Delle in die Linie zieht.
|
|
|
|
|
|
|
|
static bool letzterStandby = false;
|
|
|
|
|
|
|
|
if (st.standbyActive != letzterStandby) {
|
|
|
|
|
|
|
|
letzterStandby = st.standbyActive;
|
|
|
|
|
|
|
|
g_haltW = st.tempW;
|
|
|
|
|
|
|
|
g_haltD = st.tempD;
|
|
|
|
|
|
|
|
g_kurvenSperreBis = millis() + KURVEN_SPERRE_MS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (g_standbyScreen) {
|
|
|
|
if (g_standbyScreen) {
|
|
|
|
bool shouldShow = st.standbyActive && st.standbyShowClock;
|
|
|
|
bool shouldShow = st.standbyActive && st.standbyShowClock;
|
|
|
|
if (shouldShow) {
|
|
|
|
if (shouldShow) {
|
|
|
|
label_set_if_changed(g_standbyClock, zeit.length() ? zeit.c_str() : "--:--");
|
|
|
|
label_set_if_changed(g_standbyClock, zeit.length() ? zeit.c_str() : "--:--");
|
|
|
|
if (!g_standbyShown) {
|
|
|
|
if (!g_standbyShown) {
|
|
|
|
// Vermessen: Das Einblenden der Uhr ist der Moment, in dem das Display
|
|
|
|
|
|
|
|
// zuletzt stehen geblieben ist. Bleibt die zweite Zeile aus, haengt es hier.
|
|
|
|
|
|
|
|
esp_rom_printf("[UI] Standby-Uhr wird eingeblendet\n");
|
|
|
|
|
|
|
|
uint32_t t0 = millis();
|
|
|
|
|
|
|
|
ui_fade_in(g_standbyScreen, UI_FADE_MS); // Einschlaf-Animation
|
|
|
|
ui_fade_in(g_standbyScreen, UI_FADE_MS); // Einschlaf-Animation
|
|
|
|
g_standbyShown = true;
|
|
|
|
g_standbyShown = true;
|
|
|
|
esp_rom_printf("[UI] Standby-Uhr eingeblendet, %u ms\n",
|
|
|
|
|
|
|
|
(unsigned)(millis() - t0));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Frueher wurde die Uhr hier bei JEDER Zustandsmeldung nach vorn geholt. Das
|
|
|
|
// Frueher wurde die Uhr hier bei JEDER Zustandsmeldung nach vorn geholt. Das
|
|
|
|
// ordnet die Ebenen neu und laesst LVGL den gesamten Bildschirm neu zeichnen -
|
|
|
|
// ordnet die Ebenen neu und laesst LVGL den gesamten Bildschirm neu zeichnen -
|
|
|
|