kugelmuehle/display_ui.cpp
2026-09-26 01:10:32 +02:00

297 lines
No EOL
9 KiB
C++

#include "display_ui.h"
#include <Wire.h>
#include <U8g2lib.h>
#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();
}
}