Files
iot-bedroom-environment-con…/components/lvgl_st7735s_use/ui_display.c
Wang Beihong a0febb1e5b feat: 智能家居控制系统 v1.0 初始版本
- 环境监测:温湿度/光照/空气质量传感器采集
- 智能控制:时间段/降温/通风三种自动模式
- 闹钟系统:3个闹钟+温和唤醒功能
- 远程控制:MQTT双向通信
- 本地显示:LVGL图形界面
- 双MCU架构,FreeRTOS 10任务并行
- 完整的1250行README文档
2026-02-07 23:04:28 +08:00

259 lines
9.1 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "ui_display.h"
#include "esp_log.h"
#include "lvgl.h"
#include "esp_lvgl_port.h"
#include <time.h>
static const char *TAG = "ui_display";
// 全局变量用于存储传感器数据标签
static lv_obj_t *temp_label = NULL;
static lv_obj_t *humid_label = NULL;
static lv_obj_t *lux_label = NULL;
static lv_obj_t *air_quality_label = NULL; // 新增空气质量标签
/* Time page objects */
static lv_obj_t *time_container = NULL;
static lv_obj_t *date_label = NULL;
static lv_obj_t *time_label = NULL;
static bool time_page_visible = false;
/**
* @brief 初始化UI界面
*
* 该函数负责创建LVGL的用户界面元素用于显示传感器数据
* 优化布局以适应非触摸屏设备,所有内容在一个屏幕内显示
*/
void ui_display_init(void)
{
// 获取当前活动屏幕对象
lv_obj_t *scr = lv_scr_act();
/* 任务锁定 */
lvgl_port_lock(0);
/* 设置屏幕背景为白色 */
lv_obj_set_style_bg_color(scr, lv_color_white(), 0);
lv_obj_set_style_bg_opa(scr, LV_OPA_COVER, 0);
/* 创建标题标签 */
lv_obj_t *title_label = lv_label_create(scr);
lv_label_set_text(title_label, "IoT Home Monitor");
lv_obj_set_style_text_color(title_label, lv_palette_main(LV_PALETTE_BLUE), 0);
lv_obj_set_style_text_font(title_label, &lv_font_unscii_8, 0);
lv_obj_align(title_label, LV_ALIGN_TOP_MID, 0, 2); // 调整标题位置
/* 创建温度标签 */
temp_label = lv_label_create(scr);
lv_label_set_text(temp_label, "Temp: --.- C");
lv_obj_set_style_text_color(temp_label, lv_color_black(), 0);
lv_obj_set_style_text_font(temp_label, &lv_font_unscii_8, 0);
lv_obj_align(temp_label, LV_ALIGN_TOP_LEFT, 3, 20); // 调整位置
/* 创建湿度标签 */
humid_label = lv_label_create(scr);
lv_label_set_text(humid_label, "Humidity: --.- %");
lv_obj_set_style_text_color(humid_label, lv_color_black(), 0);
lv_obj_set_style_text_font(humid_label, &lv_font_unscii_8, 0);
lv_obj_align(humid_label, LV_ALIGN_TOP_LEFT, 3, 35); // 调整位置
/* 创建光照标签 */
lux_label = lv_label_create(scr);
lv_label_set_text(lux_label, "Light: --.- lux");
lv_obj_set_style_text_color(lux_label, lv_color_black(), 0);
lv_obj_set_style_text_font(lux_label, &lv_font_unscii_8, 0);
lv_obj_align(lux_label, LV_ALIGN_TOP_LEFT, 3, 50); // 调整位置
/* 创建空气质量标签 */
air_quality_label = lv_label_create(scr);
lv_label_set_text(air_quality_label, "IAQ : --.- Index");
lv_obj_set_style_text_color(air_quality_label, lv_color_black(), 0);
lv_obj_set_style_text_font(air_quality_label, &lv_font_unscii_8, 0);
lv_obj_align(air_quality_label, LV_ALIGN_TOP_LEFT, 3, 65); // 调整位置
/* 任务解锁 */
lvgl_port_unlock();
// 创建时间页面(初始隐藏)
lvgl_port_lock(0);
time_container = lv_obj_create(lv_scr_act());
lv_obj_set_size(time_container, lv_pct(100), lv_pct(100));
lv_obj_set_style_bg_color(time_container, lv_color_white(), 0);
lv_obj_set_style_bg_opa(time_container, LV_OPA_COVER, 0);
date_label = lv_label_create(time_container);
lv_label_set_text(date_label, "---- ---- -- ---");
lv_obj_set_style_text_color(date_label, lv_color_black(), 0);
lv_obj_set_style_text_font(date_label, &lv_font_unscii_8, 0);
lv_obj_align(date_label, LV_ALIGN_TOP_MID, 0, 6);
time_label = lv_label_create(time_container);
lv_label_set_text(time_label, "--:--:--");
lv_obj_set_style_text_color(time_label, lv_color_black(), 0);
lv_obj_set_style_text_font(time_label, &lv_font_unscii_16, 0);
lv_obj_align(time_label, LV_ALIGN_CENTER, 0, 12);
// 默认显示时间页面,隐藏传感器页面
lv_obj_clear_flag(time_container, LV_OBJ_FLAG_HIDDEN);
if (temp_label) lv_obj_add_flag(temp_label, LV_OBJ_FLAG_HIDDEN);
if (humid_label) lv_obj_add_flag(humid_label, LV_OBJ_FLAG_HIDDEN);
if (lux_label) lv_obj_add_flag(lux_label, LV_OBJ_FLAG_HIDDEN);
if (air_quality_label) lv_obj_add_flag(air_quality_label, LV_OBJ_FLAG_HIDDEN);
time_page_visible = true;
lvgl_port_unlock();
}
/**
* @brief 更新传感器数据显示
*
* 该函数用于更新LVGL界面上的传感器数据
*
* @param temperature 温度值(°C)-1.0表示无效
* @param humidity 湿度值(%)-1.0表示无效
* @param lux 光照强度(lx)-1.0表示无效
* @param ppm 空气中有害气体浓度(ppm)
* @param quality_level 空气质量等级描述
*/
void ui_update_sensor_data(float temperature, float humidity, float lux, float ppm, const char* quality_level)
{
if (temp_label != NULL && humid_label != NULL && lux_label != NULL && air_quality_label != NULL)
{
/* 任务锁定 */
lvgl_port_lock(0);
// 更新温度标签 - 缩短文本以节省空间
if (temperature >= -0.5) // -1.0表示无效
{
char temp_str[32];
snprintf(temp_str, sizeof(temp_str), "Temp: %.2f C", temperature);
lv_label_set_text(temp_label, temp_str);
}
else
{
lv_label_set_text(temp_label, "Temp: Invalid");
}
// 更新湿度标签 - 缩短文本以节省空间
if (humidity >= -0.5) // -1.0表示无效
{
char humid_str[32];
snprintf(humid_str, sizeof(humid_str), "Humidity: %.2f %%", humidity);
lv_label_set_text(humid_label, humid_str);
}
else
{
lv_label_set_text(humid_label, "Humidity: Invalid");
}
// 更新光照标签 - 缩短文本以节省空间
if (lux >= -0.5) // -1.0表示无效
{
char lux_str[32];
snprintf(lux_str, sizeof(lux_str), "Light: %.2f lx", lux);
lv_label_set_text(lux_label, lux_str);
}
else
{
lv_label_set_text(lux_label, "Light: Invalid");
}
// 更新空气质量标签 - 缩短文本以节省空间
if (ppm >= 0) // 空气质量值有效
{
char ppm_str[32];
snprintf(ppm_str, sizeof(ppm_str), "IAQ : %.2f Index", ppm);
// 根据空气质量等级更改颜色
lv_color_t color = lv_color_black(); // 默认黑色
if (ppm <= 20.0f) {
color = lv_color_make(0, 128, 0); // 绿色 - 空气质量优秀
} else if (ppm <= 100.0f) {
color = lv_color_make(0, 0, 0); // 黑色 - 空气质量良好
} else if (ppm <= 300.0f) {
color = lv_color_make(255, 165, 0); // 橙色 - 轻度污染
} else {
color = lv_color_make(255, 0, 0); // 红色 - 中重度污染
}
lv_label_set_text(air_quality_label, ppm_str);
lv_obj_set_style_text_color(air_quality_label, color, 0);
}
else
{
lv_label_set_text(air_quality_label, "IAQ : Invalid");
lv_obj_set_style_text_color(air_quality_label, lv_color_black(), 0);
}
/* 任务解锁 */
lvgl_port_unlock();
}
}
/* Show time page */
void ui_show_time_page(void)
{
lvgl_port_lock(0);
if (time_container)
{
lv_obj_clear_flag(time_container, LV_OBJ_FLAG_HIDDEN);
}
if (temp_label) lv_obj_add_flag(temp_label, LV_OBJ_FLAG_HIDDEN);
if (humid_label) lv_obj_add_flag(humid_label, LV_OBJ_FLAG_HIDDEN);
if (lux_label) lv_obj_add_flag(lux_label, LV_OBJ_FLAG_HIDDEN);
if (air_quality_label) lv_obj_add_flag(air_quality_label, LV_OBJ_FLAG_HIDDEN);
time_page_visible = true;
lvgl_port_unlock();
}
/* Show sensor page */
void ui_show_sensor_page(void)
{
lvgl_port_lock(0);
if (time_container)
{
lv_obj_add_flag(time_container, LV_OBJ_FLAG_HIDDEN);
}
if (temp_label) lv_obj_clear_flag(temp_label, LV_OBJ_FLAG_HIDDEN);
if (humid_label) lv_obj_clear_flag(humid_label, LV_OBJ_FLAG_HIDDEN);
if (lux_label) lv_obj_clear_flag(lux_label, LV_OBJ_FLAG_HIDDEN);
if (air_quality_label) lv_obj_clear_flag(air_quality_label, LV_OBJ_FLAG_HIDDEN);
time_page_visible = false;
lvgl_port_unlock();
}
/* Toggle between pages */
void ui_toggle_page(void)
{
if (time_page_visible)
ui_show_sensor_page();
else
ui_show_time_page();
}
/* Update time label (call periodically) */
void ui_time_update(void)
{
if (!time_page_visible || time_label == NULL)
return;
time_t now = time(NULL);
struct tm tm_now;
localtime_r(&now, &tm_now);
char date_buf[64];
char time_buf[32];
char weekday_buf[32];
// 年月日和星期合并为一行
strftime(date_buf, sizeof(date_buf), "%Y-%m-%d", &tm_now);
const char *weekdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
snprintf(date_buf + strlen(date_buf), sizeof(date_buf) - strlen(date_buf), " %s", weekdays[tm_now.tm_wday]);
// 时分秒
strftime(time_buf, sizeof(time_buf), "%H:%M:%S", &tm_now);
lvgl_port_lock(0);
lv_label_set_text(date_label, date_buf);
lv_label_set_text(time_label, time_buf);
lvgl_port_unlock();
}