diff --git a/boards/esp32-32e/DisplayDriverTFT.cpp b/boards/esp32-32e/DisplayDriverTFT.cpp index 982a7ca..16ba2b1 100644 --- a/boards/esp32-32e/DisplayDriverTFT.cpp +++ b/boards/esp32-32e/DisplayDriverTFT.cpp @@ -136,6 +136,7 @@ HoldState DisplayDriverTFT::updateHold(unsigned long holdMs) { if (!_holdActive) { _holdActive = true; _holdStartMs = millis(); + h.started = true; } uint32_t held = millis() - _holdStartMs; h.active = true; @@ -147,8 +148,8 @@ HoldState DisplayDriverTFT::updateHold(unsigned long holdMs) { _tft.fillRect(0, DISPLAY_HEIGHT - 8, barW, 8, TFT_WHITE); _tft.fillRect(barW, DISPLAY_HEIGHT - 8, DISPLAY_WIDTH - barW, 8, TFT_DARKGREY); } else { - if (_ // Clear theholdActive) { - progress bar when released + if (_holdActive) { + // Clear the progress bar when released _tft.fillRect(0, DISPLAY_HEIGHT - 8, DISPLAY_WIDTH, 8, TFT_DARKGREY); } _holdActive = false; @@ -156,9 +157,10 @@ HoldState DisplayDriverTFT::updateHold(unsigned long holdMs) { return h; } -void DisplayDriverTFT::updateHint() { +void DisplayDriverTFT::updateHint(int x, int y) { 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); + // Draw at touch position instead of center + _tft.drawRect(x - 40, y - 20, 80, 40, col); } diff --git a/boards/esp32-32e/DisplayDriverTFT.h b/boards/esp32-32e/DisplayDriverTFT.h index 4b45c61..3a3b5f1 100644 --- a/boards/esp32-32e/DisplayDriverTFT.h +++ b/boards/esp32-32e/DisplayDriverTFT.h @@ -12,7 +12,7 @@ public: TouchEvent readTouch() override; int dashboardTouch(int x, int y) override; HoldState updateHold(unsigned long holdMs) override; - void updateHint() override; + void updateHint(int x, int y) override; int width() override { return DISPLAY_WIDTH; } int height() override { return DISPLAY_HEIGHT; } diff --git a/boards/esp32-32e/esp32-32e.ino b/boards/esp32-32e/esp32-32e.ino index 4088a6b..5e4cfa2 100644 --- a/boards/esp32-32e/esp32-32e.ino +++ b/boards/esp32-32e/esp32-32e.ino @@ -28,18 +28,32 @@ void loop() { // ── Touch handling ── const ScreenState& st = logic.getScreenState(); + static int holdStartX = -1; + static int holdStartY = -1; if (st.deviceState == DeviceState::ALERTING) { HoldState h = display.updateHold(HOLD_TO_SILENCE_MS); if (h.completed) { logic.silenceAlert(); + holdStartX = -1; + holdStartY = -1; } - if (!h.active) { - display.updateHint(); + if (h.started) { + TouchEvent t = display.readTouch(); + holdStartX = t.x; + holdStartY = t.y; + } + if (!h.active && holdStartX >= 0) { + display.updateHint(holdStartX, holdStartY); } } else { + holdStartX = -1; + holdStartY = -1; + } + + if (st.screen == ScreenID::DASHBOARD) { TouchEvent evt = display.readTouch(); - if (evt.pressed && st.screen == ScreenID::DASHBOARD) { + if (evt.pressed) { int tile = display.dashboardTouch(evt.x, evt.y); if (tile >= 0) Serial.printf("[DASH] Tile %d tapped\n", tile); } diff --git a/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp b/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp index c86b9dd..18fe613 100644 --- a/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp +++ b/boards/esp32-s3-lcd-43/DisplayDriverGFX.cpp @@ -108,6 +108,7 @@ HoldState DisplayDriverGFX::updateHold(unsigned long holdMs) { if(!_isHolding) { _isHolding = true; + state.started = true; } state.active = true; @@ -234,7 +235,7 @@ void DisplayDriverGFX::drawDashboard(const ScreenState& state) { } } -void DisplayDriverGFX::updateHint() { +void DisplayDriverGFX::updateHint(int x, int y) { if(!_gfx) return; @@ -249,5 +250,6 @@ void DisplayDriverGFX::updateHint() { uint8_t v = static_cast(30.0f + 30.0f * sinf(t * 2 * 3.14159f)); uint16_t col = ((v >> 3) << 11) | ((v >> 2) << 5) | (v >> 3); - _gfx->drawCircle(DISP_W / 2, DISP_H / 2, 50, col); + // Draw at touch position instead of center + _gfx->drawCircle(x, y, 50, col); } diff --git a/boards/esp32-s3-lcd-43/DisplayDriverGFX.h b/boards/esp32-s3-lcd-43/DisplayDriverGFX.h index 63b5d06..ae06c29 100644 --- a/boards/esp32-s3-lcd-43/DisplayDriverGFX.h +++ b/boards/esp32-s3-lcd-43/DisplayDriverGFX.h @@ -13,7 +13,7 @@ public: TouchEvent readTouch() override; int dashboardTouch(int x, int y) override; HoldState updateHold(unsigned long holdMs) override; - void updateHint() override; + void updateHint(int x, int y) override; int width() override; int height() override; 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 f914a09..03b1da0 100644 --- a/boards/esp32-s3-lcd-43/esp32-s3-lcd-43.ino +++ b/boards/esp32-s3-lcd-43/esp32-s3-lcd-43.ino @@ -28,15 +28,32 @@ void loop() { const ScreenState& st = logic.getScreenState(); + // Track initial hold position for hint + static int holdStartX = -1; + static int holdStartY = -1; + if(st.deviceState == DeviceState::ALERTING) { HoldState h = display.updateHold(HOLD_TO_SILENCE_MS); if(h.completed) { logic.silenceAlert(); + holdStartX = -1; + holdStartY = -1; } - if(!h.active) { - display.updateHint(); + if(h.started) { + // Capture initial touch position + holdStartX = evt.x; + holdStartY = evt.y; } - } else if(evt.pressed) { + if(!h.active && holdStartX >= 0) { + display.updateHint(holdStartX, holdStartY); + } + } else { + // Reset when not alerting + holdStartX = -1; + holdStartY = -1; + } + + if(evt.pressed) { if(st.screen == ScreenID::OFF) { // Tap in OFF mode → wake to DASHBOARD Serial.println("[TOUCH] OFF → DASHBOARD"); @@ -46,15 +63,12 @@ void loop() { 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(); } } + if(Serial.available()) { String cmd = Serial.readStringUntil('\n'); cmd.trim(); diff --git a/libraries/KlubhausCore/src/DisplayManager.h b/libraries/KlubhausCore/src/DisplayManager.h index f9da315..b6f2f00 100644 --- a/libraries/KlubhausCore/src/DisplayManager.h +++ b/libraries/KlubhausCore/src/DisplayManager.h @@ -5,19 +5,33 @@ /// Board sketch creates the concrete driver and passes it in. class DisplayManager { public: - DisplayManager() : _drv(nullptr) {} - explicit DisplayManager(IDisplayDriver* drv) : _drv(drv) {} + DisplayManager() + : _drv(nullptr) { } + explicit DisplayManager(IDisplayDriver* drv) + : _drv(drv) { } void setDriver(IDisplayDriver* drv) { _drv = drv; } - void begin() { if (_drv) _drv->begin(); } - void setBacklight(bool on) { if (_drv) _drv->setBacklight(on); } - void render(const ScreenState& st) { if (_drv) _drv->render(st); } - TouchEvent readTouch() { return _drv ? _drv->readTouch() : TouchEvent{}; } - int dashboardTouch(int x, int y) { return _drv ? _drv->dashboardTouch(x, y) : -1; } - HoldState updateHold(unsigned long ms) { return _drv ? _drv->updateHold(ms) : HoldState{}; } - void updateHint() { if (_drv) _drv->updateHint(); } - int width() { return _drv ? _drv->width() : 0; } - int height() { return _drv ? _drv->height() : 0; } + void begin() { + if(_drv) + _drv->begin(); + } + void setBacklight(bool on) { + if(_drv) + _drv->setBacklight(on); + } + void render(const ScreenState& st) { + if(_drv) + _drv->render(st); + } + TouchEvent readTouch() { return _drv ? _drv->readTouch() : TouchEvent {}; } + int dashboardTouch(int x, int y) { return _drv ? _drv->dashboardTouch(x, y) : -1; } + HoldState updateHold(unsigned long ms) { return _drv ? _drv->updateHold(ms) : HoldState {}; } + void updateHint(int x, int y) { + if(_drv) + _drv->updateHint(x, y); + } + int width() { return _drv ? _drv->width() : 0; } + int height() { return _drv ? _drv->height() : 0; } private: IDisplayDriver* _drv; diff --git a/libraries/KlubhausCore/src/DoorbellLogic.h b/libraries/KlubhausCore/src/DoorbellLogic.h index 1a5c174..9164c4b 100644 --- a/libraries/KlubhausCore/src/DoorbellLogic.h +++ b/libraries/KlubhausCore/src/DoorbellLogic.h @@ -24,6 +24,7 @@ public: /// Externally trigger silence (e.g. hold-to-silence gesture). void silenceAlert(); + void setScreen(ScreenID s); private: void pollTopics(); @@ -34,7 +35,6 @@ 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/libraries/KlubhausCore/src/IDisplayDriver.h b/libraries/KlubhausCore/src/IDisplayDriver.h index dfb1add..f1fb617 100644 --- a/libraries/KlubhausCore/src/IDisplayDriver.h +++ b/libraries/KlubhausCore/src/IDisplayDriver.h @@ -9,6 +9,7 @@ struct TouchEvent { struct HoldState { bool active = false; + bool started = false; bool completed = false; float progress = 0.0f; // 0.0 – 1.0 }; @@ -31,7 +32,7 @@ public: /// Track a long-press gesture; returns progress/completion. virtual HoldState updateHold(unsigned long holdMs) = 0; /// Idle hint animation (e.g. pulsing ring) while alert is showing. - virtual void updateHint() = 0; + virtual void updateHint(int x, int y) = 0; virtual int width() = 0; virtual int height() = 0;