Files
klubhaus-doorbell/boards/esp32-32e/DisplayDriverTFT.cpp
2026-02-16 19:08:47 -08:00

156 lines
4.5 KiB
C++

#include "DisplayDriverTFT.h"
void DisplayDriverTFT::begin() {
// Backlight
pinMode(PIN_LCD_BL, OUTPUT);
digitalWrite(PIN_LCD_BL, LOW);
_tft.init();
_tft.setRotation(DISPLAY_ROTATION);
_tft.fillScreen(TFT_BLACK);
Serial.printf("[GFX] Display OK: %dx%d\n", DISPLAY_WIDTH, DISPLAY_HEIGHT);
drawBoot();
digitalWrite(PIN_LCD_BL, HIGH);
Serial.println("[GFX] Backlight ON");
}
void DisplayDriverTFT::setBacklight(bool on) {
digitalWrite(PIN_LCD_BL, on ? HIGH : LOW);
}
// ── Rendering ───────────────────────────────────────────────
void DisplayDriverTFT::render(const ScreenState& st) {
if (st.screen != _lastScreen) {
_needsRedraw = true;
_lastScreen = st.screen;
}
switch (st.screen) {
case ScreenID::BOOT:
if (_needsRedraw) { drawBoot(); _needsRedraw = false; }
break;
case ScreenID::ALERT:
drawAlert(st);
break;
case ScreenID::DASHBOARD:
if (_needsRedraw) { drawDashboard(st); _needsRedraw = false; }
break;
case ScreenID::OFF:
if (_needsRedraw) { _tft.fillScreen(TFT_BLACK); _needsRedraw = false; }
break;
}
}
void DisplayDriverTFT::drawBoot() {
_tft.fillScreen(TFT_BLACK);
_tft.setTextColor(TFT_WHITE, TFT_BLACK);
_tft.setTextSize(2);
_tft.setCursor(10, 10);
_tft.printf("KLUBHAUS v%s", FW_VERSION);
_tft.setTextSize(1);
_tft.setCursor(10, 40);
_tft.print(BOARD_NAME);
_tft.setCursor(10, 60);
_tft.print("Booting...");
}
void DisplayDriverTFT::drawAlert(const ScreenState& st) {
uint32_t elapsed = millis() - st.alertStartMs;
uint8_t pulse = 180 + (uint8_t)(75.0f * sinf(elapsed / 300.0f));
uint16_t bg = _tft.color565(pulse, 0, 0);
_tft.fillScreen(bg);
_tft.setTextColor(TFT_WHITE, bg);
_tft.setTextSize(3);
_tft.setCursor(10, 20);
_tft.print(st.alertTitle.length() > 0 ? st.alertTitle : "ALERT");
_tft.setTextSize(2);
_tft.setCursor(10, 80);
_tft.print(st.alertBody);
_tft.setTextSize(1);
_tft.setCursor(10, DISPLAY_HEIGHT - 20);
_tft.print("Hold to silence...");
}
void DisplayDriverTFT::drawDashboard(const ScreenState& st) {
_tft.fillScreen(TFT_BLACK);
_tft.setTextColor(TFT_WHITE, TFT_BLACK);
_tft.setTextSize(1);
_tft.setCursor(5, 5);
_tft.printf("KLUBHAUS — %s", deviceStateStr(st.deviceState));
int y = 30;
_tft.setCursor(5, y); y += 18;
_tft.printf("WiFi: %s %ddBm", st.wifiSsid.c_str(), st.wifiRssi);
_tft.setCursor(5, y); y += 18;
_tft.printf("IP: %s", st.ipAddr.c_str());
_tft.setCursor(5, y); y += 18;
_tft.printf("Up: %lus Heap: %d", st.uptimeMs / 1000, ESP.getFreeHeap());
_tft.setCursor(5, y); y += 18;
_tft.printf("Last poll: %lus ago",
st.lastPollMs > 0 ? (millis() - st.lastPollMs) / 1000 : 0);
}
// ── Touch ───────────────────────────────────────────────────
TouchEvent DisplayDriverTFT::readTouch() {
TouchEvent evt;
uint16_t tx, ty;
if (_tft.getTouch(&tx, &ty)) {
evt.pressed = true;
evt.x = tx;
evt.y = ty;
}
return evt;
}
int DisplayDriverTFT::dashboardTouch(int x, int y) {
// 2-column, 4-row
int col = x / (DISPLAY_WIDTH / 2);
int row = (y - 30) / 40;
if (row < 0 || row > 3) return -1;
return row * 2 + col;
}
HoldState DisplayDriverTFT::updateHold(unsigned long holdMs) {
HoldState h;
TouchEvent t = readTouch();
if (t.pressed) {
if (!_holdActive) {
_holdActive = true;
_holdStartMs = millis();
}
uint32_t held = millis() - _holdStartMs;
h.active = true;
h.progress = constrain((float)held / (float)holdMs, 0.0f, 1.0f);
h.completed = (held >= holdMs);
// Simple progress bar at bottom of screen
int barW = (int)(DISPLAY_WIDTH * h.progress);
_tft.fillRect(0, DISPLAY_HEIGHT - 8, barW, 8, TFT_WHITE);
_tft.fillRect(barW, DISPLAY_HEIGHT - 8, DISPLAY_WIDTH - barW, 8, TFT_DARKGREY);
} else {
_holdActive = false;
}
return h;
}
void DisplayDriverTFT::updateHint() {
float t = (millis() % 2000) / 2000.0f;
uint8_t v = (uint8_t)(30.0f + 30.0f * sinf(t * 2 * PI));
uint16_t col = _tft.color565(v, v, v);
_tft.drawRect(DISPLAY_WIDTH / 2 - 40, DISPLAY_HEIGHT / 2 + 20, 80, 40, col);
}