118 lines
3.9 KiB
C++
118 lines
3.9 KiB
C++
/**
|
||
* @file App.cpp
|
||
* @brief xInfo 环境监控终端主应用逻辑。
|
||
*/
|
||
#include "App.h"
|
||
|
||
#include "esp_log.h"
|
||
#include "esp_netif_sntp.h"
|
||
#include "freertos/FreeRTOS.h"
|
||
#include "freertos/task.h"
|
||
#include <ctime>
|
||
|
||
// ============ 编译期常量(来自 Kconfig / menuconfig)============
|
||
static constexpr uint32_t kDisplayIntervalMs = CONFIG_DISPLAY_REFRESH_INTERVAL_MIN * 60 * 1000; // 墨水屏刷新间隔
|
||
|
||
static const char *TAG = "App";
|
||
|
||
App::App()
|
||
: wifi_(CONFIG_WIFI_SSID, CONFIG_WIFI_PASSWORD),
|
||
dht11Driver_(GPIO_NUM_5),
|
||
dashFetcher_(sensorDriver_, dht11Driver_) {}
|
||
|
||
App::~App() {}
|
||
|
||
void App::init() {
|
||
ESP_LOGI(TAG, "正在初始化 xInfo 环境监控终端...");
|
||
|
||
// 步骤 1:连接 WiFi
|
||
wifi_.connect();
|
||
|
||
// 步骤 2:SNTP 时间同步(获取网络时间用于显示准确时钟)
|
||
ESP_LOGI(TAG, "正在同步 NTP 时间(服务器: %s)...", CONFIG_NTP_SERVER);
|
||
setenv("TZ", "CST-8", 1);
|
||
tzset();
|
||
|
||
esp_sntp_config_t sntpConfig = ESP_NETIF_SNTP_DEFAULT_CONFIG(CONFIG_NTP_SERVER);
|
||
esp_netif_sntp_init(&sntpConfig);
|
||
|
||
constexpr int kMaxRetries = 3;
|
||
for (int i = 0; i < kMaxRetries; ++i) {
|
||
esp_err_t ret = esp_netif_sntp_sync_wait(pdMS_TO_TICKS(CONFIG_NTP_SYNC_TIMEOUT_SEC * 1000));
|
||
if (ret == ESP_OK) {
|
||
time_t now = time(nullptr);
|
||
struct tm timeinfo;
|
||
localtime_r(&now, &timeinfo);
|
||
char timeBuf[64];
|
||
strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", &timeinfo);
|
||
ESP_LOGI(TAG, "NTP 时间同步成功: %s", timeBuf);
|
||
break;
|
||
}
|
||
ESP_LOGW(TAG, "NTP 同步第 %d 次超时...", i + 1);
|
||
}
|
||
|
||
// 步骤 3:初始化墨水屏硬件
|
||
display_.initHardware();
|
||
|
||
// 步骤 4:初始化空气质量传感器驱动
|
||
sensorDriver_.init();
|
||
|
||
// 步骤 5:初始化 DHT11 温湿度传感器驱动
|
||
dht11Driver_.init();
|
||
}
|
||
|
||
void App::run() {
|
||
ESP_LOGI(TAG, "进入主循环...");
|
||
|
||
std::string mac = wifi_.getMac();
|
||
|
||
while (true) {
|
||
ESP_LOGI(TAG, "采集本地环境数据并刷新墨水屏...");
|
||
auto dashData = dashFetcher_.fetch();
|
||
|
||
if (dashData && dashData != lastDashData_) {
|
||
display_.beginDrawing();
|
||
|
||
// 绘制环境与网络监控界面
|
||
std::string ssid = wifi_.getSsid();
|
||
display_.drawTopBanner(ssid.empty() || ssid == "N/A" ? "Offline" : ssid);
|
||
display_.drawThermoHygrometer(*dashData); // 核心温湿度看板与舒适度
|
||
display_.drawAirQuality(*dashData); // 空气质量多维度指标(CO2/TVOC/甲醛)
|
||
display_.drawBottomInfoBar(wifi_.getIp(), mac); // 底部 IP 与 MAC 网络参数
|
||
|
||
// 定期全刷消除墨水屏残影
|
||
int maxFastRefreshes = 180 / CONFIG_DISPLAY_REFRESH_INTERVAL_MIN;
|
||
if (maxFastRefreshes < 1) maxFastRefreshes = 1;
|
||
|
||
#ifdef CONFIG_DISPLAY_BWR
|
||
std::string redContent = ssid;
|
||
bool needFullRefresh = lastRedContent_.empty()
|
||
|| (redContent != lastRedContent_)
|
||
|| (fullRefreshCounter_ >= maxFastRefreshes);
|
||
#else
|
||
bool needFullRefresh = (fullRefreshCounter_ == 0)
|
||
|| (fullRefreshCounter_ >= maxFastRefreshes);
|
||
#endif
|
||
|
||
if (needFullRefresh) {
|
||
display_.updateFullAndSleep();
|
||
#ifdef CONFIG_DISPLAY_BWR
|
||
lastRedContent_ = redContent;
|
||
#endif
|
||
fullRefreshCounter_ = 0;
|
||
} else {
|
||
display_.updateFastAndSleep();
|
||
fullRefreshCounter_++;
|
||
}
|
||
|
||
lastDashData_ = dashData;
|
||
ESP_LOGI(TAG, "墨水屏刷新完成(%s)", needFullRefresh ? "全量" : "快刷");
|
||
} else {
|
||
ESP_LOGI(TAG, "数据无变化,跳过本次墨水屏刷新");
|
||
}
|
||
|
||
// 休眠等待下一个刷新周期
|
||
vTaskDelay(pdMS_TO_TICKS(kDisplayIntervalMs));
|
||
}
|
||
}
|