diff --git a/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp b/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp index b163b72..c86b9dd 100644 --- a/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp +++ b/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp @@ -1,8 +1,10 @@ // boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp -#include +#include "DisplayDriverGFX.h" + #include "LovyanPins.h" #include "board_config.h" -#include "DisplayDriverGFX.h" + +#include // ── Globals ── static LGFX* _gfx = nullptr; @@ -18,9 +20,12 @@ static constexpr int DISP_H = 480; static void initDisplay() { Serial.println("LovyanGFX init..."); + // Note: LovyanGFX handles I2C internally (port 1 for touch, port 0 for CH422G) + // No need to call Wire.begin() or Wire1.begin() + _gfx = new LGFX(); _gfx->init(); - _gfx->setRotation(1); // Landscape + _gfx->setRotation(0); // Landscape _gfx->fillScreen(0x000000); Serial.println("Display ready"); @@ -36,44 +41,41 @@ DisplayDriverGFX& DisplayDriverGFX::instance() { void DisplayDriverGFX::begin() { initDisplay(); + // Turn on backlight immediately + setBacklight(true); } void DisplayDriverGFX::setBacklight(bool on) { - if (_gfx) { + if(_gfx) { // LovyanGFX handles backlight via setBrightness _gfx->setBrightness(on ? 255 : 0); } } -int DisplayDriverGFX::width() { - return DISP_W; -} +int DisplayDriverGFX::width() { return DISP_W; } -int DisplayDriverGFX::height() { - return DISP_H; -} +int DisplayDriverGFX::height() { return DISP_H; } // ── Touch handling ── TouchEvent DisplayDriverGFX::readTouch() { TouchEvent evt; - - if (!_gfx) return evt; + if(!_gfx) + return evt; int32_t x, y; - if (_gfx->getTouch(&x, &y)) { - evt.pressed = true; + bool pressed = _gfx->getTouch(&x, &y); + + // Only report NEW touches (debounce - ignore held touches) + evt.pressed = pressed && !_lastTouch.pressed; + + if(pressed) { evt.x = static_cast(x); evt.y = static_cast(y); - - // Track press start for hold detection - if (!_lastTouch.pressed) { - _pressStartMs = millis(); - _isHolding = false; - } + _pressStartMs = millis(); } - _lastTouch = evt; + _lastTouch.pressed = pressed; return evt; } @@ -84,7 +86,7 @@ int DisplayDriverGFX::dashboardTouch(int x, int y) { constexpr int tileW = DISP_W / cols; constexpr int tileH = DISP_H / rows; - if (x < 0 || x >= DISP_W || y < 0 || y >= DISP_H) { + if(x < 0 || x >= DISP_W || y < 0 || y >= DISP_H) { return -1; } @@ -97,21 +99,21 @@ int DisplayDriverGFX::dashboardTouch(int x, int y) { HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) { HoldState state; - if (!_lastTouch.pressed) { + if(!_lastTouch.pressed) { _isHolding = false; return state; } unsigned long elapsed = millis() - _pressStartMs; - if (!_isHolding) { + if(!_isHolding) { _isHolding = true; } state.active = true; state.progress = static_cast(elapsed) / static_cast(holdMs); - if (state.progress >= 1.0f) { + if(state.progress >= 1.0f) { state.progress = 1.0f; state.completed = true; } @@ -122,43 +124,44 @@ HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) { // ── Rendering ── void DisplayDriverGFX::render(const ScreenState& state) { - if (!_gfx) return; + if(!_gfx) + return; // Check if we need full redraw - if (state.screen != _lastScreen) { + if(state.screen != _lastScreen) { _needsRedraw = true; _lastScreen = state.screen; } - 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; + 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::OFF: + if(_needsRedraw) { + _gfx->fillScreen(0x000000); + _needsRedraw = false; + } + break; - case ScreenID::ALERT: - drawAlert(state); - break; + case ScreenID::ALERT: + drawAlert(state); + break; - case ScreenID::DASHBOARD: - if (_needsRedraw) { - drawDashboard(state); - _needsRedraw = false; - } - break; + case ScreenID::DASHBOARD: + if(_needsRedraw) { + drawDashboard(state); + _needsRedraw = false; + } + break; } } @@ -184,10 +187,11 @@ void DisplayDriverGFX::drawAlert(const ScreenState& state) { } void DisplayDriverGFX::drawDashboard(const ScreenState& state) { - _gfx->fillScreen(0x001030); // Dark blue + _gfx->fillScreen(0x001030); // Dark blue // Header - _gfx->fillRect(0, 0, DISP_W, 30, 0x0220); + _gfx->fillRect(0, 0, DISP_W, 30, 0x1A1A); // Dark gray + _gfx->setFont(&fonts::Font0); // Built-in minimal font _gfx->setTextColor(0xFFFF); _gfx->setTextSize(1); _gfx->setCursor(5, 10); @@ -197,7 +201,6 @@ void DisplayDriverGFX::drawDashboard(const ScreenState& state) { _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; @@ -206,9 +209,9 @@ void DisplayDriverGFX::drawDashboard(const ScreenState& state) { constexpr int margin = 8; // Draw placeholder tiles (8 total for 2x4 grid) - const char* tileLabels[] = {"1", "2", "3", "4", "5", "6", "7", "8"}; + const char* tileLabels[] = { "1", "2", "3", "4", "5", "6", "7", "8" }; - for (int i = 0; i < 8; i++) { + for(int i = 0; i < 8; i++) { int col = i % cols; int row = i / cols; @@ -226,17 +229,20 @@ void DisplayDriverGFX::drawDashboard(const ScreenState& state) { // Tile number _gfx->setTextColor(0xFFFF); _gfx->setTextSize(2); - _gfx->setCursor(x + w/2 - 10, y + h/2 - 10); + _gfx->setCursor(x + w / 2 - 10, y + h / 2 - 10); _gfx->print(tileLabels[i]); } } void DisplayDriverGFX::updateHint() { - if (!_gfx) return; + if(!_gfx) + return; static uint32_t lastTime = 0; uint32_t now = millis(); - if (now - lastTime < 50) return; + // Fixed: throttle to 100ms instead of 50ms + if(now - lastTime < 100) + return; lastTime = now; float t = (now % 2000) / 2000.0f; diff --git a/boards/esp32-s3-lcd-43/esp32-s3-lcd-43.ino b/boards/esp32-s3-lcd-43/esp32-s3-lcd-43.ino index 7300dcb..b09fa5d 100644 --- a/boards/esp32-s3-lcd-43/esp32-s3-lcd-43.ino +++ b/boards/esp32-s3-lcd-43/esp32-s3-lcd-43.ino @@ -2,14 +2,15 @@ // Klubhaus Doorbell — ESP32-S3-Touch-LCD-4.3 target // -#include +#include "DisplayDriverGFX.h" #include "board_config.h" #include "secrets.h" -#include "DisplayDriverGFX.h" + +#include DisplayDriverGFX gfxDriver; -DisplayManager display(&gfxDriver); -DoorbellLogic logic(&display); +DisplayManager display(&gfxDriver); +DoorbellLogic logic(&display); void setup() { Serial.begin(115200); @@ -19,36 +20,52 @@ void setup() { logic.finishBoot(); } -void loop() { - // ── State machine tick ── - logic.update(); +// void loop() { +TouchEvent evt = display.readTouch(); - // ── Render current screen ── - display.render(logic.getScreenState()); +logic.update(); +display.render(logic.getScreenState()); - // ── Touch handling ── - const ScreenState& st = logic.getScreenState(); +const ScreenState& st = logic.getScreenState(); - if (st.deviceState == DeviceState::ALERTING) { - HoldState h = display.updateHold(HOLD_TO_SILENCE_MS); - if (h.completed) { - logic.silenceAlert(); - } - if (!h.active) { - display.updateHint(); - } - } else { - TouchEvent evt = display.readTouch(); - if (evt.pressed && st.screen == ScreenID::DASHBOARD) { - int tile = display.dashboardTouch(evt.x, evt.y); - if (tile >= 0) Serial.printf("[DASH] Tile %d tapped\n", tile); - } +if(st.deviceState == DeviceState::ALERTING) { + HoldState h = display.updateHold(HOLD_TO_SILENCE_MS); + if(h.completed) { + logic.silenceAlert(); } - - // ── Serial console ── - if (Serial.available()) { - String cmd = Serial.readStringUntil('\n'); - cmd.trim(); - if (cmd.length() > 0) logic.onSerialCommand(cmd); + if(!h.active) { + display.updateHint(); + } +} else if(evt.pressed) { + if(st.screen == ScreenID::OFF) { + // Tap in OFF mode → wake to DASHBOARD + Serial.println("[TOUCH] OFF → DASHBOARD"); + logic.setScreen(ScreenID::DASHBOARD); + display.setBacklight(true); + } else if(st.screen == ScreenID::DASHBOARD) { + int tile = display.dashboardTouch(evt.x, evt.y); + if(tile >= 0) { + Serial.printf("[DASH] Tile %d tapped\n", tile); + // TODO: Handle tile actions + } + } else if(st.screen == ScreenID::ALERT) { + // Tap in ALERT mode → could dismiss or show more info + Serial.println("[TOUCH] ALERT tap"); + // For now, let's make tap do nothing (hold to silence only) + // Or: logic.dismissAlert(); } } + +// Serial console (unchanged) +if(Serial.available()) { + // ... +} +} +// ── Serial console ── +if(Serial.available()) { + String cmd = Serial.readStringUntil('\n'); + cmd.trim(); + if(cmd.length() > 0) + logic.onSerialCommand(cmd); +} +} diff --git a/libraries/KlubhausCore/src/DoorbellLogic.cpp b/libraries/KlubhausCore/src/DoorbellLogic.cpp index ba66da2..48458cf 100644 --- a/libraries/KlubhausCore/src/DoorbellLogic.cpp +++ b/libraries/KlubhausCore/src/DoorbellLogic.cpp @@ -258,3 +258,13 @@ void DoorbellLogic::onSerialCommand(const String& cmd) { } else Serial.println(F("[CMD] alert|silence|reboot|dashboard|off|status")); } + +void DoorbellLogic::setScreen(ScreenID s) { + Serial.printf("[SCREEN] Set to %s\n", screenIdStr(s)); + _state.screen = s; + + // Auto-manage backlight based on screen + bool needsBacklight = (s != ScreenID::OFF); + _display->setBacklight(needsBacklight); + _state.backlightOn = needsBacklight; +} diff --git a/libraries/KlubhausCore/src/DoorbellLogic.h b/libraries/KlubhausCore/src/DoorbellLogic.h index f9714fc..1a5c174 100644 --- a/libraries/KlubhausCore/src/DoorbellLogic.h +++ b/libraries/KlubhausCore/src/DoorbellLogic.h @@ -34,6 +34,7 @@ private: void flushStatus(const String& message); void heartbeat(); void transition(DeviceState s); + void setScreen(ScreenID s); String topicUrl(const char* base); DisplayManager* _display; diff --git a/vendor/.gitignore b/vendor/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/vendor/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore