optimized flush procedure.
Signed-off-by: imi415 <imi415@imi.moe>
This commit is contained in:
parent
d378c2d50d
commit
9cd7aba20b
|
@ -1 +1 @@
|
|||
Subproject commit 3e2c515e99c310d3e0ecfcf336c96ef19893aa54
|
||||
Subproject commit 562432a46e54d93b115f1b2132e32544e683e043
|
|
@ -24,7 +24,7 @@
|
|||
*====================*/
|
||||
|
||||
/*Color depth: 1 (1 byte per pixel), 8 (RGB332), 16 (RGB565), 32 (ARGB8888)*/
|
||||
#define LV_COLOR_DEPTH 32
|
||||
#define LV_COLOR_DEPTH 8
|
||||
|
||||
/*Swap the 2 bytes of RGB565 color. Useful if the display has an 8-bit interface (e.g. SPI)*/
|
||||
#define LV_COLOR_16_SWAP 0
|
||||
|
@ -46,10 +46,10 @@
|
|||
*=========================*/
|
||||
|
||||
/*1: use custom malloc/free, 0: use the built-in `lv_mem_alloc()` and `lv_mem_free()`*/
|
||||
#define LV_MEM_CUSTOM 0
|
||||
#define LV_MEM_CUSTOM 1
|
||||
#if LV_MEM_CUSTOM == 0
|
||||
/*Size of the memory available for `lv_mem_alloc()` in bytes (>= 2kB)*/
|
||||
#define LV_MEM_SIZE (32U * 1024U) /*[bytes]*/
|
||||
#define LV_MEM_SIZE (40U * 1024U) /*[bytes]*/
|
||||
|
||||
/*Set an address for the memory pool instead of allocating it as a normal array. Can be in external SRAM too.*/
|
||||
#define LV_MEM_ADR 0 /*0: unused*/
|
||||
|
@ -78,7 +78,7 @@
|
|||
*====================*/
|
||||
|
||||
/*Default display refresh period. LVG will redraw changed areas with this period time*/
|
||||
#define LV_DISP_DEF_REFR_PERIOD 500 /*[ms]*/
|
||||
#define LV_DISP_DEF_REFR_PERIOD 1 /*[ms] !note: this is not the actual time, set as small as possible. */
|
||||
|
||||
/*Input device read period in milliseconds*/
|
||||
#define LV_INDEV_DEF_READ_PERIOD 30 /*[ms]*/
|
||||
|
@ -219,7 +219,7 @@
|
|||
*-----------*/
|
||||
|
||||
/*Enable the log module*/
|
||||
#define LV_USE_LOG 0
|
||||
#define LV_USE_LOG 1
|
||||
#if LV_USE_LOG
|
||||
|
||||
/*How important log should be added:
|
||||
|
@ -229,21 +229,21 @@
|
|||
*LV_LOG_LEVEL_ERROR Only critical issue, when the system may fail
|
||||
*LV_LOG_LEVEL_USER Only logs added by the user
|
||||
*LV_LOG_LEVEL_NONE Do not log anything*/
|
||||
#define LV_LOG_LEVEL LV_LOG_LEVEL_WARN
|
||||
#define LV_LOG_LEVEL LV_LOG_LEVEL_ERROR
|
||||
|
||||
/*1: Print the log with 'printf';
|
||||
*0: User need to register a callback with `lv_log_register_print_cb()`*/
|
||||
#define LV_LOG_PRINTF 0
|
||||
|
||||
/*Enable/disable LV_LOG_TRACE in modules that produces a huge number of logs*/
|
||||
#define LV_LOG_TRACE_MEM 1
|
||||
#define LV_LOG_TRACE_TIMER 1
|
||||
#define LV_LOG_TRACE_INDEV 1
|
||||
#define LV_LOG_TRACE_DISP_REFR 1
|
||||
#define LV_LOG_TRACE_EVENT 1
|
||||
#define LV_LOG_TRACE_OBJ_CREATE 1
|
||||
#define LV_LOG_TRACE_LAYOUT 1
|
||||
#define LV_LOG_TRACE_ANIM 1
|
||||
#define LV_LOG_TRACE_MEM 0
|
||||
#define LV_LOG_TRACE_TIMER 0
|
||||
#define LV_LOG_TRACE_INDEV 0
|
||||
#define LV_LOG_TRACE_DISP_REFR 0
|
||||
#define LV_LOG_TRACE_EVENT 0
|
||||
#define LV_LOG_TRACE_OBJ_CREATE 0
|
||||
#define LV_LOG_TRACE_LAYOUT 0
|
||||
#define LV_LOG_TRACE_ANIM 0
|
||||
|
||||
#endif /*LV_USE_LOG*/
|
||||
|
||||
|
|
2
lib/lvgl
2
lib/lvgl
|
@ -1 +1 @@
|
|||
Subproject commit 9024b72b4853e1e7ac29a42e54b7a10d3c4f3b20
|
||||
Subproject commit 755d363ecc4eb7a85583db477446343969aa5efa
|
|
@ -3,10 +3,16 @@ SRCS
|
|||
"app_lvgl.c"
|
||||
"app_main.c"
|
||||
"app_mqtt.c"
|
||||
"app_ui_weather.c"
|
||||
"app_ui.c"
|
||||
"app_wifi.c"
|
||||
"assets/fonts/noto_sans_24.c"
|
||||
"assets/fonts/noto_sans_96.c"
|
||||
"assets/fonts/noto_sans_150.c"
|
||||
"assets/fonts/noto_sans_240.c"
|
||||
"assets/fonts/weather_icon_24.c"
|
||||
"assets/fonts/weather_icon_96.c"
|
||||
"assets/fonts/weather_icon_150.c"
|
||||
"assets/fonts/weather_icon_240.c"
|
||||
|
||||
INCLUDE_DIRS
|
||||
"include"
|
||||
|
|
|
@ -8,19 +8,21 @@
|
|||
#include "freertos/task.h"
|
||||
|
||||
/* IDF drivers */
|
||||
#include "esp_log.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
/* EPD driver */
|
||||
#include "epd_driver.h"
|
||||
#include "epd_highlevel.h"
|
||||
#include "epd_board_specific.h"
|
||||
|
||||
/* LVGL */
|
||||
#include "lvgl.h"
|
||||
|
||||
/* Private */
|
||||
#include "app_bkp_ram.h"
|
||||
#include "app_lvgl.h"
|
||||
|
||||
#define LVGL_TASK_HEAP 4096
|
||||
|
@ -28,6 +30,8 @@
|
|||
|
||||
#define APP_LOG_TAG "APP_LVGL"
|
||||
|
||||
#define EPD_MAX_REFR_COUNT 8
|
||||
|
||||
static EpdiyHighlevelState s_epd_hl;
|
||||
static int s_temp = 26;
|
||||
|
||||
|
@ -36,11 +40,14 @@ static lv_color_t *s_screen_buf;
|
|||
static lv_disp_drv_t s_disp_drv;
|
||||
|
||||
static SemaphoreHandle_t s_lvgl_semphr;
|
||||
static SemaphoreHandle_t s_lvgl_flush_cmd_semphr; /* This semaphore is used to start the drawing */
|
||||
static SemaphoreHandle_t s_lvgl_flush_ready_semphr; /* This semaphore is used to notify the drawing has completed */
|
||||
|
||||
static void app_lvgl_task(void *pvParameters);
|
||||
static void app_lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
|
||||
static void app_lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t buf_w, lv_coord_t x, lv_coord_t y,
|
||||
lv_color_t color, lv_opa_t opa);
|
||||
static void app_lvgl_log_cb(const char *buf);
|
||||
|
||||
int app_lvgl_init(void) {
|
||||
/* Initialize EPDIY */
|
||||
|
@ -54,12 +61,14 @@ int app_lvgl_init(void) {
|
|||
|
||||
/* Initialize LVGL */
|
||||
lv_init();
|
||||
lv_log_register_print_cb(app_lvgl_log_cb);
|
||||
lv_disp_draw_buf_init(&s_disp_buf, s_screen_buf, NULL, 960 * 540);
|
||||
lv_disp_drv_init(&s_disp_drv);
|
||||
s_disp_drv.user_data = &s_epd_hl;
|
||||
s_disp_drv.draw_buf = &s_disp_buf;
|
||||
s_disp_drv.hor_res = 960;
|
||||
s_disp_drv.ver_res = 540;
|
||||
s_disp_drv.full_refresh = true;
|
||||
s_disp_drv.flush_cb = app_lvgl_flush_cb;
|
||||
s_disp_drv.set_px_cb = app_lvgl_set_px_cb;
|
||||
lv_disp_drv_register(&s_disp_drv);
|
||||
|
@ -70,16 +79,37 @@ int app_lvgl_init(void) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (xTaskCreate(app_lvgl_task, "LV_TASK", LVGL_TASK_HEAP, NULL, 2, NULL) != pdPASS) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to create LVGL task, available heap: %d.", esp_get_free_heap_size());
|
||||
s_lvgl_flush_ready_semphr = xSemaphoreCreateBinary();
|
||||
if (s_lvgl_flush_ready_semphr == NULL) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to create flush semaphore.");
|
||||
return -2;
|
||||
}
|
||||
|
||||
s_lvgl_flush_cmd_semphr = xSemaphoreCreateBinary();
|
||||
if(s_lvgl_flush_cmd_semphr == NULL) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to create flush command semaphore.");
|
||||
return -3;
|
||||
}
|
||||
|
||||
if (xTaskCreate(app_lvgl_task, "LV_TASK", LVGL_TASK_HEAP, NULL, 2, NULL) != pdPASS) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to create LVGL task, available heap: %d.", esp_get_free_heap_size());
|
||||
return -4;
|
||||
}
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "LVGL initialized.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_lvgl_deinit(void) {
|
||||
epd_powerdown_lilygo_t5_47();
|
||||
epd_deinit();
|
||||
|
||||
/* LVGL is not required to be de-init. */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_lvgl_lock(uint32_t ms) {
|
||||
if (xSemaphoreTake(s_lvgl_semphr, pdMS_TO_TICKS(ms)) != pdPASS) {
|
||||
return -1;
|
||||
|
@ -96,7 +126,29 @@ int app_lvgl_unlock(void) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int app_lvgl_start_flush(void) {
|
||||
if (xSemaphoreGive(s_lvgl_flush_cmd_semphr) != pdPASS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_lvgl_wait_flush(uint32_t timeout_ms) {
|
||||
if (xSemaphoreTake(s_lvgl_flush_ready_semphr, pdMS_TO_TICKS(timeout_ms)) != pdPASS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void app_lvgl_task(void *pvParameters) {
|
||||
if(xSemaphoreTake(s_lvgl_flush_cmd_semphr, portMAX_DELAY) != pdPASS) {
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "Received flush GO signal, start flushing...");
|
||||
|
||||
for (;;) {
|
||||
if (app_lvgl_lock(50) == 0) {
|
||||
lv_timer_handler();
|
||||
|
@ -122,9 +174,12 @@ static void app_lvgl_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv
|
|||
ESP_LOGI(APP_LOG_TAG, "Flush called.");
|
||||
|
||||
epd_poweron();
|
||||
epd_hl_update_area(hl, MODE_GC16, s_temp, rect);
|
||||
epd_hl_update_area(hl, MODE_GL16, s_temp, rect);
|
||||
epd_poweroff();
|
||||
|
||||
// Done flushing..
|
||||
xSemaphoreGive(s_lvgl_flush_ready_semphr);
|
||||
|
||||
lv_disp_flush_ready(disp_drv);
|
||||
}
|
||||
|
||||
|
@ -143,3 +198,7 @@ static void app_lvgl_set_px_cb(lv_disp_drv_t *disp_drv, uint8_t *buf, lv_coord_t
|
|||
buf[px_offset] |= pix_y << 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void app_lvgl_log_cb(const char *buf) {
|
||||
ESP_LOGI(APP_LOG_TAG, "LVGL: %s", buf);
|
||||
}
|
342
main/app_main.c
342
main/app_main.c
|
@ -7,21 +7,37 @@
|
|||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include "esp_system.h"
|
||||
/* ESP libraries */
|
||||
#include "esp_log.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
/* FreeRTOS */
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
/* MISC */
|
||||
#include "cbor.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
/* APP */
|
||||
#include "app_bkp_ram.h"
|
||||
#include "app_lvgl.h"
|
||||
#include "app_mqtt.h"
|
||||
#include "app_ui.h"
|
||||
#include "app_wifi.h"
|
||||
|
||||
#define APP_WAKE_INTERVAL_MS (30 * 60 * 1000)
|
||||
|
||||
#define APP_LOG_TAG "MAIN"
|
||||
|
||||
RTC_NOINIT_ATTR app_bkp_ram_t g_app_bkp;
|
||||
|
||||
int app_ui_weather_init(void);
|
||||
static CborError app_get_condition_string(CborValue *it, char *key, char **value, uint32_t *size);
|
||||
static int app_windlevel_to_font(char *input, char **output);
|
||||
static int app_condition_to_font(char *input, char **output);
|
||||
static int app_update_ui(void);
|
||||
|
||||
void app_main(void) {
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
|
@ -36,18 +52,330 @@ void app_main(void) {
|
|||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
if (app_wifi_init() != 0) {
|
||||
return;
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
if (app_mqtt_init() != 0) {
|
||||
return;
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
if (app_wifi_wait_ready(5000) != 0) {
|
||||
ESP_LOGW(APP_LOG_TAG, "Failed to connect to WiFi in time, bail out.");
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
if (app_lvgl_init() != 0) {
|
||||
return;
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
if(app_ui_weather_init() != 0) {
|
||||
return;
|
||||
if (app_ui_init() != 0) {
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
if (app_update_ui() != 0) {
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
app_lvgl_start_flush();
|
||||
if(app_lvgl_wait_flush(5000) < 0) {
|
||||
ESP_LOGW(APP_LOG_TAG, "Did not get flush ready flag in time, bail out.");
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
next_round:
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "Enter deep power down mode, interval: %d", APP_WAKE_INTERVAL_MS);
|
||||
app_lvgl_deinit();
|
||||
esp_deep_sleep(APP_WAKE_INTERVAL_MS * 1000);
|
||||
}
|
||||
|
||||
static int app_update_ui(void) {
|
||||
app_mqtt_subscribe("iot/weather/ESP32_Weather/response");
|
||||
|
||||
CborEncoder root_encoder;
|
||||
uint8_t *tx_buf = malloc(100);
|
||||
if (tx_buf == NULL) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to allocate tx buffer");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
cbor_encoder_init(&root_encoder, tx_buf, 100, 0);
|
||||
|
||||
CborEncoder map_encoder;
|
||||
cbor_encoder_create_map(&root_encoder, &map_encoder, 2);
|
||||
|
||||
cbor_encode_text_stringz(&map_encoder, "type");
|
||||
cbor_encode_text_stringz(&map_encoder, "condition");
|
||||
|
||||
cbor_encode_text_stringz(&map_encoder, "city_id");
|
||||
cbor_encode_uint(&map_encoder, 10);
|
||||
|
||||
cbor_encoder_close_container(&root_encoder, &map_encoder);
|
||||
|
||||
uint32_t data_size = cbor_encoder_get_buffer_size(&root_encoder, tx_buf);
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "Encoded CBOR message %d bytes.", data_size);
|
||||
|
||||
app_mqtt_publish("iot/weather/ESP32_Weather/request", tx_buf, data_size);
|
||||
|
||||
free(tx_buf);
|
||||
|
||||
char *topic;
|
||||
uint8_t *payload;
|
||||
uint32_t payload_len;
|
||||
|
||||
if (app_mqtt_poll(&topic, &payload, &payload_len, 10000) != 0) {
|
||||
ESP_LOGE(APP_LOG_TAG, "failed to receive payload in time, bail out");
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "Received %d bytes from topic %s", payload_len, topic);
|
||||
|
||||
CborParser root_parser;
|
||||
CborValue it;
|
||||
CborError cbor_ret;
|
||||
|
||||
cbor_ret = cbor_parser_init(payload, payload_len, 0, &root_parser, &it);
|
||||
if (cbor_ret != CborNoError) {
|
||||
ESP_LOGE(APP_LOG_TAG, "CBOR Parse 1");
|
||||
return -3;
|
||||
}
|
||||
|
||||
char *str;
|
||||
uint32_t size;
|
||||
if (app_get_condition_string(&it, "sunRise", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_SUNRISE, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "sunSet", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_SUNSET, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "uvi", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_UVI, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "updatetime", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_UPDATED, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "temp", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_TEMP, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "humidity", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_HUMID, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "realFeel", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_TEMP_REAL, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "windSpeed", &str, &size) == CborNoError) {
|
||||
app_ui_update(APP_UI_CMD_WIND_SPEED, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "windLevel", &str, &size) == CborNoError) {
|
||||
app_windlevel_to_font(str, &str);
|
||||
app_ui_update(APP_UI_CMD_WIND_LEVEL, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
if (app_get_condition_string(&it, "conditionId", &str, &size) == CborNoError) {
|
||||
app_condition_to_font(str, &str);
|
||||
app_ui_update(APP_UI_CMD_COND, str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
free(topic);
|
||||
free(payload);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int app_condition_to_font(char *input, char **output) {
|
||||
*output = malloc(4);
|
||||
if (*output == NULL) return -1;
|
||||
|
||||
char *unicode = "\U0000F00D";
|
||||
|
||||
int wx_id = strtol(input, NULL, 10);
|
||||
|
||||
if (wx_id <= 5) {
|
||||
/* Do nothing */
|
||||
} else if (wx_id <= 7) {
|
||||
unicode = "\U0000F072";
|
||||
} else if (wx_id <= 11) {
|
||||
unicode = "\U0000F002";
|
||||
} else if (wx_id <= 12) {
|
||||
unicode = "\U0000F072";
|
||||
} else if (wx_id <= 14) {
|
||||
unicode = "\U0000F013";
|
||||
} else if (wx_id <= 23) {
|
||||
unicode = "\U0000F009";
|
||||
} else if (wx_id <= 25) {
|
||||
unicode = "\U0000F00A";
|
||||
} else if (wx_id <= 28) {
|
||||
unicode = "\U0000F003";
|
||||
} else if (wx_id <= 33) {
|
||||
unicode = "\U0000F082";
|
||||
} else if (wx_id <= 35) {
|
||||
unicode = "\U0000F0B6";
|
||||
} else if (wx_id <= 36) {
|
||||
unicode = "\U0000F041";
|
||||
} else if (wx_id <= 41) {
|
||||
unicode = "\U0000F00E";
|
||||
} else if (wx_id <= 43) {
|
||||
unicode = "\U0000F005";
|
||||
} else if (wx_id <= 45) {
|
||||
unicode = "\U0000F068";
|
||||
} else if (wx_id <= 48) {
|
||||
unicode = "\U0000F004";
|
||||
} else if (wx_id <= 50) {
|
||||
unicode = "\U0000F006";
|
||||
} else if (wx_id <= 57) {
|
||||
unicode = "\U0000F008";
|
||||
} else if (wx_id <= 63) {
|
||||
unicode = "\U0000F00A";
|
||||
} else if (wx_id <= 65) {
|
||||
unicode = "\U0000F006";
|
||||
} else if (wx_id <= 70) {
|
||||
unicode = "\U0000F008";
|
||||
} else if (wx_id <= 77) {
|
||||
unicode = "\U0000F00A";
|
||||
} else if (wx_id <= 78) {
|
||||
unicode = "\U0000F008";
|
||||
} else if (wx_id <= 79) {
|
||||
unicode = "\U0000F0B6";
|
||||
} else if (wx_id <= 82) {
|
||||
unicode = "\U0000F002";
|
||||
} else if (wx_id <= 84) {
|
||||
unicode = "\U0000F003";
|
||||
} else if (wx_id <= 85) {
|
||||
unicode = "\U0000F002";
|
||||
} else if (wx_id <= 86) {
|
||||
unicode = "\U0000F009";
|
||||
} else if (wx_id <= 90) {
|
||||
unicode = "\U0000F00E";
|
||||
} else if (wx_id <= 93) {
|
||||
unicode = "\U0000F008";
|
||||
} else if (wx_id <= 94) {
|
||||
unicode = "\U0000F00A";
|
||||
}
|
||||
|
||||
snprintf(*output, 4, "%s", unicode);
|
||||
free(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int app_windlevel_to_font(char *input, char **output) {
|
||||
*output = malloc(4);
|
||||
if (*output == NULL) return -1;
|
||||
|
||||
char *unicode = "\U0000F0B7";
|
||||
|
||||
if (input[1] != '\0') {
|
||||
switch (input[0]) {
|
||||
case '0':
|
||||
unicode = "\U0000F0C1";
|
||||
break;
|
||||
case '1':
|
||||
unicode = "\U0000F0C2";
|
||||
break;
|
||||
case '2':
|
||||
unicode = "\U0000F0C3";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (input[0]) {
|
||||
case '0':
|
||||
unicode = "\U0000F0B7";
|
||||
break;
|
||||
case '1':
|
||||
unicode = "\U0000F0B8";
|
||||
break;
|
||||
case '2':
|
||||
unicode = "\U0000F0B9";
|
||||
break;
|
||||
case '3':
|
||||
unicode = "\U0000F0BA";
|
||||
break;
|
||||
case '4':
|
||||
unicode = "\U0000F0BB";
|
||||
break;
|
||||
case '5':
|
||||
unicode = "\U0000F0BC";
|
||||
break;
|
||||
case '6':
|
||||
unicode = "\U0000F0BD";
|
||||
break;
|
||||
case '7':
|
||||
unicode = "\U0000F0BE";
|
||||
break;
|
||||
case '8':
|
||||
unicode = "\U0000F0BF";
|
||||
break;
|
||||
case '9':
|
||||
unicode = "\U0000F0C0";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(*output, 4, "%s", unicode);
|
||||
free(input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CborError app_get_condition_string(CborValue *it, char *key, char **value, uint32_t *size) {
|
||||
CborError ret;
|
||||
|
||||
CborValue data;
|
||||
ret = cbor_value_map_find_value(it, "data", &data);
|
||||
if (ret != CborNoError) {
|
||||
ESP_LOGE(APP_LOG_TAG, "CBOR Parse 2");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cbor_value_get_type(&data) != CborMapType) {
|
||||
ESP_LOGE(APP_LOG_TAG, "CBOR Parse 3");
|
||||
return ret;
|
||||
}
|
||||
|
||||
CborValue condition;
|
||||
ret = cbor_value_map_find_value(&data, "condition", &condition);
|
||||
if (ret != CborNoError) {
|
||||
ESP_LOGE(APP_LOG_TAG, "CBOR Parse 4");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cbor_value_get_type(&condition) != CborMapType) {
|
||||
ESP_LOGE(APP_LOG_TAG, "CBOR Parse 5");
|
||||
return ret;
|
||||
}
|
||||
|
||||
CborValue result;
|
||||
ret = cbor_value_map_find_value(&condition, key, &result);
|
||||
if (ret != CborNoError) {
|
||||
ESP_LOGE(APP_LOG_TAG, "CBOR Parse 6");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (cbor_value_is_text_string(&result)) {
|
||||
cbor_value_dup_text_string(&result, value, (size_t *)&size, &result);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
162
main/app_mqtt.c
162
main/app_mqtt.c
|
@ -19,9 +19,17 @@
|
|||
|
||||
#define APP_LOG_TAG "APP_MQTT"
|
||||
|
||||
typedef enum {
|
||||
APP_MQTT_CMD_PUBLISH,
|
||||
APP_MQTT_CMD_SUBSCRIBE,
|
||||
APP_MQTT_CMD_UNSUBSCRIBE,
|
||||
} app_mqtt_queue_cmd_t;
|
||||
|
||||
typedef struct {
|
||||
app_mqtt_queue_cmd_t cmd;
|
||||
char *topic;
|
||||
char *payload;
|
||||
uint8_t *payload;
|
||||
uint32_t payload_len;
|
||||
} app_mqtt_queue_item_t;
|
||||
|
||||
extern const char mqtt_client_cert_start[] asm("_binary_client_crt_start");
|
||||
|
@ -32,44 +40,108 @@ extern const char mqtt_client_key_end[] asm("_binary_client_key_end");
|
|||
static void app_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||
static void app_mqtt_task(void *pvParameters);
|
||||
|
||||
static QueueHandle_t s_app_mqtt_publish_queue;
|
||||
static QueueHandle_t s_app_mqtt_command_queue;
|
||||
static QueueHandle_t s_app_mqtt_response_queue;
|
||||
|
||||
int app_mqtt_init(void) {
|
||||
s_app_mqtt_publish_queue = xQueueCreate(4, sizeof(app_mqtt_queue_item_t));
|
||||
if(s_app_mqtt_publish_queue == NULL) {
|
||||
s_app_mqtt_command_queue = xQueueCreate(4, sizeof(app_mqtt_queue_item_t));
|
||||
if (s_app_mqtt_command_queue == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
s_app_mqtt_response_queue = xQueueCreate(4, sizeof(app_mqtt_queue_item_t));
|
||||
if (s_app_mqtt_response_queue == NULL) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (xTaskCreate(app_mqtt_task, "MQ_TASK", 2048, NULL, 2U, NULL) != pdPASS) {
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_mqtt_publish(char *topic, uint8_t *payload, uint32_t payload_len) {
|
||||
app_mqtt_queue_item_t item;
|
||||
item.cmd = APP_MQTT_CMD_PUBLISH;
|
||||
|
||||
item.topic = malloc(strlen(topic) + 1);
|
||||
if (item.topic == NULL) return -1;
|
||||
|
||||
item.payload = malloc(payload_len);
|
||||
if (item.payload == NULL) {
|
||||
free(item.topic);
|
||||
return -2;
|
||||
}
|
||||
|
||||
item.payload_len = payload_len;
|
||||
|
||||
strcpy(item.topic, topic);
|
||||
memcpy(item.payload, payload, payload_len);
|
||||
|
||||
if (xQueueSend(s_app_mqtt_command_queue, &item, portMAX_DELAY) != pdPASS) {
|
||||
free(item.topic);
|
||||
free(item.payload);
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_mqtt_subscribe(char *topic) {
|
||||
app_mqtt_queue_item_t item;
|
||||
item.cmd = APP_MQTT_CMD_SUBSCRIBE;
|
||||
|
||||
item.topic = malloc(strlen(topic) + 1);
|
||||
if (item.topic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(item.topic, topic);
|
||||
|
||||
if (xQueueSend(s_app_mqtt_command_queue, &item, portMAX_DELAY) != pdPASS) {
|
||||
free(item.topic);
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_mqtt_publish(char *topic, char *payload) {
|
||||
int app_mqtt_unsubscribe(char *topic) {
|
||||
app_mqtt_queue_item_t item;
|
||||
item.topic = malloc(strlen(topic) + 1);
|
||||
if(item.topic == NULL) return -1;
|
||||
item.cmd = APP_MQTT_CMD_UNSUBSCRIBE;
|
||||
|
||||
item.payload = malloc(strlen(payload) + 1);
|
||||
if(item.payload == NULL) {
|
||||
free(item.topic);
|
||||
return -2;
|
||||
item.topic = malloc(strlen(topic) + 1);
|
||||
if (item.topic == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(item.topic, topic);
|
||||
strcpy(item.payload, payload);
|
||||
|
||||
if(xQueueSend(s_app_mqtt_publish_queue, &item, portMAX_DELAY) != pdPASS) {
|
||||
if (xQueueSend(s_app_mqtt_command_queue, &item, portMAX_DELAY) != pdPASS) {
|
||||
free(item.topic);
|
||||
free(item.payload);
|
||||
return -3;
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_mqtt_poll(char **topic, uint8_t **payload, uint32_t *payload_len, uint32_t timeout) {
|
||||
app_mqtt_queue_item_t item;
|
||||
|
||||
if (xQueueReceive(s_app_mqtt_response_queue, &item, pdMS_TO_TICKS(timeout)) != pdPASS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*topic = item.topic;
|
||||
*payload = item.payload;
|
||||
*payload_len = item.payload_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void app_mqtt_task(void *pvParameters) {
|
||||
const esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.uri = CONFIG_APP_MQTT_BROKER_ADDR,
|
||||
|
@ -90,16 +162,70 @@ static void app_mqtt_task(void *pvParameters) {
|
|||
app_mqtt_queue_item_t item;
|
||||
|
||||
for (;;) {
|
||||
if(xQueueReceive(s_app_mqtt_publish_queue, &item, portMAX_DELAY) == pdPASS) {
|
||||
esp_mqtt_client_publish(client, item.topic, item.payload, strlen(item.payload), 0, 0);
|
||||
if (xQueueReceive(s_app_mqtt_command_queue, &item, portMAX_DELAY) == pdPASS) {
|
||||
switch (item.cmd) {
|
||||
case APP_MQTT_CMD_PUBLISH: {
|
||||
esp_mqtt_client_publish(client, item.topic, (char *)item.payload, item.payload_len, 0, 0);
|
||||
|
||||
/* This is alloc'ed by us. */
|
||||
free(item.topic);
|
||||
free(item.payload);
|
||||
} break;
|
||||
case APP_MQTT_CMD_SUBSCRIBE: {
|
||||
esp_mqtt_client_subscribe(client, item.topic, 0);
|
||||
|
||||
free(item.topic);
|
||||
} break;
|
||||
|
||||
case APP_MQTT_CMD_UNSUBSCRIBE: {
|
||||
esp_mqtt_client_unsubscribe(client, item.topic);
|
||||
|
||||
free(item.topic);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void app_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
|
||||
/**/
|
||||
esp_mqtt_event_handle_t event = event_data;
|
||||
|
||||
switch ((esp_mqtt_event_id_t)event_id) {
|
||||
case MQTT_EVENT_DATA:
|
||||
ESP_LOGI(APP_LOG_TAG, "Received from: %.*s", event->topic_len, event->topic);
|
||||
|
||||
app_mqtt_queue_item_t item;
|
||||
item.topic = malloc(event->topic_len + 1);
|
||||
if (item.topic == NULL) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to allocate topic");
|
||||
return;
|
||||
}
|
||||
item.payload = malloc(event->data_len);
|
||||
if (item.payload == NULL) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to allocate data");
|
||||
free(item.topic);
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(item.topic, event->topic, event->topic_len);
|
||||
memcpy(item.payload, event->data, event->data_len);
|
||||
|
||||
item.topic[event->topic_len] = '\0';
|
||||
|
||||
item.payload_len = event->data_len;
|
||||
|
||||
if (xQueueSend(s_app_mqtt_response_queue, &item, pdMS_TO_TICKS(500)) != pdTRUE) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Response queue is full...");
|
||||
|
||||
free(item.topic);
|
||||
free(item.payload);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
366
main/app_ui.c
Normal file
366
main/app_ui.c
Normal file
|
@ -0,0 +1,366 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**/
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
/* FreeRTOS */
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
/* LVGL */
|
||||
#include "lvgl.h"
|
||||
|
||||
/* Private */
|
||||
#include "app_lvgl.h"
|
||||
#include "app_ui.h"
|
||||
|
||||
#define UI_TASK_HEAP 4096
|
||||
#define APP_LOG_TAG "UI_WX"
|
||||
|
||||
typedef struct {
|
||||
app_ui_cmd_t cmd;
|
||||
char *data;
|
||||
} app_ui_queue_item_t;
|
||||
|
||||
LV_FONT_DECLARE(noto_sans_24)
|
||||
LV_FONT_DECLARE(noto_sans_96)
|
||||
LV_FONT_DECLARE(noto_sans_150)
|
||||
LV_FONT_DECLARE(noto_sans_240)
|
||||
LV_FONT_DECLARE(weather_icon_24)
|
||||
LV_FONT_DECLARE(weather_icon_96)
|
||||
LV_FONT_DECLARE(weather_icon_150)
|
||||
LV_FONT_DECLARE(weather_icon_240)
|
||||
|
||||
static lv_style_t s_epd_style;
|
||||
static lv_theme_t s_epd_theme;
|
||||
|
||||
static QueueHandle_t s_app_ui_update_queue;
|
||||
|
||||
static void app_ui_theme_apply(lv_theme_t *th, lv_obj_t *obj);
|
||||
static void app_ui_task(void *pvParameters);
|
||||
|
||||
int app_ui_init(void) {
|
||||
s_app_ui_update_queue = xQueueCreate(4, sizeof(app_ui_queue_item_t));
|
||||
if (s_app_ui_update_queue == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (xTaskCreate(app_ui_task, "UI_WX", UI_TASK_HEAP, NULL, 3, NULL) != pdPASS) {
|
||||
ESP_LOGE(APP_LOG_TAG, "UI WX task failed to create.");
|
||||
return -2;
|
||||
}
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "UI WX initialized.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int app_ui_update(app_ui_cmd_t cmd, char *data) {
|
||||
app_ui_queue_item_t item;
|
||||
item.cmd = cmd;
|
||||
item.data = malloc(strlen(data));
|
||||
|
||||
if (item.data == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(item.data, data);
|
||||
|
||||
if (xQueueSend(s_app_ui_update_queue, &item, portMAX_DELAY) != pdPASS) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void app_ui_task(void *pvParameters) {
|
||||
lv_obj_t *screen_cond = NULL;
|
||||
|
||||
/* Top bar */
|
||||
lv_obj_t *container_topbar = NULL;
|
||||
|
||||
lv_obj_t *label_sunrise = NULL;
|
||||
lv_obj_t *label_sunrise_time = NULL;
|
||||
lv_obj_t *label_sunset = NULL;
|
||||
lv_obj_t *label_sunset_time = NULL;
|
||||
lv_obj_t *label_uvi = NULL;
|
||||
lv_obj_t *label_uvi_value = NULL;
|
||||
lv_obj_t *label_updated = NULL;
|
||||
lv_obj_t *label_updated_time = NULL;
|
||||
|
||||
/* Seperation line */
|
||||
lv_obj_t *line_topbar = NULL;
|
||||
|
||||
/* Middle display */
|
||||
lv_obj_t *container_main = NULL;
|
||||
|
||||
lv_obj_t *label_wxicon = NULL;
|
||||
lv_obj_t *label_temperature = NULL;
|
||||
lv_obj_t *label_temperature_hi = NULL;
|
||||
lv_obj_t *label_temperature_lo = NULL;
|
||||
lv_obj_t *label_temperature_real = NULL;
|
||||
lv_obj_t *label_temperature_real_desc = NULL;
|
||||
lv_obj_t *label_temperature_unit = NULL;
|
||||
lv_obj_t *label_temperature_hi_unit = NULL;
|
||||
lv_obj_t *label_temperature_lo_unit = NULL;
|
||||
lv_obj_t *label_temperature_real_unit = NULL;
|
||||
lv_obj_t *label_humidity = NULL;
|
||||
lv_obj_t *label_humidity_unit = NULL;
|
||||
lv_obj_t *label_wind_level = NULL;
|
||||
lv_obj_t *label_wind_speed = NULL;
|
||||
lv_obj_t *label_wind_direction = NULL;
|
||||
|
||||
lv_point_t points_line_topbar[] = {{0, 37}, {959, 37}};
|
||||
|
||||
if (app_lvgl_lock(portMAX_DELAY) == 0) {
|
||||
lv_style_init(&s_epd_style);
|
||||
lv_style_set_pad_all(&s_epd_style, 0);
|
||||
lv_style_set_radius(&s_epd_style, 0);
|
||||
lv_style_set_border_width(&s_epd_style, 0);
|
||||
|
||||
lv_theme_set_apply_cb(&s_epd_theme, app_ui_theme_apply);
|
||||
|
||||
lv_disp_set_theme(NULL, &s_epd_theme);
|
||||
|
||||
screen_cond = lv_obj_create(NULL);
|
||||
|
||||
container_topbar = lv_obj_create(screen_cond);
|
||||
|
||||
label_sunrise = lv_label_create(container_topbar);
|
||||
label_sunrise_time = lv_label_create(container_topbar);
|
||||
label_sunset = lv_label_create(container_topbar);
|
||||
label_sunset_time = lv_label_create(container_topbar);
|
||||
label_uvi = lv_label_create(container_topbar);
|
||||
label_uvi_value = lv_label_create(container_topbar);
|
||||
label_updated = lv_label_create(container_topbar);
|
||||
label_updated_time = lv_label_create(container_topbar);
|
||||
|
||||
line_topbar = lv_line_create(screen_cond);
|
||||
container_main = lv_obj_create(screen_cond);
|
||||
|
||||
label_wxicon = lv_label_create(container_main);
|
||||
label_temperature = lv_label_create(container_main);
|
||||
label_temperature_hi = lv_label_create(container_main);
|
||||
label_temperature_lo = lv_label_create(container_main);
|
||||
label_temperature_real = lv_label_create(container_main);
|
||||
label_temperature_real_desc = lv_label_create(container_main);
|
||||
label_temperature_unit = lv_label_create(container_main);
|
||||
label_temperature_hi_unit = lv_label_create(container_main);
|
||||
label_temperature_lo_unit = lv_label_create(container_main);
|
||||
label_temperature_real_unit = lv_label_create(container_main);
|
||||
label_humidity = lv_label_create(container_main);
|
||||
label_humidity_unit = lv_label_create(container_main);
|
||||
label_wind_level = lv_label_create(container_main);
|
||||
label_wind_direction = lv_label_create(container_main);
|
||||
label_wind_speed = lv_label_create(container_main);
|
||||
|
||||
/* Top bar parts */
|
||||
lv_obj_set_style_text_font(label_sunrise, &weather_icon_24, 0U);
|
||||
lv_obj_set_style_text_font(label_sunset, &weather_icon_24, 0U);
|
||||
lv_obj_set_style_text_font(label_uvi, &weather_icon_24, 0U);
|
||||
lv_obj_set_style_text_font(label_updated, &weather_icon_24, 0U);
|
||||
|
||||
lv_obj_set_style_text_font(label_sunrise_time, ¬o_sans_24, 0U);
|
||||
lv_obj_set_style_text_font(label_sunset_time, ¬o_sans_24, 0U);
|
||||
lv_obj_set_style_text_font(label_uvi_value, ¬o_sans_24, 0U);
|
||||
lv_obj_set_style_text_font(label_updated_time, ¬o_sans_24, 0U);
|
||||
|
||||
lv_label_set_text(label_sunrise, "\U0000F051");
|
||||
lv_label_set_text(label_sunset, "\U0000F052");
|
||||
lv_label_set_text(label_uvi, "\U0000F00D");
|
||||
lv_label_set_text(label_updated, "\U0000F04C");
|
||||
|
||||
lv_label_set_text(label_sunrise_time, "----/--/-- --:--:--");
|
||||
lv_label_set_text(label_sunset_time, "----/--/-- --:--:--");
|
||||
lv_label_set_text(label_uvi_value, "-");
|
||||
lv_label_set_text(label_updated_time, "----/--/-- --:--:--");
|
||||
|
||||
lv_obj_set_size(container_topbar, 960, 36);
|
||||
|
||||
lv_obj_set_width(label_sunrise, 32);
|
||||
lv_obj_set_width(label_sunset, 32);
|
||||
lv_obj_set_width(label_uvi, 32);
|
||||
lv_obj_set_width(label_updated, 32);
|
||||
|
||||
lv_obj_set_style_text_align(label_sunrise, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_sunset, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_uvi, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_updated, LV_TEXT_ALIGN_CENTER, 0);
|
||||
|
||||
lv_obj_set_style_text_align(label_sunrise_time, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_style_text_align(label_sunset_time, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_style_text_align(label_uvi_value, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_style_text_align(label_updated_time, LV_TEXT_ALIGN_LEFT, 0);
|
||||
|
||||
lv_obj_align(container_topbar, LV_ALIGN_TOP_LEFT, 0, 0);
|
||||
|
||||
lv_obj_align(label_sunrise, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
lv_obj_align(label_sunset, LV_ALIGN_LEFT_MID, 300, 0);
|
||||
lv_obj_align(label_uvi, LV_ALIGN_LEFT_MID, 600, 0);
|
||||
lv_obj_align(label_updated, LV_ALIGN_LEFT_MID, 680, 0);
|
||||
|
||||
lv_obj_align(label_sunrise_time, LV_ALIGN_LEFT_MID, 40, 3);
|
||||
lv_obj_align(label_sunset_time, LV_ALIGN_LEFT_MID, 340, 3);
|
||||
lv_obj_align(label_uvi_value, LV_ALIGN_LEFT_MID, 640, 3);
|
||||
lv_obj_align(label_updated_time, LV_ALIGN_LEFT_MID, 720, 3);
|
||||
|
||||
lv_line_set_points(line_topbar, points_line_topbar, 2);
|
||||
lv_obj_set_style_line_width(line_topbar, 1, 0);
|
||||
|
||||
/* Main parts */
|
||||
lv_obj_set_style_text_font(label_wxicon, &weather_icon_150, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_unit, &weather_icon_96, 0);
|
||||
lv_obj_set_style_text_font(label_humidity_unit, &weather_icon_96, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_hi_unit, &weather_icon_96, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_lo_unit, &weather_icon_96, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_real_unit, &weather_icon_96, 0);
|
||||
lv_obj_set_style_text_font(label_wind_direction, &weather_icon_96, 0);
|
||||
lv_obj_set_style_text_font(label_wind_level, &weather_icon_96, 0);
|
||||
|
||||
lv_obj_set_style_text_font(label_temperature, ¬o_sans_150, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_hi, ¬o_sans_96, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_lo, ¬o_sans_96, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_real, ¬o_sans_96, 0);
|
||||
lv_obj_set_style_text_font(label_temperature_real_desc, ¬o_sans_24, 0);
|
||||
lv_obj_set_style_text_font(label_humidity, ¬o_sans_96, 0);
|
||||
lv_obj_set_style_text_font(label_wind_speed, ¬o_sans_96, 0);
|
||||
|
||||
lv_label_set_text(label_wxicon, "\U0000F07B");
|
||||
lv_label_set_text(label_temperature_unit, "\U0000F03C");
|
||||
lv_label_set_text(label_temperature_hi_unit, "\U0000F058");
|
||||
lv_label_set_text(label_temperature_lo_unit, "\U0000F044");
|
||||
lv_label_set_text(label_temperature_real_unit, "\U0000F03C");
|
||||
lv_label_set_text(label_humidity_unit, "\U0000F07A");
|
||||
lv_label_set_text(label_wind_direction, "\U0000F0B1");
|
||||
lv_label_set_text(label_wind_level, "\U0000F0BA");
|
||||
|
||||
lv_label_set_text(label_temperature, "--");
|
||||
lv_label_set_text(label_temperature_hi, "--");
|
||||
lv_label_set_text(label_temperature_lo, "--");
|
||||
lv_label_set_text(label_temperature_real, "--");
|
||||
lv_label_set_text(label_temperature_real_desc, "Real\nFeel");
|
||||
lv_label_set_text(label_humidity, "---");
|
||||
lv_label_set_text(label_wind_speed, "----");
|
||||
|
||||
lv_obj_set_size(container_main, 960, 370);
|
||||
lv_obj_set_size(label_temperature_unit, 96, 96);
|
||||
lv_obj_set_size(label_temperature_hi_unit, 96, 96);
|
||||
lv_obj_set_size(label_temperature_lo_unit, 96, 96);
|
||||
lv_obj_set_size(label_temperature_real_unit, 96, 96);
|
||||
lv_obj_set_size(label_humidity_unit, 96, 150);
|
||||
lv_obj_set_size(label_wind_direction, 96, 96);
|
||||
lv_obj_set_size(label_wind_level, 96, 96);
|
||||
|
||||
lv_obj_set_width(label_wxicon, 200);
|
||||
lv_obj_set_width(label_temperature, 200);
|
||||
lv_obj_set_width(label_temperature_hi, 150);
|
||||
lv_obj_set_width(label_temperature_lo, 150);
|
||||
lv_obj_set_width(label_temperature_real, 150);
|
||||
lv_obj_set_width(label_temperature_real_desc, 50);
|
||||
lv_obj_set_width(label_humidity, 200);
|
||||
lv_obj_set_width(label_wind_speed, 200);
|
||||
|
||||
lv_obj_set_style_text_align(label_wxicon, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_temperature, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_hi, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_lo, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_real, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_real_desc, LV_TEXT_ALIGN_LEFT, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_unit, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_hi_unit, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_lo_unit, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_temperature_real_unit, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_humidity, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
lv_obj_set_style_text_align(label_humidity_unit, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_wind_direction, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_wind_level, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_set_style_text_align(label_wind_speed, LV_TEXT_ALIGN_RIGHT, 0);
|
||||
|
||||
lv_obj_align(container_main, LV_ALIGN_TOP_LEFT, 0, 38);
|
||||
|
||||
lv_obj_align(label_wxicon, LV_ALIGN_LEFT_MID, 0, 0);
|
||||
lv_obj_align(label_temperature_unit, LV_ALIGN_TOP_LEFT, 400, -20);
|
||||
lv_obj_align(label_temperature_hi_unit, LV_ALIGN_TOP_LEFT, 200, 115);
|
||||
lv_obj_align(label_temperature_lo_unit, LV_ALIGN_TOP_LEFT, 200, 235);
|
||||
|
||||
lv_obj_align(label_temperature, LV_ALIGN_TOP_LEFT, 200, 0);
|
||||
lv_obj_align(label_temperature_hi, LV_ALIGN_TOP_LEFT, 250, 150);
|
||||
lv_obj_align(label_temperature_lo, LV_ALIGN_TOP_LEFT, 250, 250);
|
||||
lv_obj_align(label_temperature_real, LV_ALIGN_TOP_LEFT, 650, 130);
|
||||
lv_obj_align(label_temperature_real_desc, LV_ALIGN_TOP_LEFT, 585, 165);
|
||||
lv_obj_align(label_humidity, LV_ALIGN_TOP_LEFT, 600, 10);
|
||||
lv_obj_align(label_humidity_unit, LV_ALIGN_TOP_LEFT, 800, -20);
|
||||
lv_obj_align(label_temperature_real_unit, LV_ALIGN_TOP_LEFT, 800, 120);
|
||||
lv_obj_align(label_wind_direction, LV_ALIGN_TOP_LEFT, 500, 230);
|
||||
lv_obj_align(label_wind_speed, LV_ALIGN_TOP_LEFT, 600, 250);
|
||||
lv_obj_align(label_wind_level, LV_ALIGN_TOP_LEFT, 815, 240);
|
||||
|
||||
lv_scr_load(screen_cond);
|
||||
app_lvgl_unlock();
|
||||
}
|
||||
|
||||
app_ui_queue_item_t item;
|
||||
|
||||
for (;;) {
|
||||
/* Receive update requests. */
|
||||
if (xQueueReceive(s_app_ui_update_queue, &item, portMAX_DELAY) == pdPASS) {
|
||||
if (app_lvgl_lock(portMAX_DELAY) == 0) {
|
||||
lv_obj_t *label = NULL;
|
||||
|
||||
switch (item.cmd) {
|
||||
case APP_UI_CMD_SUNRISE:
|
||||
label = label_sunrise_time;
|
||||
break;
|
||||
case APP_UI_CMD_SUNSET:
|
||||
label = label_sunset_time;
|
||||
break;
|
||||
case APP_UI_CMD_UVI:
|
||||
label = label_uvi_value;
|
||||
break;
|
||||
case APP_UI_CMD_COND:
|
||||
label = label_wxicon;
|
||||
break;
|
||||
case APP_UI_CMD_TEMP:
|
||||
label = label_temperature;
|
||||
break;
|
||||
case APP_UI_CMD_TEMP_HI:
|
||||
label = label_temperature_hi;
|
||||
break;
|
||||
case APP_UI_CMD_TEMP_LO:
|
||||
label = label_temperature_lo;
|
||||
break;
|
||||
case APP_UI_CMD_TEMP_REAL:
|
||||
label = label_temperature_real;
|
||||
break;
|
||||
case APP_UI_CMD_HUMID:
|
||||
label = label_humidity;
|
||||
break;
|
||||
case APP_UI_CMD_UPDATED:
|
||||
label = label_updated_time;
|
||||
break;
|
||||
case APP_UI_CMD_WIND_SPEED:
|
||||
label = label_wind_speed;
|
||||
break;
|
||||
case APP_UI_CMD_WIND_LEVEL:
|
||||
label = label_wind_level;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
lv_label_set_text(label, item.data);
|
||||
app_lvgl_unlock();
|
||||
}
|
||||
|
||||
free(item.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void app_ui_theme_apply(lv_theme_t *th, lv_obj_t *obj) {
|
||||
lv_obj_add_style(obj, &s_epd_style, 0);
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
/**/
|
||||
#include "esp_log.h"
|
||||
#include "esp_system.h"
|
||||
|
||||
/* FreeRTOS */
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
/* LVGL */
|
||||
#include "lvgl.h"
|
||||
|
||||
/* Private */
|
||||
#include "app_lvgl.h"
|
||||
|
||||
#define UI_WEATHER_TASK_HEAP 2048
|
||||
#define APP_LOG_TAG "UI_WX"
|
||||
|
||||
LV_FONT_DECLARE(noto_sans_96)
|
||||
LV_FONT_DECLARE(weather_icon_96)
|
||||
|
||||
static void app_ui_weather_task(void *pvParameters);
|
||||
|
||||
int app_ui_weather_init(void) {
|
||||
if (xTaskCreate(app_ui_weather_task, "UI_WX", UI_WEATHER_TASK_HEAP, NULL, 3, NULL) != pdPASS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "UI WX initialized.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void app_ui_weather_task(void *pvParameters) {
|
||||
lv_obj_t *main_label = NULL;
|
||||
if (app_lvgl_lock(portMAX_DELAY) == 0) {
|
||||
main_label = lv_label_create(lv_scr_act());
|
||||
lv_label_set_text(main_label, "\U0000F052");
|
||||
lv_obj_set_width(main_label, 960);
|
||||
lv_obj_set_style_text_align(main_label, LV_TEXT_ALIGN_CENTER, 0);
|
||||
lv_obj_align(main_label, LV_ALIGN_CENTER, 0, 0);
|
||||
lv_obj_set_style_text_font(main_label, &weather_icon_96, 0);
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "UI label created");
|
||||
|
||||
app_lvgl_unlock();
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
}
|
0
main/app_weather.c
Normal file
0
main/app_weather.c
Normal file
10063
main/assets/fonts/noto_sans_150.c
Normal file
10063
main/assets/fonts/noto_sans_150.c
Normal file
File diff suppressed because it is too large
Load Diff
1277
main/assets/fonts/noto_sans_24.c
Normal file
1277
main/assets/fonts/noto_sans_24.c
Normal file
File diff suppressed because it is too large
Load Diff
18388
main/assets/fonts/noto_sans_240.c
Normal file
18388
main/assets/fonts/noto_sans_240.c
Normal file
File diff suppressed because it is too large
Load Diff
60988
main/assets/fonts/weather_icon_150.c
Normal file
60988
main/assets/fonts/weather_icon_150.c
Normal file
File diff suppressed because it is too large
Load Diff
5784
main/assets/fonts/weather_icon_24.c
Normal file
5784
main/assets/fonts/weather_icon_24.c
Normal file
File diff suppressed because it is too large
Load Diff
115844
main/assets/fonts/weather_icon_240.c
Normal file
115844
main/assets/fonts/weather_icon_240.c
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -4,7 +4,10 @@
|
|||
#include <stdint.h>
|
||||
|
||||
int app_lvgl_init(void);
|
||||
int app_lvgl_deinit(void);
|
||||
int app_lvgl_lock(uint32_t ms);
|
||||
int app_lvgl_unlock(void);
|
||||
int app_lvgl_start_flush(void);
|
||||
int app_lvgl_wait_flush(uint32_t timeout_ms);
|
||||
|
||||
#endif
|
|
@ -2,6 +2,9 @@
|
|||
#define APP_MQTT_H
|
||||
|
||||
int app_mqtt_init(void);
|
||||
int app_mqtt_publish(char *topic, char *payload);
|
||||
int app_mqtt_publish(char *topic, uint8_t *payload, uint32_t payload_len);
|
||||
int app_mqtt_subscribe(char *topic);
|
||||
int app_mqtt_unsubscribe(char *topic);
|
||||
int app_mqtt_poll(char **topic, uint8_t **payload, uint32_t *payload_len, uint32_t timeout);
|
||||
|
||||
#endif
|
24
main/include/app_ui.h
Normal file
24
main/include/app_ui.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#ifndef APP_UI_H
|
||||
#define APP_UI_H
|
||||
|
||||
typedef enum {
|
||||
APP_UI_CMD_SUNRISE,
|
||||
APP_UI_CMD_SUNSET,
|
||||
APP_UI_CMD_UVI,
|
||||
APP_UI_CMD_UPDATED,
|
||||
APP_UI_CMD_TEMP,
|
||||
APP_UI_CMD_COND,
|
||||
APP_UI_CMD_TEMP_HI,
|
||||
APP_UI_CMD_TEMP_LO,
|
||||
APP_UI_CMD_HUMID,
|
||||
APP_UI_CMD_TEMP_REAL,
|
||||
APP_UI_CMD_WIND_DIR,
|
||||
APP_UI_CMD_WIND_SPEED,
|
||||
APP_UI_CMD_WIND_LEVEL,
|
||||
} app_ui_cmd_t;
|
||||
|
||||
int app_ui_init(void);
|
||||
|
||||
int app_ui_update(app_ui_cmd_t cmd, char *data);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user