diff --git a/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp b/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp index d94f30b..aee597a 100644 --- a/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp +++ b/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp @@ -1,20 +1,3 @@ -#include "LovyanPins.h" -#include "board_config.h" -#include -#include - -// Global display instance -static LGFX* _gfx = nullptr; -static ESP_IOExpander* _expander = nullptr; - -// Forward declarations -void initExpander(); -void initDisplay(); - -// ── Expander initialization (from Westcott) ── -void initExpander() -{ - Serial.println("IO expander init..."); #include #include #include @@ -34,11 +17,11 @@ static void initDisplay(); static constexpr int DISP_W = 800; static constexpr int DISP_H = 480; -// ── Expander initialization ── +// ── Expander initialization (from Westcott) ── static void initExpander() { Serial.println("IO expander init..."); - // Initialize I2C for expander + // Initialize I2C for expander (port 0) Wire.begin(TOUCH_SDA, TOUCH_SCL); _expander = new ESP_IOExpander_CH422G( @@ -51,7 +34,7 @@ static void initExpander() { // Set all pins to output _expander->multiPinMode(TP_RST | LCD_BL | LCD_RST | SD_CS | USB_SEL, OUTPUT); - // Reset sequence + // Reset sequence for LCD _expander->digitalWrite(LCD_RST, LOW); delay(50); _expander->digitalWrite(LCD_RST, HIGH); @@ -115,7 +98,7 @@ TouchEvent DisplayDriverGFX::readTouch() { evt.x = static_cast(x); evt.y = static_cast(y); - // Track press start + // Track press start for hold detection if (!_lastTouch.pressed) { _pressStartMs = millis(); _isHolding = false; @@ -154,7 +137,6 @@ HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) { unsigned long elapsed = millis() - _pressStartMs; if (!_isHolding) { - // Start tracking hold _isHolding = true; } @@ -174,49 +156,111 @@ HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) { void DisplayDriverGFX::render(const ScreenState& state) { if (!_gfx) return; - // Clear with background color - _gfx->fillScreen(0x001030); // Dark blue - - if (!state.showDashboard) { - // Show alert/message screen - renderAlert(state); - return; + // Check if we need full redraw + if (state.screen != _lastScreen) { + _needsRedraw = true; + _lastScreen = state.screen; } - // Draw dashboard tiles + switch (state.screen) { + case ScreenID::BOOT: + if (_needsRedraw) { + _gfx->fillScreen(0x000000); + _gfx->setTextColor(0xFFFF); + _gfx->setTextSize(2); + _gfx->setCursor(10, 10); + _gfx->print("KLUBHAUS BOOT"); + _needsRedraw = false; + } + break; + + case ScreenID::OFF: + if (_needsRedraw) { + _gfx->fillScreen(0x000000); + _needsRedraw = false; + } + break; + + case ScreenID::ALERT: + drawAlert(state); + break; + + case ScreenID::DASHBOARD: + if (_needsRedraw) { + drawDashboard(state); + _needsRedraw = false; + } + break; + } +} + +void DisplayDriverGFX::drawAlert(const ScreenState& state) { + uint32_t elapsed = millis() - state.alertStartMs; + uint8_t pulse = static_cast(180.0f + 75.0f * sinf(elapsed / 300.0f)); + uint16_t bg = _gfx->color565(pulse, 0, 0); + + _gfx->fillScreen(bg); + _gfx->setTextColor(0xFFFF, bg); + + _gfx->setTextSize(3); + _gfx->setCursor(10, 20); + _gfx->print(state.alertTitle.length() > 0 ? state.alertTitle.c_str() : "ALERT"); + + _gfx->setTextSize(2); + _gfx->setCursor(10, 80); + _gfx->print(state.alertBody); + + _gfx->setTextSize(1); + _gfx->setCursor(10, DISP_H - 20); + _gfx->print("Hold to silence..."); +} + +void DisplayDriverGFX::drawDashboard(const ScreenState& state) { + _gfx->fillScreen(0x001030); // Dark blue + + // Header + _gfx->fillRect(0, 0, DISP_W, 30, 0x0220); + _gfx->setTextColor(0xFFFF); + _gfx->setTextSize(1); + _gfx->setCursor(5, 10); + _gfx->printf("KLUBHAUS"); + + // WiFi status + _gfx->setCursor(DISP_W - 100, 10); + _gfx->printf("WiFi:%s", state.wifiSsid.length() > 0 ? "ON" : "OFF"); + + + // Tiles: 2 rows × 4 columns constexpr int cols = 4; constexpr int rows = 2; constexpr int tileW = DISP_W / cols; - constexpr int tileH = DISP_H / rows; + constexpr int tileH = (DISP_H - 30) / rows; constexpr int margin = 8; - for (int i = 0; i < state.dashTiles.size(); i++) { + // Draw placeholder tiles (8 total for 2x4 grid) + const char* tileLabels[] = {"1", "2", "3", "4", "5", "6", "7", "8"}; + + for (int i = 0; i < 8; i++) { int col = i % cols; int row = i / cols; int x = col * tileW + margin; - int y = row * tileH + margin; + int y = 30 + row * tileH + margin; int w = tileW - 2 * margin; int h = tileH - 2 * margin; // Tile background - uint16_t tileColor = state.dashTiles[i].active ? 0x04A0 : 0x0220; - _gfx->fillRoundRect(x, y, w, h, 8, tileColor); + _gfx->fillRoundRect(x, y, w, h, 8, 0x0220); // Tile border _gfx->drawRoundRect(x, y, w, h, 8, 0xFFFF); - // Tile label + // Tile number _gfx->setTextColor(0xFFFF); _gfx->setTextSize(2); - _gfx->setCursor(x + 10, y + 10); - _gfx->print(state.dashTiles[i].label); + _gfx->setCursor(x + w/2 - 10, y + h/2 - 10); + _gfx->print(tileLabels[i]); } - - // Draw WiFi status - _gfx->setTextSize(1); - _gfx->setCursor(DISP_W - 100, 10); - _gfx->printf("WiFi: %s", state.wifiConnected ? "ON" : "OFF"); } void DisplayDriverGFX::updateHint() { @@ -233,12 +277,3 @@ void DisplayDriverGFX::updateHint() { _gfx->drawCircle(DISP_W / 2, DISP_H / 2, 50, col); } - -// Helper for alert rendering (implement as needed) -void DisplayDriverGFX::renderAlert(const ScreenState& state) { - // Placeholder - implement based on your ScreenState fields - _gfx->setTextColor(0xFFFF); - _gfx->setTextSize(3); - _gfx->setCursor(200, 200); - _gfx->print("Alert Mode"); -} diff --git a/boards/esp32-s3-lcd-43/DisplayDriverGFX.h b/boards/esp32-s3-lcd-43/DisplayDriverGFX.h index 5746fb3..63b5d06 100644 --- a/boards/esp32-s3-lcd-43/DisplayDriverGFX.h +++ b/boards/esp32-s3-lcd-43/DisplayDriverGFX.h @@ -1,21 +1,8 @@ #pragma once #include -#include "ScreenState.h" #include "IDisplayDriver.h" -struct TouchEvent { - bool pressed = false; - int x = 0; - int y = 0; -}; - -struct HoldState { - bool active = false; - bool completed = false; - float progress = 0.0f; // 0.0 – 1.0 -}; - class DisplayDriverGFX : public IDisplayDriver { public: // ── IDisplayDriver ── @@ -35,8 +22,16 @@ public: static DisplayDriverGFX& instance(); private: + // Helper rendering functions + void drawAlert(const ScreenState& state); + void drawDashboard(const ScreenState& state); + // Touch handling TouchEvent _lastTouch = {false, 0, 0}; unsigned long _pressStartMs = 0; bool _isHolding = false; + + // Screen tracking + ScreenID _lastScreen = ScreenID::BOOT; + bool _needsRedraw = true; }; diff --git a/libraries/KlubhausCore/src/ScreenState.h b/libraries/KlubhausCore/src/ScreenState.h index 0f02126..f9d47ae 100644 --- a/libraries/KlubhausCore/src/ScreenState.h +++ b/libraries/KlubhausCore/src/ScreenState.h @@ -17,38 +17,50 @@ enum class ScreenID { struct ScreenState { DeviceState deviceState = DeviceState::BOOTED; - ScreenID screen = ScreenID::BOOT; + ScreenID screen = ScreenID::BOOT; - String alertTitle; - String alertBody; - uint32_t alertStartMs = 0; + String alertTitle; + String alertBody; + uint32_t alertStartMs = 0; uint32_t silenceStartMs = 0; - bool backlightOn = false; - int wifiRssi = 0; - String wifiSsid; - String ipAddr; - uint32_t uptimeMs = 0; - uint32_t lastPollMs = 0; - uint32_t lastHeartbeatMs= 0; + bool backlightOn = false; + int wifiRssi = 0; + String wifiSsid; + String ipAddr; + uint32_t uptimeMs = 0; + uint32_t lastPollMs = 0; + uint32_t lastHeartbeatMs = 0; + + bool showDashboard = false; }; -inline const char* deviceStateStr(DeviceState s) { +inline const char* deviceStateStr(DeviceState s) +{ switch (s) { - case DeviceState::BOOTED: return "BOOTED"; - case DeviceState::SILENT: return "SILENT"; - case DeviceState::ALERTING: return "ALERTING"; - case DeviceState::SILENCED: return "SILENCED"; + case DeviceState::BOOTED: + return "BOOTED"; + case DeviceState::SILENT: + return "SILENT"; + case DeviceState::ALERTING: + return "ALERTING"; + case DeviceState::SILENCED: + return "SILENCED"; } return "?"; } -inline const char* screenIdStr(ScreenID s) { +inline const char* screenIdStr(ScreenID s) +{ switch (s) { - case ScreenID::BOOT: return "BOOT"; - case ScreenID::OFF: return "OFF"; - case ScreenID::ALERT: return "ALERT"; - case ScreenID::DASHBOARD: return "DASHBOARD"; + case ScreenID::BOOT: + return "BOOT"; + case ScreenID::OFF: + return "OFF"; + case ScreenID::ALERT: + return "ALERT"; + case ScreenID::DASHBOARD: + return "DASHBOARD"; } return "?"; } diff --git a/mise.toml b/mise.toml index 8276591..50db3a3 100644 --- a/mise.toml +++ b/mise.toml @@ -42,6 +42,22 @@ if [ ! -d "vendor/esp32-s3-lcd-43/LovyanGFX" ]; then else echo "LovyanGFX already exists, skipping" fi + +# Create library.properties for Arduino CLI +cat > vendor/esp32-s3-lcd-43/LovyanGFX/library.properties << 'EOF' +name=LovyanGFX +version=0.5.0 +author=lovyan03 +maintainer=lovyan03 +sentence=GFX library for ESP32 +paragraph=Display and touch driver for ESP32 +category=Display +url=https://github.com/lovyan03/LovyanGFX +architectures=esp32 +includes=LovyanGFX.hpp +src_core=src +EOF + echo "[OK] LovyanGFX vendored" """