feat: add status screen with system info display
This commit is contained in:
@@ -138,6 +138,12 @@ void DisplayDriverTFT::render(const ScreenState& st) {
|
|||||||
_needsRedraw = false;
|
_needsRedraw = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ScreenID::STATUS:
|
||||||
|
if(_needsRedraw) {
|
||||||
|
drawStatus(st);
|
||||||
|
_needsRedraw = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ScreenID::OFF:
|
case ScreenID::OFF:
|
||||||
if(_needsRedraw) {
|
if(_needsRedraw) {
|
||||||
_tft.fillScreen(TFT_BLACK);
|
_tft.fillScreen(TFT_BLACK);
|
||||||
@@ -194,6 +200,22 @@ void DisplayDriverTFT::drawAlert(const ScreenState& st) {
|
|||||||
_tft.fillScreen(bg);
|
_tft.fillScreen(bg);
|
||||||
_tft.setTextColor(TFT_WHITE, bg);
|
_tft.setTextColor(TFT_WHITE, bg);
|
||||||
|
|
||||||
|
// Progressive fill hint - draws dark overlay from bottom rising up
|
||||||
|
if(_alertTouchDown) {
|
||||||
|
uint32_t touchElapsed = millis() - _alertTouchStartMs;
|
||||||
|
float progress = (float)touchElapsed / (float)ALERT_FILL_DURATION_MS;
|
||||||
|
if(progress > 1.0f)
|
||||||
|
progress = 1.0f;
|
||||||
|
|
||||||
|
int dispH = _tft.height();
|
||||||
|
int fillHeight = (int)(dispH * progress);
|
||||||
|
if(fillHeight > 0) {
|
||||||
|
// Draw dark overlay from bottom
|
||||||
|
uint16_t overlay = _tft.color565(80, 0, 0); // Dark red
|
||||||
|
_tft.fillRect(0, dispH - fillHeight, _tft.width(), fillHeight, overlay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setTitleFont();
|
setTitleFont();
|
||||||
_tft.setCursor(10, 28); // y=28 baseline for ~18px font
|
_tft.setCursor(10, 28); // y=28 baseline for ~18px font
|
||||||
_tft.print(st.alertTitle.length() > 0 ? st.alertTitle : "ALERT");
|
_tft.print(st.alertTitle.length() > 0 ? st.alertTitle : "ALERT");
|
||||||
@@ -257,6 +279,61 @@ void DisplayDriverTFT::drawDashboard(const ScreenState& st) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayDriverTFT::drawStatus(const ScreenState& st) {
|
||||||
|
int dispW = _tft.width();
|
||||||
|
int dispH = _tft.height();
|
||||||
|
|
||||||
|
_tft.fillScreen(TFT_BLACK);
|
||||||
|
|
||||||
|
// Header
|
||||||
|
_tft.fillRect(0, 0, dispW, STYLE_HEADER_HEIGHT, 0x1A1A);
|
||||||
|
_tft.setTextSize(1);
|
||||||
|
_tft.setTextColor(TFT_WHITE);
|
||||||
|
_tft.setCursor(5, 20);
|
||||||
|
_tft.print("STATUS");
|
||||||
|
|
||||||
|
// Back button in lower right
|
||||||
|
_tft.setCursor(dispW - 60, dispH - 20);
|
||||||
|
_tft.print("[BACK]");
|
||||||
|
|
||||||
|
// Status info
|
||||||
|
setBodyFont();
|
||||||
|
int y = STYLE_HEADER_HEIGHT + 20;
|
||||||
|
|
||||||
|
// WiFi
|
||||||
|
_tft.setCursor(10, y);
|
||||||
|
_tft.printf("WiFi: %s", st.wifiSsid.length() > 0 ? st.wifiSsid.c_str() : "N/A");
|
||||||
|
y += 20;
|
||||||
|
|
||||||
|
_tft.setCursor(10, y);
|
||||||
|
_tft.printf("RSSI: %d dBm", st.wifiRssi);
|
||||||
|
y += 20;
|
||||||
|
|
||||||
|
_tft.setCursor(10, y);
|
||||||
|
_tft.printf("IP: %s", st.ipAddr.length() > 0 ? st.ipAddr.c_str() : "N/A");
|
||||||
|
y += 30;
|
||||||
|
|
||||||
|
// Uptime
|
||||||
|
uint32_t upSec = st.uptimeMs / 1000;
|
||||||
|
uint32_t upMin = upSec / 60;
|
||||||
|
uint32_t upHr = upMin / 60;
|
||||||
|
upSec = upSec % 60;
|
||||||
|
upMin = upMin % 60;
|
||||||
|
_tft.setCursor(10, y);
|
||||||
|
_tft.printf("Uptime: %02lu:%02lu:%02lu", upHr, upMin, upSec);
|
||||||
|
y += 20;
|
||||||
|
|
||||||
|
// Heap
|
||||||
|
_tft.setCursor(10, y);
|
||||||
|
_tft.printf("Heap: %d bytes", ESP.getFreeHeap());
|
||||||
|
y += 20;
|
||||||
|
|
||||||
|
// Last poll
|
||||||
|
uint32_t pollAgo = (millis() - st.lastPollMs) / 1000;
|
||||||
|
_tft.setCursor(10, y);
|
||||||
|
_tft.printf("Last poll: %lu sec ago", pollAgo);
|
||||||
|
}
|
||||||
|
|
||||||
// ── Touch ───────────────────────────────────────────────────
|
// ── Touch ───────────────────────────────────────────────────
|
||||||
|
|
||||||
TouchEvent DisplayDriverTFT::readTouch() {
|
TouchEvent DisplayDriverTFT::readTouch() {
|
||||||
@@ -317,6 +394,15 @@ TouchEvent DisplayDriverTFT::readTouch() {
|
|||||||
|
|
||||||
// Track previous state for next call
|
// Track previous state for next call
|
||||||
_touchWasPressed = touched;
|
_touchWasPressed = touched;
|
||||||
|
|
||||||
|
// Track alert touch for progressive hint
|
||||||
|
if(evt.pressed) {
|
||||||
|
_alertTouchDown = true;
|
||||||
|
_alertTouchStartMs = millis();
|
||||||
|
} else if(evt.released) {
|
||||||
|
_alertTouchDown = false;
|
||||||
|
}
|
||||||
|
|
||||||
return evt;
|
return evt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ private:
|
|||||||
void drawBoot(const ScreenState& st);
|
void drawBoot(const ScreenState& st);
|
||||||
void drawAlert(const ScreenState& st);
|
void drawAlert(const ScreenState& st);
|
||||||
void drawDashboard(const ScreenState& st);
|
void drawDashboard(const ScreenState& st);
|
||||||
|
void drawStatus(const ScreenState& st);
|
||||||
|
|
||||||
TFT_eSPI _tft;
|
TFT_eSPI _tft;
|
||||||
|
|
||||||
@@ -40,6 +41,11 @@ private:
|
|||||||
BootStage _lastBootStage = BootStage::SPLASH;
|
BootStage _lastBootStage = BootStage::SPLASH;
|
||||||
bool _needsRedraw = true;
|
bool _needsRedraw = true;
|
||||||
|
|
||||||
|
// Touch hint for alert - progressive fill from bottom
|
||||||
|
bool _alertTouchDown = false;
|
||||||
|
uint32_t _alertTouchStartMs = 0;
|
||||||
|
static constexpr uint32_t ALERT_FILL_DURATION_MS = 3000;
|
||||||
|
|
||||||
// Touch tracking for press/release detection
|
// Touch tracking for press/release detection
|
||||||
bool _touchWasPressed = false;
|
bool _touchWasPressed = false;
|
||||||
int _touchDownX = -1;
|
int _touchDownX = -1;
|
||||||
|
|||||||
2
justfile
2
justfile
@@ -125,11 +125,13 @@ install-libs-shared:
|
|||||||
install: install-libs-shared
|
install: install-libs-shared
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
./boards/{{BOARD}}/install.sh
|
./boards/{{BOARD}}/install.sh
|
||||||
|
arduino-cli core install esp32:esp32
|
||||||
|
|
||||||
# Clean build artifacts
|
# Clean build artifacts
|
||||||
clean:
|
clean:
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
rm -rf vendor/
|
rm -rf vendor/
|
||||||
|
rm -rf .cache/
|
||||||
rm -rf boards/esp32-32e/build
|
rm -rf boards/esp32-32e/build
|
||||||
rm -rf boards/esp32-32e-4/build
|
rm -rf boards/esp32-32e-4/build
|
||||||
rm -rf boards/esp32-s3-lcd-43/build
|
rm -rf boards/esp32-s3-lcd-43/build
|
||||||
|
|||||||
@@ -354,6 +354,18 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle STATUS screen back button (lower right corner)
|
||||||
|
if(_state.screen == ScreenID::STATUS) {
|
||||||
|
int dispW = _display->width();
|
||||||
|
int dispH = _display->height();
|
||||||
|
// Back button area: lower right (dispW-60 to dispW, dispH-30 to dispH)
|
||||||
|
if(evt.x >= dispW - 60 && evt.y >= dispH - 30) {
|
||||||
|
Serial.printf("[%lu] [TOUCH] STATUS → DASHBOARD (back)\n", millis());
|
||||||
|
setScreen(ScreenID::DASHBOARD);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Draw debug crosshair at touch point
|
// Draw debug crosshair at touch point
|
||||||
#ifdef DEBUG_MODE
|
#ifdef DEBUG_MODE
|
||||||
if(_state.screen == ScreenID::DASHBOARD) {
|
if(_state.screen == ScreenID::DASHBOARD) {
|
||||||
@@ -380,7 +392,7 @@ int DoorbellLogic::handleTouch(const TouchEvent& evt) {
|
|||||||
silenceAlert();
|
silenceAlert();
|
||||||
break;
|
break;
|
||||||
case TileAction::STATUS:
|
case TileAction::STATUS:
|
||||||
heartbeat();
|
setScreen(ScreenID::STATUS);
|
||||||
break;
|
break;
|
||||||
case TileAction::REBOOT:
|
case TileAction::REBOOT:
|
||||||
flushStatus("REBOOT (tile)");
|
flushStatus("REBOOT (tile)");
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
enum class DeviceState { BOOTED, SILENT, ALERTING, SILENCED };
|
enum class DeviceState { BOOTED, SILENT, ALERTING, SILENCED };
|
||||||
|
|
||||||
enum class ScreenID { BOOT, OFF, ALERT, DASHBOARD };
|
enum class ScreenID { BOOT, OFF, ALERT, DASHBOARD, STATUS };
|
||||||
|
|
||||||
enum class BootStage { SPLASH, INIT_DISPLAY, INIT_NETWORK, CONNECTING_WIFI, READY, DONE };
|
enum class BootStage { SPLASH, INIT_DISPLAY, INIT_NETWORK, CONNECTING_WIFI, READY, DONE };
|
||||||
|
|
||||||
@@ -94,6 +94,8 @@ inline const char* screenIdStr(ScreenID s) {
|
|||||||
return "ALERT";
|
return "ALERT";
|
||||||
case ScreenID::DASHBOARD:
|
case ScreenID::DASHBOARD:
|
||||||
return "DASHBOARD";
|
return "DASHBOARD";
|
||||||
|
case ScreenID::STATUS:
|
||||||
|
return "STATUS";
|
||||||
}
|
}
|
||||||
return "?";
|
return "?";
|
||||||
}
|
}
|
||||||
|
|||||||
2
vendor/.gitignore
vendored
2
vendor/.gitignore
vendored
@@ -1,2 +0,0 @@
|
|||||||
*
|
|
||||||
!.gitignore
|
|
||||||
1
vendor/esp32-s3-lcd-43/LovyanGFX
vendored
1
vendor/esp32-s3-lcd-43/LovyanGFX
vendored
Submodule vendor/esp32-s3-lcd-43/LovyanGFX deleted from 42998359d8
Reference in New Issue
Block a user