diff --git a/components/lvgl_st7735s_use/lvgl_st7735s_use.c b/components/lvgl_st7735s_use/lvgl_st7735s_use.c index 932266d..3943ded 100644 --- a/components/lvgl_st7735s_use/lvgl_st7735s_use.c +++ b/components/lvgl_st7735s_use/lvgl_st7735s_use.c @@ -205,7 +205,7 @@ static void app_main_display(void) lv_label_set_long_mode(s_center_label, LV_LABEL_LONG_WRAP); lv_obj_set_size(s_center_label, EXAMPLE_LCD_H_RES - 6, EXAMPLE_LCD_V_RES - 6); lv_obj_set_style_text_color(s_center_label, lv_color_black(), 0); - lv_obj_set_style_text_font(s_center_label, &lv_font_unscii_16, 0); + lv_obj_set_style_text_font(s_center_label, &lv_font_montserrat_14, 0); lv_obj_set_style_text_align(s_center_label, LV_TEXT_ALIGN_CENTER, 0); lv_obj_set_style_pad_all(s_center_label, 0, 0); lv_obj_align(s_center_label, LV_ALIGN_CENTER, 0, 0); diff --git a/components/ui/.eez-project-build b/components/ui/.eez-project-build new file mode 100644 index 0000000..9998c0f --- /dev/null +++ b/components/ui/.eez-project-build @@ -0,0 +1,16 @@ +{ + "files": [ + "actions.h", + "fonts.h", + "images.c", + "images.h", + "screens.c", + "screens.h", + "structs.h", + "styles.c", + "styles.h", + "ui.c", + "ui.h", + "vars.h" + ] +} \ No newline at end of file diff --git a/components/ui/CMakeLists.txt b/components/ui/CMakeLists.txt new file mode 100644 index 0000000..4415dd8 --- /dev/null +++ b/components/ui/CMakeLists.txt @@ -0,0 +1,5 @@ +idf_component_register( + SRC_DIRS "." + INCLUDE_DIRS "." + REQUIRES lvgl esp_lvgl_port +) \ No newline at end of file diff --git a/components/ui/actions.h b/components/ui/actions.h new file mode 100644 index 0000000..5e0df4a --- /dev/null +++ b/components/ui/actions.h @@ -0,0 +1,14 @@ +#ifndef EEZ_LVGL_UI_EVENTS_H +#define EEZ_LVGL_UI_EVENTS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*EEZ_LVGL_UI_EVENTS_H*/ \ No newline at end of file diff --git a/components/ui/fonts.h b/components/ui/fonts.h new file mode 100644 index 0000000..8f96d72 --- /dev/null +++ b/components/ui/fonts.h @@ -0,0 +1,24 @@ +#ifndef EEZ_LVGL_UI_FONTS_H +#define EEZ_LVGL_UI_FONTS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef EXT_FONT_DESC_T +#define EXT_FONT_DESC_T +typedef struct _ext_font_desc_t { + const char *name; + const void *font_ptr; +} ext_font_desc_t; +#endif + +extern ext_font_desc_t fonts[]; + +#ifdef __cplusplus +} +#endif + +#endif /*EEZ_LVGL_UI_FONTS_H*/ \ No newline at end of file diff --git a/components/ui/images.c b/components/ui/images.c new file mode 100644 index 0000000..38d810c --- /dev/null +++ b/components/ui/images.c @@ -0,0 +1,5 @@ +#include "images.h" + +const ext_img_desc_t images[1] = { + 0 +}; \ No newline at end of file diff --git a/components/ui/images.h b/components/ui/images.h new file mode 100644 index 0000000..3aa52ad --- /dev/null +++ b/components/ui/images.h @@ -0,0 +1,24 @@ +#ifndef EEZ_LVGL_UI_IMAGES_H +#define EEZ_LVGL_UI_IMAGES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef EXT_IMG_DESC_T +#define EXT_IMG_DESC_T +typedef struct _ext_img_desc_t { + const char *name; + const lv_img_dsc_t *img_dsc; +} ext_img_desc_t; +#endif + +extern const ext_img_desc_t images[1]; + +#ifdef __cplusplus +} +#endif + +#endif /*EEZ_LVGL_UI_IMAGES_H*/ \ No newline at end of file diff --git a/components/ui/screens.c b/components/ui/screens.c new file mode 100644 index 0000000..e2f0e1b --- /dev/null +++ b/components/ui/screens.c @@ -0,0 +1,197 @@ +#include + +#include "screens.h" +#include "images.h" +#include "fonts.h" +#include "actions.h" +#include "vars.h" +#include "styles.h" +#include "ui.h" + +#include + +objects_t objects; + +// +// Event handlers +// + +lv_obj_t *tick_value_change_obj; + +static void event_handler_cb_main_obj1(lv_event_t *e) { + lv_event_code_t event = lv_event_get_code(e); + if (event == LV_EVENT_VALUE_CHANGED) { + lv_obj_t *ta = lv_event_get_target_obj(e); + if (tick_value_change_obj != ta) { + int32_t value = lv_arc_get_value(ta); + set_var_air_temperature_int(value); + } + } +} + +// +// Screens +// + +void create_screen_main() { + lv_obj_t *obj = lv_obj_create(0); + objects.main = obj; + lv_obj_set_pos(obj, 0, 0); + lv_obj_set_size(obj, 160, 80); + lv_obj_set_style_bg_color(obj, lv_color_hex(0xff000000), LV_PART_MAIN | LV_STATE_DEFAULT); + { + lv_obj_t *parent_obj = obj; + { + lv_obj_t *obj = lv_label_create(parent_obj); + objects.obj0 = obj; + lv_obj_set_pos(obj, 0, 0); + lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_set_style_text_color(obj, lv_color_hex(0xffffffff), LV_PART_MAIN | LV_STATE_DEFAULT); + lv_obj_set_style_text_font(obj, &lv_font_montserrat_28, LV_PART_MAIN | LV_STATE_DEFAULT); + lv_label_set_text(obj, "Temp"); + } + { + lv_obj_t *obj = lv_arc_create(parent_obj); + objects.obj1 = obj; + lv_obj_set_pos(obj, 92, 10); + lv_obj_set_size(obj, 58, 57); + lv_arc_set_range(obj, -5, 44); + lv_obj_add_event_cb(obj, event_handler_cb_main_obj1, LV_EVENT_ALL, 0); + } + { + lv_obj_t *obj = lv_label_create(parent_obj); + objects.obj2 = obj; + lv_obj_set_pos(obj, 25, 42); + lv_obj_set_size(obj, LV_SIZE_CONTENT, LV_SIZE_CONTENT); + lv_obj_set_style_text_font(obj, &lv_font_montserrat_32, LV_PART_MAIN | LV_STATE_CHECKED); + lv_obj_set_style_text_color(obj, lv_color_hex(0xffd40808), LV_PART_MAIN | LV_STATE_CHECKED); + lv_label_set_text(obj, ""); + } + } + + tick_screen_main(); +} + +void tick_screen_main() { + { + int32_t new_val = get_var_air_temperature_int(); + int32_t cur_val = lv_arc_get_value(objects.obj1); + if (new_val != cur_val) { + tick_value_change_obj = objects.obj1; + lv_arc_set_value(objects.obj1, new_val); + tick_value_change_obj = NULL; + } + } + { + const char *new_val = get_var_air_temperature(); + const char *cur_val = lv_label_get_text(objects.obj2); + if (strcmp(new_val, cur_val) != 0) { + tick_value_change_obj = objects.obj2; + lv_label_set_text(objects.obj2, new_val); + tick_value_change_obj = NULL; + } + } +} + +typedef void (*tick_screen_func_t)(); +tick_screen_func_t tick_screen_funcs[] = { + tick_screen_main, +}; +void tick_screen(int screen_index) { + tick_screen_funcs[screen_index](); +} +void tick_screen_by_id(enum ScreensEnum screenId) { + tick_screen_funcs[screenId - 1](); +} + +// +// Fonts +// + +ext_font_desc_t fonts[] = { +#if LV_FONT_MONTSERRAT_8 + { "MONTSERRAT_8", &lv_font_montserrat_8 }, +#endif +#if LV_FONT_MONTSERRAT_10 + { "MONTSERRAT_10", &lv_font_montserrat_10 }, +#endif +#if LV_FONT_MONTSERRAT_12 + { "MONTSERRAT_12", &lv_font_montserrat_12 }, +#endif +#if LV_FONT_MONTSERRAT_14 + { "MONTSERRAT_14", &lv_font_montserrat_14 }, +#endif +#if LV_FONT_MONTSERRAT_16 + { "MONTSERRAT_16", &lv_font_montserrat_16 }, +#endif +#if LV_FONT_MONTSERRAT_18 + { "MONTSERRAT_18", &lv_font_montserrat_18 }, +#endif +#if LV_FONT_MONTSERRAT_20 + { "MONTSERRAT_20", &lv_font_montserrat_20 }, +#endif +#if LV_FONT_MONTSERRAT_22 + { "MONTSERRAT_22", &lv_font_montserrat_22 }, +#endif +#if LV_FONT_MONTSERRAT_24 + { "MONTSERRAT_24", &lv_font_montserrat_24 }, +#endif +#if LV_FONT_MONTSERRAT_26 + { "MONTSERRAT_26", &lv_font_montserrat_26 }, +#endif +#if LV_FONT_MONTSERRAT_28 + { "MONTSERRAT_28", &lv_font_montserrat_28 }, +#endif +#if LV_FONT_MONTSERRAT_30 + { "MONTSERRAT_30", &lv_font_montserrat_30 }, +#endif +#if LV_FONT_MONTSERRAT_32 + { "MONTSERRAT_32", &lv_font_montserrat_32 }, +#endif +#if LV_FONT_MONTSERRAT_34 + { "MONTSERRAT_34", &lv_font_montserrat_34 }, +#endif +#if LV_FONT_MONTSERRAT_36 + { "MONTSERRAT_36", &lv_font_montserrat_36 }, +#endif +#if LV_FONT_MONTSERRAT_38 + { "MONTSERRAT_38", &lv_font_montserrat_38 }, +#endif +#if LV_FONT_MONTSERRAT_40 + { "MONTSERRAT_40", &lv_font_montserrat_40 }, +#endif +#if LV_FONT_MONTSERRAT_42 + { "MONTSERRAT_42", &lv_font_montserrat_42 }, +#endif +#if LV_FONT_MONTSERRAT_44 + { "MONTSERRAT_44", &lv_font_montserrat_44 }, +#endif +#if LV_FONT_MONTSERRAT_46 + { "MONTSERRAT_46", &lv_font_montserrat_46 }, +#endif +#if LV_FONT_MONTSERRAT_48 + { "MONTSERRAT_48", &lv_font_montserrat_48 }, +#endif +}; + +// +// Color themes +// + +uint32_t active_theme_index = 0; + +// +// +// + +void create_screens() { + +// Set default LVGL theme + lv_display_t *dispp = lv_display_get_default(); + lv_theme_t *theme = lv_theme_default_init(dispp, lv_palette_main(LV_PALETTE_BLUE), lv_palette_main(LV_PALETTE_RED), false, LV_FONT_DEFAULT); + lv_display_set_theme(dispp, theme); + + // Initialize screens + // Create screens + create_screen_main(); +} \ No newline at end of file diff --git a/components/ui/screens.h b/components/ui/screens.h new file mode 100644 index 0000000..20a7984 --- /dev/null +++ b/components/ui/screens.h @@ -0,0 +1,39 @@ +#ifndef EEZ_LVGL_UI_SCREENS_H +#define EEZ_LVGL_UI_SCREENS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// Screens + +enum ScreensEnum { + _SCREEN_ID_FIRST = 1, + SCREEN_ID_MAIN = 1, + _SCREEN_ID_LAST = 1 +}; + +typedef struct _objects_t { + lv_obj_t *main; + lv_obj_t *obj0; + lv_obj_t *obj1; + lv_obj_t *obj2; +} objects_t; + +extern objects_t objects; + +void create_screen_main(); +void tick_screen_main(); + +void tick_screen_by_id(enum ScreensEnum screenId); +void tick_screen(int screen_index); + +void create_screens(); + +#ifdef __cplusplus +} +#endif + +#endif /*EEZ_LVGL_UI_SCREENS_H*/ \ No newline at end of file diff --git a/components/ui/structs.h b/components/ui/structs.h new file mode 100644 index 0000000..8d8441b --- /dev/null +++ b/components/ui/structs.h @@ -0,0 +1,4 @@ +#ifndef EEZ_LVGL_UI_STRUCTS_H +#define EEZ_LVGL_UI_STRUCTS_H + +#endif /*EEZ_LVGL_UI_STRUCTS_H*/ \ No newline at end of file diff --git a/components/ui/styles.c b/components/ui/styles.c new file mode 100644 index 0000000..78cf152 --- /dev/null +++ b/components/ui/styles.c @@ -0,0 +1,6 @@ +#include "styles.h" +#include "images.h" +#include "fonts.h" + +#include "ui.h" +#include "screens.h" \ No newline at end of file diff --git a/components/ui/styles.h b/components/ui/styles.h new file mode 100644 index 0000000..f4d548d --- /dev/null +++ b/components/ui/styles.h @@ -0,0 +1,14 @@ +#ifndef EEZ_LVGL_UI_STYLES_H +#define EEZ_LVGL_UI_STYLES_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif /*EEZ_LVGL_UI_STYLES_H*/ \ No newline at end of file diff --git a/components/ui/ui.c b/components/ui/ui.c new file mode 100644 index 0000000..b2d7ab3 --- /dev/null +++ b/components/ui/ui.c @@ -0,0 +1,32 @@ +#include "ui.h" +#include "screens.h" +#include "images.h" +#include "actions.h" +#include "vars.h" + +#include + +static int16_t currentScreen = -1; + +static lv_obj_t *getLvglObjectFromIndex(int32_t index) { + if (index == -1) { + return 0; + } + return ((lv_obj_t **)&objects)[index]; +} + +void loadScreen(enum ScreensEnum screenId) { + currentScreen = screenId - 1; + lv_obj_t *screen = getLvglObjectFromIndex(currentScreen); + lv_scr_load_anim(screen, LV_SCR_LOAD_ANIM_FADE_IN, 200, 0, false); +} + +void ui_init() { + create_screens(); + loadScreen(SCREEN_ID_MAIN); + +} + +void ui_tick() { + tick_screen(currentScreen); +} \ No newline at end of file diff --git a/components/ui/ui.h b/components/ui/ui.h new file mode 100644 index 0000000..0462f26 --- /dev/null +++ b/components/ui/ui.h @@ -0,0 +1,21 @@ +#ifndef EEZ_LVGL_UI_GUI_H +#define EEZ_LVGL_UI_GUI_H + +#include + +#include "screens.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void ui_init(); +void ui_tick(); + +void loadScreen(enum ScreensEnum screenId); + +#ifdef __cplusplus +} +#endif + +#endif // EEZ_LVGL_UI_GUI_H \ No newline at end of file diff --git a/components/ui/vars.c b/components/ui/vars.c new file mode 100644 index 0000000..f56e526 --- /dev/null +++ b/components/ui/vars.c @@ -0,0 +1,57 @@ +#include +#include "vars.h" + +char air_temperature[100] = { 0 }; + +const char *get_var_air_temperature() { + return air_temperature; +} + +void set_var_air_temperature(const char *value) { + strncpy(air_temperature, value, sizeof(air_temperature) / sizeof(char)); + air_temperature[sizeof(air_temperature) / sizeof(char) - 1] = 0; +} + +char air_humidity[100] = { 0 }; + +const char *get_var_air_humidity() { + return air_humidity; +} + +void set_var_air_humidity(const char *value) { + strncpy(air_humidity, value, sizeof(air_humidity) / sizeof(char)); + air_humidity[sizeof(air_humidity) / sizeof(char) - 1] = 0; +} + + +char soil_moisture[100] = { 0 }; + +const char *get_var_soil_moisture() { + return soil_moisture; +} + +void set_var_soil_moisture(const char *value) { + strncpy(soil_moisture, value, sizeof(soil_moisture) / sizeof(char)); + soil_moisture[sizeof(soil_moisture) / sizeof(char) - 1] = 0; +} + +char light_intensity[100] = { 0 }; + +const char *get_var_light_intensity() { + return light_intensity; +} + +void set_var_light_intensity(const char *value) { + strncpy(light_intensity, value, sizeof(light_intensity) / sizeof(char)); + light_intensity[sizeof(light_intensity) / sizeof(char) - 1] = 0; +} + +int32_t air_temperature_int; + +int32_t get_var_air_temperature_int() { + return air_temperature_int; +} + +void set_var_air_temperature_int(int32_t value) { + air_temperature_int = value; +} diff --git a/components/ui/vars.h b/components/ui/vars.h new file mode 100644 index 0000000..7da4552 --- /dev/null +++ b/components/ui/vars.h @@ -0,0 +1,40 @@ +#ifndef EEZ_LVGL_UI_VARS_H +#define EEZ_LVGL_UI_VARS_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// enum declarations + +// Flow global variables + +enum FlowGlobalVariables { + FLOW_GLOBAL_VARIABLE_AIR_TEMPERATURE = 0, + FLOW_GLOBAL_VARIABLE_AIR_HUMIDITY = 1, + FLOW_GLOBAL_VARIABLE_SOIL_MOISTURE = 2, + FLOW_GLOBAL_VARIABLE_LIGHT_INTENSITY = 3, + FLOW_GLOBAL_VARIABLE_AIR_TEMPERATURE_INT = 4 +}; + +// Native global variables + +extern const char *get_var_air_temperature(); +extern void set_var_air_temperature(const char *value); +extern const char *get_var_air_humidity(); +extern void set_var_air_humidity(const char *value); +extern const char *get_var_soil_moisture(); +extern void set_var_soil_moisture(const char *value); +extern const char *get_var_light_intensity(); +extern void set_var_light_intensity(const char *value); +extern int32_t get_var_air_temperature_int(); +extern void set_var_air_temperature_int(int32_t value); + +#ifdef __cplusplus +} +#endif + +#endif /*EEZ_LVGL_UI_VARS_H*/ \ No newline at end of file diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 5eaad13..6bad10b 100755 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -1,4 +1,4 @@ idf_component_register(SRCS "main.c" INCLUDE_DIRS "." - REQUIRES wifi-connect esp_lvgl_port lvgl_st7735s_use i2c_master_messager io_device_control console_simple_init console console_user_cmds capactive_soil_moisture_sensor_V2.0 + REQUIRES wifi-connect esp_lvgl_port lvgl_st7735s_use i2c_master_messager io_device_control console_simple_init console console_user_cmds capactive_soil_moisture_sensor_V2.0 ui ) diff --git a/main/main.c b/main/main.c index 0043933..c6b8e9f 100755 --- a/main/main.c +++ b/main/main.c @@ -12,6 +12,9 @@ #include "console_simple_init.h" // 提供 console_cmd_user_register 和 console_cmd_all_register #include "console_user_cmds.h" #include "capactive_soil_moisture_sensor_V2.0.h" +#include "ui.h" // 使用EEZStudio提供的ui组件,便于后续扩展 +#include "esp_lvgl_port.h" +#include "vars.h" // 定义全局变量接口 #ifndef CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE #define CONFIG_I2C_MASTER_MESSAGER_BH1750_ENABLE 0 @@ -44,24 +47,23 @@ static const char *TAG = "main"; -static const char *wifi_status_short_str(wifi_connect_status_t status) +static char s_air_temp[16]; +static char s_air_hum[16]; +static char s_soil[16]; +static char s_lux[16]; + +static void ui_task(void *arg) { - switch (status) + (void)arg; + + for (;;) { - case WIFI_CONNECT_STATUS_IDLE: - return "IDLE"; - case WIFI_CONNECT_STATUS_PROVISIONING: - return "PROV"; - case WIFI_CONNECT_STATUS_CONNECTING: - return "CONN"; - case WIFI_CONNECT_STATUS_CONNECTED: - return "UP"; - case WIFI_CONNECT_STATUS_FAILED: - return "FAIL"; - case WIFI_CONNECT_STATUS_TIMEOUT: - return "TIME"; - default: - return "UNKN"; + lvgl_port_lock(0); + ui_tick(); + lvgl_port_unlock(); + + // UI 刷新周期无需过高,20ms 兼顾流畅度与CPU占用。 + vTaskDelay(pdMS_TO_TICKS(20)); } } @@ -101,6 +103,14 @@ void app_main(void) // 启动 LVGL 演示程序,显示简单的界面 ESP_ERROR_CHECK(start_lvgl_demo()); + // 初始化 UI 组件(需在 LVGL 锁内进行对象创建) + lvgl_port_lock(0); + ui_init(); + lvgl_port_unlock(); + + BaseType_t ui_task_ok = xTaskCreate(ui_task, "ui_task", 4096, NULL, 5, NULL); + ESP_ERROR_CHECK(ui_task_ok == pdPASS ? ESP_OK : ESP_FAIL); + // 初始化 IO 设备控制组件(GPIO1 水泵,GPIO10 光照,高电平有效) ESP_ERROR_CHECK(io_device_control_init()); @@ -169,17 +179,30 @@ void app_main(void) cap_soil_sensor_data_t soil_data = {0}; if (soil_ready && cap_soil_sensor_read(&soil_data) == ESP_OK) { - // 读取成功,当前版本仅保留采样流程,显示逻辑由用户自定义。 + // 读取成功 + snprintf(s_soil, sizeof(s_soil), "%.0f", soil_data.moisture_percent); + set_var_soil_moisture(s_soil); } i2c_master_messager_data_t sensor_data = {0}; if (i2c_ready && i2c_master_messager_get_data(&sensor_data) == ESP_OK) { - // 读取成功,当前版本仅保留采样流程,显示逻辑由用户自定义。 - } + // 读取成功 + if (sensor_data.aht30.valid) + { + snprintf(s_air_temp, sizeof(s_air_temp), "%.1f", sensor_data.aht30.temperature_c); + set_var_air_temperature(s_air_temp); + set_var_air_temperature_int((int32_t)(sensor_data.aht30.temperature_c * 100)); // 以 1°C 为单位的整数 - // TODO: 在这里实现你自己的 LCD 显示内容与排版。 - // ESP_ERROR_CHECK(lvgl_st7735s_set_center_text("custom text")); + snprintf(s_air_hum, sizeof(s_air_hum), "%.1f", sensor_data.aht30.humidity_rh); + set_var_air_humidity(s_air_hum); + } + if (sensor_data.bh1750.valid) + { + snprintf(s_lux, sizeof(s_lux), "%.0f", sensor_data.bh1750.lux); + set_var_light_intensity(s_lux); + } + } vTaskDelay(pdMS_TO_TICKS(1000)); }