#include "ui_display.h" #include "esp_log.h" #include "lvgl.h" #include "esp_lvgl_port.h" #include 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(); }