snapshot
This commit is contained in:
169
sketches/doorbell-touch-esp32-32e/Dashboard.cpp
Normal file
169
sketches/doorbell-touch-esp32-32e/Dashboard.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include "Dashboard.h"
|
||||
|
||||
// 16-bit color helpers
|
||||
#define COL_BG 0x1082 // dark charcoal
|
||||
#define COL_BAR 0x2104 // slightly lighter
|
||||
#define COL_RED 0xF800
|
||||
#define COL_ORANGE 0xFBE0
|
||||
#define COL_GREEN 0x07E0
|
||||
#define COL_CYAN 0x07FF
|
||||
#define COL_BLUE 0x001F
|
||||
#define COL_PURPLE 0x780F
|
||||
#define COL_YELLOW 0xFFE0
|
||||
#define COL_WHITE 0xFFFF
|
||||
#define COL_GRAY 0x8410
|
||||
#define COL_DARK_TILE 0x18E3
|
||||
|
||||
// Tile color themes
|
||||
static const uint16_t tileBG[] = {
|
||||
COL_RED, // LAST_ALERT — red
|
||||
COL_ORANGE, // STATS — orange
|
||||
COL_CYAN, // NETWORK — cyan
|
||||
COL_PURPLE, // MUTE — purple
|
||||
COL_DARK_TILE, // HISTORY — dark
|
||||
COL_DARK_TILE // SYSTEM — dark
|
||||
};
|
||||
|
||||
static const uint16_t tileFG[] = {
|
||||
COL_WHITE, COL_WHITE, 0x0000, COL_WHITE, COL_WHITE, COL_WHITE
|
||||
};
|
||||
|
||||
Dashboard::Dashboard(TFT_eSPI& tft)
|
||||
: _tft(tft), _sprite(&tft)
|
||||
{
|
||||
// Initialize tile metadata
|
||||
_tiles[TILE_LAST_ALERT] = { "!", "LAST ALERT", "none", "", 0, 0, true };
|
||||
_tiles[TILE_STATS] = { "#", "TODAY", "0 alerts", "", 0, 0, true };
|
||||
_tiles[TILE_NETWORK] = { "~", "NETWORK", "---", "", 0, 0, true };
|
||||
_tiles[TILE_MUTE] = { "M", "MUTE", "OFF", "", 0, 0, true };
|
||||
_tiles[TILE_HISTORY] = { ">", "HISTORY", "tap to view","", 0, 0, true };
|
||||
_tiles[TILE_SYSTEM] = { "*", "SYSTEM", "---", "", 0, 0, true };
|
||||
|
||||
for (int i = 0; i < TILE_COUNT; i++) {
|
||||
_tiles[i].bgColor = tileBG[i];
|
||||
_tiles[i].fgColor = tileFG[i];
|
||||
}
|
||||
}
|
||||
|
||||
void Dashboard::begin() {
|
||||
// Create sprite sized to one tile (reused for each)
|
||||
_sprite.createSprite(TILE_W, TILE_H);
|
||||
_sprite.setTextDatum(MC_DATUM);
|
||||
_tft.fillScreen(COL_BG);
|
||||
}
|
||||
|
||||
void Dashboard::tilePosition(TileID id, int& x, int& y) {
|
||||
int col = id % DASH_COLS;
|
||||
int row = id / DASH_COLS;
|
||||
x = DASH_MARGIN + col * (TILE_W + DASH_MARGIN);
|
||||
y = DASH_TOP_BAR + DASH_MARGIN + row * (TILE_H + DASH_MARGIN);
|
||||
}
|
||||
|
||||
void Dashboard::drawTile(TileID id) {
|
||||
TileData& t = _tiles[id];
|
||||
int tx, ty;
|
||||
tilePosition(id, tx, ty);
|
||||
|
||||
// Draw into sprite (off-screen)
|
||||
_sprite.fillSprite(t.bgColor);
|
||||
|
||||
// Rounded corner effect — draw border pixels
|
||||
_sprite.drawRoundRect(0, 0, TILE_W, TILE_H, 8, COL_GRAY);
|
||||
|
||||
// Icon — large character at top
|
||||
_sprite.setTextColor(t.fgColor, t.bgColor);
|
||||
_sprite.setTextFont(4);
|
||||
_sprite.setTextSize(2);
|
||||
_sprite.setTextDatum(TC_DATUM);
|
||||
_sprite.drawString(t.icon, TILE_W / 2, 8);
|
||||
|
||||
// Label — below icon
|
||||
_sprite.setTextSize(1);
|
||||
_sprite.setTextFont(2);
|
||||
_sprite.setTextDatum(MC_DATUM);
|
||||
_sprite.drawString(t.label, TILE_W / 2, TILE_H / 2 + 5);
|
||||
|
||||
// Value — bottom area
|
||||
_sprite.setTextFont(2);
|
||||
_sprite.setTextDatum(BC_DATUM);
|
||||
_sprite.drawString(t.value, TILE_W / 2, TILE_H - 25);
|
||||
|
||||
// Sub text — very bottom
|
||||
if (strlen(t.sub) > 0) {
|
||||
_sprite.setTextFont(1);
|
||||
_sprite.setTextDatum(BC_DATUM);
|
||||
_sprite.drawString(t.sub, TILE_W / 2, TILE_H - 8);
|
||||
}
|
||||
|
||||
// Push sprite to screen in one operation — no flicker
|
||||
_sprite.pushSprite(tx, ty);
|
||||
|
||||
t.dirty = false;
|
||||
}
|
||||
|
||||
void Dashboard::drawTopBar(const char* time, int rssi, bool wifiOk) {
|
||||
_tft.fillRect(0, 0, 480, DASH_TOP_BAR, COL_BAR);
|
||||
|
||||
_tft.setTextColor(COL_WHITE, COL_BAR);
|
||||
_tft.setTextFont(4);
|
||||
_tft.setTextSize(1);
|
||||
|
||||
// Title — left
|
||||
_tft.setTextDatum(ML_DATUM);
|
||||
_tft.drawString("KLUBHAUS ALERT", DASH_MARGIN, DASH_TOP_BAR / 2);
|
||||
|
||||
// Time — right
|
||||
_tft.setTextDatum(MR_DATUM);
|
||||
_tft.drawString(time, 470, DASH_TOP_BAR / 2);
|
||||
|
||||
// WiFi indicator — signal bars
|
||||
int bars = 0;
|
||||
if (wifiOk) {
|
||||
if (rssi > -50) bars = 4;
|
||||
else if (rssi > -60) bars = 3;
|
||||
else if (rssi > -70) bars = 2;
|
||||
else bars = 1;
|
||||
}
|
||||
|
||||
int barX = 370;
|
||||
int barW = 6;
|
||||
int barGap = 3;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int barH = 6 + i * 5;
|
||||
int barY = DASH_TOP_BAR - 8 - barH;
|
||||
uint16_t col = (i < bars) ? COL_GREEN : COL_GRAY;
|
||||
_tft.fillRect(barX + i * (barW + barGap), barY, barW, barH, col);
|
||||
}
|
||||
}
|
||||
|
||||
void Dashboard::drawAll() {
|
||||
drawTopBar("--:--", 0, false);
|
||||
for (int i = 0; i < TILE_COUNT; i++) {
|
||||
drawTile((TileID)i);
|
||||
}
|
||||
}
|
||||
|
||||
void Dashboard::updateTile(TileID id, const char* value, const char* sub) {
|
||||
TileData& t = _tiles[id];
|
||||
strncpy(t.value, value, 31);
|
||||
t.value[31] = '\0';
|
||||
if (sub) {
|
||||
strncpy(t.sub, sub, 31);
|
||||
t.sub[31] = '\0';
|
||||
}
|
||||
t.dirty = true;
|
||||
drawTile(id); // immediate redraw of just this tile
|
||||
}
|
||||
|
||||
int Dashboard::handleTouch(int x, int y) {
|
||||
for (int i = 0; i < TILE_COUNT; i++) {
|
||||
int tx, ty;
|
||||
tilePosition((TileID)i, tx, ty);
|
||||
if (x >= tx && x < tx + TILE_W &&
|
||||
y >= ty && y < ty + TILE_H) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
53
sketches/doorbell-touch-esp32-32e/Dashboard.h
Normal file
53
sketches/doorbell-touch-esp32-32e/Dashboard.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
#include <TFT_eSPI.h>
|
||||
|
||||
// Grid layout constants
|
||||
#define DASH_COLS 3
|
||||
#define DASH_ROWS 2
|
||||
#define DASH_MARGIN 8
|
||||
#define DASH_TOP_BAR 40
|
||||
|
||||
// Tile dimensions (calculated for 480x320)
|
||||
#define TILE_W ((480 - (DASH_COLS + 1) * DASH_MARGIN) / DASH_COLS) // ~148
|
||||
#define TILE_H ((320 - DASH_TOP_BAR - (DASH_ROWS + 1) * DASH_MARGIN) / DASH_ROWS) // ~128
|
||||
|
||||
// Tile IDs
|
||||
enum TileID : uint8_t {
|
||||
TILE_LAST_ALERT = 0,
|
||||
TILE_STATS,
|
||||
TILE_NETWORK,
|
||||
TILE_MUTE,
|
||||
TILE_HISTORY,
|
||||
TILE_SYSTEM,
|
||||
TILE_COUNT
|
||||
};
|
||||
|
||||
struct TileData {
|
||||
const char* icon; // emoji/symbol character
|
||||
const char* label; // tile name
|
||||
char value[32]; // dynamic value text
|
||||
char sub[32]; // secondary line
|
||||
uint16_t bgColor;
|
||||
uint16_t fgColor;
|
||||
bool dirty; // needs redraw
|
||||
};
|
||||
|
||||
class Dashboard {
|
||||
public:
|
||||
Dashboard(TFT_eSPI& tft);
|
||||
|
||||
void begin();
|
||||
void drawAll();
|
||||
void drawTopBar(const char* time, int rssi, bool wifiOk);
|
||||
void updateTile(TileID id, const char* value, const char* sub = nullptr);
|
||||
int handleTouch(int x, int y); // returns TileID or -1
|
||||
|
||||
private:
|
||||
TFT_eSPI& _tft;
|
||||
TFT_eSprite _sprite;
|
||||
TileData _tiles[TILE_COUNT];
|
||||
|
||||
void drawTile(TileID id);
|
||||
void tilePosition(TileID id, int& x, int& y);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user