Files
ESP32-ThermoPro-Bridge/cyd-bridge/src/display/Dashboard.cpp
T
Keith Solomon 9a3a8f9368 Add ThermoPro BLE support and dashboard display
- Implement ThermoproBLE class for handling BLE communication with ThermoPro BBQ thermometer.
- Create ThermoproReading structure to hold thermometer data.
- Develop Dashboard class for displaying thermometer readings and WiFi status on a TFT display.
- Configure display settings and touch input handling.
- Introduce SettingsManager for managing user settings stored in NVS.
- Implement WiFiManager for handling WiFi connections and captive portal setup.
- Add HTML interface for user to input WiFi credentials and ThermoPro MAC address.
- Ensure proper state management for WiFi and BLE connections in the main application loop.
2026-07-19 19:33:18 -05:00

173 lines
5.6 KiB
C++

#include "Dashboard.hpp"
#include <WiFi.h>
#include <math.h>
namespace cyd {
Dashboard::Dashboard(CYD_Display& display, SettingsManager& settings, ThermoproBLE& bleClient)
: display_(display), settings_(settings), bleClient_(bleClient) {
}
void Dashboard::begin() {
display_.init();
display_.initBacklight();
display_.setRotation(0); // Portrait 240x320
display_.fillScreen(TFT_BLACK);
display_.setTextDatum(middle_center);
drawStatusBar_();
for (size_t i = 0; i < 4; ++i) {
int x = (i % 2) * 120;
int y = 40 + (i / 2) * 110;
drawProbeTile_(i, x, y, 120, 110);
}
drawFooter_("Touch here for settings");
}
void Dashboard::update(bool force) {
if (!force && millis() - lastUpdateMillis_ < 1000) {
return;
}
lastUpdateMillis_ = millis();
ThermoproReading reading = bleClient_.getReading();
char targetUnit = settings_.getUnit();
if (force || reading.connected != lastBleConnected_ || reading.battery != lastBattery_) {
lastBleConnected_ = reading.connected;
lastBattery_ = reading.battery;
drawStatusBar_();
}
for (size_t i = 0; i < 4; ++i) {
float raw = reading.rawTemperatures[i];
bool conn = isValidTemperature(raw);
float displayTemp = conn ? convertTemperature(raw, reading.deviceUnit, targetUnit) : -9999.0f;
if (force || conn != lastConnected_[i] || fabsf(displayTemp - lastTemps_[i]) > 0.05f) {
lastConnected_[i] = conn;
lastTemps_[i] = displayTemp;
int x = (i % 2) * 120;
int y = 40 + (i / 2) * 110;
drawProbeTile_(i, x, y, 120, 110);
}
}
String footer = "IP: " + WiFi.localIP().toString();
if (WiFi.status() != WL_CONNECTED) {
footer = "AP: CYD-ThermoPro-Setup";
}
drawFooter_(footer);
}
bool Dashboard::checkTouch() {
uint16_t x, y;
if (display_.getTouch(&x, &y)) {
// The footer area is at the bottom 40 px of the screen in portrait mode.
if (y > 280) {
// Debounce: consume all touch events for 300 ms.
unsigned long start = millis();
while (display_.getTouch(&x, &y) && millis() - start < 300) {
delay(10);
}
return true;
}
}
return false;
}
void Dashboard::showMessage(const String& title, const String& line2, const String& line3) {
display_.fillScreen(TFT_BLACK);
display_.setTextColor(TFT_WHITE, TFT_BLACK);
display_.setTextDatum(top_center);
display_.setTextSize(2);
display_.drawString(title.c_str(), display_.width() / 2, 60);
display_.setTextSize(1);
if (line2.length()) {
display_.drawString(line2.c_str(), display_.width() / 2, 120);
}
if (line3.length()) {
display_.drawString(line3.c_str(), display_.width() / 2, 150);
}
display_.setTextDatum(middle_center); // restore default
}
void Dashboard::drawStatusBar_() {
int w = display_.width();
display_.fillRect(0, 0, w, 36, TFT_DARKGREY);
display_.drawLine(0, 36, w, 36, TFT_LIGHTGREY);
ThermoproReading reading = bleClient_.getReading();
// WiFi icon placeholder: small circle + text
display_.setTextColor(TFT_WHITE, TFT_DARKGREY);
display_.setTextDatum(middle_left);
display_.setTextSize(1);
display_.drawString("WiFi", 4, 18);
String wifiStatus = (WiFi.status() == WL_CONNECTED) ? "OK" : "--";
display_.drawString(wifiStatus.c_str(), 34, 18);
// BLE status
display_.setTextDatum(middle_right);
String ble = reading.connected ? "BLE OK" : "BLE --";
display_.drawString(ble.c_str(), w - 54, 18);
// Battery
String batt = String(reading.battery) + "%";
display_.drawString(batt.c_str(), w - 4, 18);
}
void Dashboard::drawProbeTile_(size_t index, int x, int y, int tileW, int tileH) {
ThermoproReading reading = bleClient_.getReading();
char targetUnit = settings_.getUnit();
float raw = reading.rawTemperatures[index];
bool connected = isValidTemperature(raw);
float temp = connected ? convertTemperature(raw, reading.deviceUnit, targetUnit) : -9999.0f;
// Background
uint16_t bgColor = (index % 2 == 0) ? TFT_DARKGREY : TFT_BLACK;
display_.fillRect(x + 1, y + 1, tileW - 2, tileH - 2, bgColor);
display_.drawRect(x, y, tileW, tileH, TFT_LIGHTGREY);
// Probe name
display_.setTextColor(TFT_WHITE, bgColor);
display_.setTextDatum(top_center);
display_.setTextSize(1);
display_.drawString(settings_.getProbeName(index).c_str(), x + tileW / 2, y + 8);
// Temperature
display_.setTextSize(2);
if (connected) {
String t = formatTemperature_(temp);
display_.drawString(t.c_str(), x + tileW / 2, y + tileH / 2 - 8);
display_.setTextSize(1);
display_.drawString((String("°") + targetUnit).c_str(), x + tileW / 2, y + tileH / 2 + 22);
} else {
display_.setTextColor(TFT_LIGHTGREY, bgColor);
display_.drawString("---", x + tileW / 2, y + tileH / 2);
}
// Connection dot
display_.fillCircle(x + tileW - 12, y + 12, 4, connected ? TFT_GREEN : TFT_RED);
}
void Dashboard::drawFooter_(const String& message) {
int y = display_.height() - 40;
display_.fillRect(0, y, display_.width(), 40, TFT_NAVY);
display_.drawLine(0, y, display_.width(), y, TFT_LIGHTGREY);
display_.setTextColor(TFT_WHITE, TFT_NAVY);
display_.setTextDatum(middle_center);
display_.setTextSize(1);
display_.drawString(message.c_str(), display_.width() / 2, y + 20);
}
String Dashboard::formatTemperature_(float temp) {
char buf[12];
snprintf(buf, sizeof(buf), "%.1f", temp);
return String(buf);
}
} // namespace cyd