#include "display_ui.h" #include #include #include "fire_frames.h" #include "clock_frames.h" static uint8_t fire_flames_frame = 0; static uint8_t clock_frame = 0; uint32_t lastDispTime = 0; // Statische Bitmap aus Lopaka static const unsigned char image_paint_27_bits[] U8X8_PROGMEM = { 0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80, 0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00, 0x00,0x00,0x01,0x00 }; static const unsigned char image_checked_bits[] U8X8_PROGMEM = {0x00,0x00,0x40,0x21,0x13,0x0e,0x04,0x00}; static const unsigned char image_crossed_bits[] U8X8_PROGMEM = {0x00,0x21,0x12,0x0c,0x1e,0x33,0x00,0x00}; // U8g2-Display-Objekt static U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); void initDisplay() { Wire.begin(I2C_SDA, I2C_SCL); // SDA, SCL für XIAO ESP32-C6 Wire.setClock(400000); // 400 kHz Fast Mode u8g2.begin(); } // ############################################################# // ANIMATIONEN BERECHNEN & ZEICHNEN // ############################################################# static void updateAnimations() { // 8 Frames: Wechsel alle 77 ms fire_flames_frame = (millis() / 77) % FIRE_FLAMES_FRAME_COUNT; // 143 Frames: Wechsel alle 50 ms (ca. 7 Sekunden Gesamt-Umlaufzeit) clock_frame = (millis() / 50) % CLOCK_FRAME_COUNT; } static void drawAnimation_fire_flames() { u8g2.setDrawColor(1); u8g2.drawXBMP(80, 30, FIRE_FLAMES_WIDTH, FIRE_FLAMES_HEIGHT, fire_flames_frames[fire_flames_frame]); } static void drawAnimation_Clock() { u8g2.setDrawColor(1); u8g2.drawXBMP(104, 40, CLOCK_WIDTH, CLOCK_HEIGHT, clock_frames[clock_frame]); } // ############################################################# // HAUPTANZEIGE // ############################################################# static void drawHomeScreen(int currentSpeed, int curH, int curM, bool timeValid, bool timerActive, SystemSettings settings, int curTemp) { u8g2.setFontMode(1); u8g2.setBitmapMode(1); u8g2.setDrawColor(1); // 1 = Weiß (an) // Aktuelle Geschwindigkeit u8g2.setFont(u8g2_font_helvB08_tr); u8g2.drawStr(2, 10, "Geschw:"); char speedBuf[16]; snprintf(speedBuf, sizeof(speedBuf), "%d U/min", currentSpeed); u8g2.drawStr(52, 10, speedBuf); // Zeitschaltuhr u8g2.drawStr(2, 21, "Zeituhr"); // 3. Dynamische Zeitschaltuhr: Start- und Endzeit char timerBuf[16]; if (settings.timerEnabled) { snprintf(timerBuf, sizeof(timerBuf), "%02d:%02d-%02d:%02d", settings.startHour, settings.startMin, settings.endHour, settings.endMin); } else { snprintf(timerBuf, sizeof(timerBuf), "Deaktiviert"); } u8g2.drawStr(52, 21, timerBuf); // Aktuelle Temperatur u8g2.drawStr(2, 32, "Temp"); char tempBuf[16]; snprintf(tempBuf, sizeof(tempBuf), "%d / %d \xb0""C", curTemp, settings.maxTemp); // \xb0 = Grad-Zeichen u8g2.drawStr(52, 32, tempBuf); // ========================================================= // 2. HORIZONTALE TRENNLINIE // ========================================================= u8g2.drawHLine(0, 36, 128); // 5. Große aktuelle Uhrzeit unten links u8g2.setFont(u8g2_font_helvB14_tr); char timeBuf[10]; if (timeValid) { snprintf(timeBuf, sizeof(timeBuf), "%02d:%02d", curH, curM); } else { snprintf(timeBuf, sizeof(timeBuf), "--:--"); } u8g2.drawStr(2, 58, timeBuf); // Icon 1: Zeitschaltuhr aktiv (z. B. bei X = 90) if (timerActive) { drawAnimation_Clock(); } // Icon 2: Überhitzungs-Warnung (z. B. bei X = 110) if (curTemp >= settings.maxTemp) { drawAnimation_fire_flames(); } } // ############################################################# // Zeitschaltuhr // ############################################################# static void drawTimerScreen(TimeEditStep timeEditStep, uint8_t settingIdx, const SystemSettings& settings){ const uint8_t* Font = u8g2_font_helvB10_tr; u8g2.setFontMode(1); u8g2.setBitmapMode(1); // Von u8g2.setFont(Font); u8g2.drawStr(30, 18, "Von:"); // Start Time char startBuf[10]; snprintf(startBuf, sizeof(startBuf), "%02d:%02d", settings.startHour, settings.startMin); u8g2.drawStr(66, 18, startBuf); // string 23 u8g2.drawStr(30, 36, "Bis:"); // End Time char endBuf[10]; snprintf(endBuf, sizeof(endBuf), "%02d:%02d", settings.endHour, settings.endMin); u8g2.drawStr(66, 36, endBuf); // AutoSpeed u8g2.drawStr(18, 54, "Speed:"); char speedBuf[10]; snprintf(speedBuf, sizeof(speedBuf), "%d", settings.autoSpeed); u8g2.drawStr(66, 54, speedBuf); // Auswahlbox Zeichnen switch (timeEditStep) { case EDIT_START_HOUR: u8g2.setDrawColor(2); // Invertierungs mode u8g2.drawBox(65, 7, 16, 13); u8g2.setDrawColor(1); // Wieder zurück auf normal break; case EDIT_START_MIN: u8g2.setDrawColor(2); // Invertierungs mode u8g2.drawBox(65 + 19, 7, 16, 13); u8g2.setDrawColor(1); // Wieder zurück auf normal break; case EDIT_END_HOUR: u8g2.setDrawColor(2); // Invertierungs mode u8g2.drawBox(65, 25, 16, 13); u8g2.setDrawColor(1); // Wieder zurück auf normal break; case EDIT_END_MIN: u8g2.setDrawColor(2); // Invertierungs mode u8g2.drawBox(65 + 19, 25, 16, 13); u8g2.setDrawColor(1); // Wieder zurück auf normal break; case EDIT_SPEED:{ int widthSpeedBuf = u8g2.getStrWidth(speedBuf); u8g2.setDrawColor(2); u8g2.drawBox(64, 43, widthSpeedBuf + 4, 13); // Umschließt den gesamten Wert u8g2.setDrawColor(1); break; } default: break; } } // ############################################################# // EINSTELLUNGSMENÜ // ############################################################# static void drawSettingsScreen(uint8_t settingIdx, TimeEditStep timeEditStep, const SystemSettings& s) { const uint8_t* textFont = u8g2_font_helvB08_tr; const uint8_t* valFont = u8g2_font_helvB08_tr; if(timeEditStep != EDIT_NONE){ drawTimerScreen(timeEditStep, settingIdx, s); return; } u8g2.setFontMode(1); u8g2.setBitmapMode(1); u8g2.setDrawColor(1); //###################### // Zeitschaltuhr Einstellungen //###################### u8g2.setFont(textFont); u8g2.drawStr(10, 10, "Zeituhr Einstellung"); //###################### // Zeitschaltuhr Status //###################### u8g2.setFont(textFont); u8g2.drawStr(10, 22, "Zeituhr:"); // Wenn Zeitschaltuhr Aktiviert if(s.timerEnabled){ // Draw Check u8g2.drawXBMP(78, 15, 7, 8, image_checked_bits); }else{ // Draw X u8g2.drawXBMP(78, 15, 6, 8, image_crossed_bits); } //###################### // Max Temp //###################### u8g2.setFont(textFont); u8g2.drawStr(10, 34, "Max Temp:"); char maxTempBuf[10]; snprintf(maxTempBuf, sizeof(maxTempBuf), "%d", s.maxTemp); u8g2.setFont(valFont); u8g2.drawStr(78, 34, maxTempBuf); // Wenn Ausgewählt if(s.editMaxTemp){ // Edit Fenster makieren int w = u8g2.getStrWidth(maxTempBuf); u8g2.drawFrame(75, 25, w + 6, 12); } //###################### // Beschleunigung //###################### u8g2.setFont(textFont); u8g2.drawStr(10, 46, "Beschleu:"); u8g2.setFont(valFont); char accBuf[10]; snprintf(accBuf, sizeof(accBuf), "%d", s.accelRate); u8g2.drawStr(78, 46, accBuf); // Wenn Ausgewählt if(s.editAcc){ // Edit Fenster makieren int w = u8g2.getStrWidth(accBuf); u8g2.drawFrame(75, 37, w + 6, 12); } //###################### // Save //###################### u8g2.setFont(textFont); u8g2.drawUTF8(10, 58, "Bestätigung"); // Wenn nichts bearbeitet wird... if(!s.editAcc || !s.editMaxTemp){ // ... Auswahl rahmen anzeigen int rowY = 0; int rowH = 12; switch (settingIdx) { case 0: rowY = 1; break; // Zeituhr Einstellung case 1: rowY = 13; break; // Zeituhr An/Aus case 2: rowY = 25; break; // Max Temp case 3: rowY = 37; break; // Beschleunigung case 4: rowY = 49; break; // Bestätigung default: break; } // Rahmen um die aktive Zeile (von X=2 bis fast zum rechten Rand) u8g2.drawFrame(2, rowY, 124, rowH); } } // ############################################################# // Main Funktion // ############################################################# void updateDisplay(bool inSettings, uint8_t settingIdx, TimeEditStep editStep, const SystemSettings& settings, int currentSpeed, int curH, int curM, bool timeValid, int curTemp) { if (millis() - lastDispTime >= 50) { lastDispTime = millis(); u8g2.clearBuffer(); updateAnimations(); if (inSettings) { drawSettingsScreen(settingIdx, editStep, settings); }else{ drawHomeScreen(currentSpeed, curH, curM, timeValid, settings.timerEnabled, settings, curTemp); } u8g2.sendBuffer(); } }