Rewrite weather rendering code, use LUT instead of switch block.
Signed-off-by: imi415 <imi415@imi.moe>
This commit is contained in:
parent
9cd7aba20b
commit
9f44ebe114
|
@ -4,6 +4,7 @@ SRCS
|
|||
"app_main.c"
|
||||
"app_mqtt.c"
|
||||
"app_ui.c"
|
||||
"app_weather.c"
|
||||
"app_wifi.c"
|
||||
"assets/fonts/noto_sans_24.c"
|
||||
"assets/fonts/noto_sans_96.c"
|
||||
|
|
|
@ -14,9 +14,9 @@
|
|||
#include "esp_system.h"
|
||||
|
||||
/* EPD driver */
|
||||
#include "epd_board_specific.h"
|
||||
#include "epd_driver.h"
|
||||
#include "epd_highlevel.h"
|
||||
#include "epd_board_specific.h"
|
||||
|
||||
/* LVGL */
|
||||
#include "lvgl.h"
|
||||
|
@ -55,10 +55,6 @@ int app_lvgl_init(void) {
|
|||
s_epd_hl = epd_hl_init(EPD_BUILTIN_WAVEFORM);
|
||||
s_screen_buf = (lv_color_t *)epd_hl_get_framebuffer(&s_epd_hl);
|
||||
|
||||
epd_poweron();
|
||||
epd_fullclear(&s_epd_hl, s_temp);
|
||||
epd_poweroff();
|
||||
|
||||
/* Initialize LVGL */
|
||||
lv_init();
|
||||
lv_log_register_print_cb(app_lvgl_log_cb);
|
||||
|
@ -86,7 +82,7 @@ int app_lvgl_init(void) {
|
|||
}
|
||||
|
||||
s_lvgl_flush_cmd_semphr = xSemaphoreCreateBinary();
|
||||
if(s_lvgl_flush_cmd_semphr == NULL) {
|
||||
if (s_lvgl_flush_cmd_semphr == NULL) {
|
||||
ESP_LOGE(APP_LOG_TAG, "Failed to create flush command semaphore.");
|
||||
return -3;
|
||||
}
|
||||
|
@ -143,12 +139,16 @@ int app_lvgl_wait_flush(uint32_t timeout_ms) {
|
|||
}
|
||||
|
||||
static void app_lvgl_task(void *pvParameters) {
|
||||
if(xSemaphoreTake(s_lvgl_flush_cmd_semphr, portMAX_DELAY) != pdPASS) {
|
||||
if (xSemaphoreTake(s_lvgl_flush_cmd_semphr, portMAX_DELAY) != pdPASS) {
|
||||
vTaskSuspend(NULL);
|
||||
}
|
||||
|
||||
ESP_LOGI(APP_LOG_TAG, "Received flush GO signal, start flushing...");
|
||||
|
||||
epd_poweron();
|
||||
epd_fullclear(&s_epd_hl, s_temp);
|
||||
epd_poweroff();
|
||||
|
||||
for (;;) {
|
||||
if (app_lvgl_lock(50) == 0) {
|
||||
lv_timer_handler();
|
||||
|
|
301
main/app_main.c
301
main/app_main.c
|
@ -27,6 +27,7 @@
|
|||
#include "app_mqtt.h"
|
||||
#include "app_ui.h"
|
||||
#include "app_wifi.h"
|
||||
#include "app_weather.h"
|
||||
|
||||
#define APP_WAKE_INTERVAL_MS (30 * 60 * 1000)
|
||||
|
||||
|
@ -34,11 +35,6 @@
|
|||
|
||||
RTC_NOINIT_ATTR app_bkp_ram_t g_app_bkp;
|
||||
|
||||
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();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
|
@ -72,12 +68,12 @@ void app_main(void) {
|
|||
goto next_round;
|
||||
}
|
||||
|
||||
if (app_update_ui() != 0) {
|
||||
if (app_weather_update() != 0) {
|
||||
goto next_round;
|
||||
}
|
||||
|
||||
app_lvgl_start_flush();
|
||||
if(app_lvgl_wait_flush(5000) < 0) {
|
||||
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;
|
||||
}
|
||||
|
@ -88,294 +84,3 @@ next_round:
|
|||
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;
|
||||
}
|
|
@ -194,9 +194,7 @@ static void app_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32
|
|||
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);
|
||||
|
||||
case MQTT_EVENT_DATA: {
|
||||
app_mqtt_queue_item_t item;
|
||||
item.topic = malloc(event->topic_len + 1);
|
||||
if (item.topic == NULL) {
|
||||
|
@ -222,9 +220,9 @@ static void app_mqtt_event_handler(void *arg, esp_event_base_t event_base, int32
|
|||
|
||||
free(item.topic);
|
||||
free(item.payload);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -262,7 +262,7 @@ static void app_ui_task(void *pvParameters) {
|
|||
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_width(label_wind_speed, 220);
|
||||
|
||||
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);
|
||||
|
@ -296,7 +296,7 @@ static void app_ui_task(void *pvParameters) {
|
|||
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_speed, LV_ALIGN_TOP_LEFT, 580, 250);
|
||||
lv_obj_align(label_wind_level, LV_ALIGN_TOP_LEFT, 815, 240);
|
||||
|
||||
lv_scr_load(screen_cond);
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
/* MISC */
|
||||
#include "cbor.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
/* APP */
|
||||
#include "app_bkp_ram.h"
|
||||
#include "app_mqtt.h"
|
||||
#include "app_ui.h"
|
||||
|
||||
#define APP_CITY_ID (CONFIG_APP_WX_CITY_ID)
|
||||
|
||||
#define APP_LOG_TAG "WX"
|
||||
|
||||
static char *s_condition_icon_table_day[] = {
|
||||
[1] = "\U0000F00D", [2] = "\U0000F00D", [3] = "\U0000F00D", [4] = "\U0000F00D", [5] = "\U0000F00D", /* 晴 */
|
||||
[6] = "\U0000F00C", [7] = "\U0000F00C", /* 大部晴朗 */
|
||||
[8] = "\U0000F002", [9] = "\U0000F002", [10] = "\U0000F002", [11] = "\U0000F002", [80] = "\U0000F002", /* 多云 */
|
||||
[81] = "\U0000F002", [82] = "\U0000F002", /* 多云 */
|
||||
[12] = "\U0000F00C", /* 少云 */
|
||||
[13] = "\U0000F013", [14] = "\U0000F013", [36] = "\U0000F013", [85] = "\U0000F013", /* 阴 */
|
||||
[15] = "\U0000F008", [16] = "\U0000F008", [17] = "\U0000F008", [18] = "\U0000F008", [19] = "\U0000F008", /* 阵雨 */
|
||||
[86] = "\U0000F008", /* 阵雨 */
|
||||
[20] = "\U0000F008", [21] = "\U0000F008", [22] = "\U0000F008", [23] = "\U0000F008", /* 局部阵雨 小阵雨 强阵雨 */
|
||||
[51] = "\U0000F008", [52] = "\U0000F008", [53] = "\U0000F008", [54] = "\U0000F008", /* 小中大雨 */
|
||||
[69] = "\U0000F008", [70] = "\U0000F008", /* 大暴雨 */
|
||||
[55] = "\U0000F008", [56] = "\U0000F008", [57] = "\U0000F008", /* 暴雨 大 特大 */
|
||||
[66] = "\U0000F008", [67] = "\U0000F008", [68] = "\U0000F008", /* 小中大雨 */
|
||||
[78] = "\U0000F008", /* 雨 */
|
||||
[91] = "\U0000F008", [92] = "\U0000F008", [93] = "\U0000F008", /* 小-中-大-暴雨 */
|
||||
[24] = "\U0000F00A", [25] = "\U0000F00A", /* 阵雪 小阵雪 */
|
||||
[58] = "\U0000F00A", [59] = "\U0000F00A", [60] = "\U0000F00A", [61] = "\U0000F00A", /* 小中暴雪 */
|
||||
[62] = "\U0000F00A", /* 暴雪 */
|
||||
[71] = "\U0000F00A", [72] = "\U0000F00A", [73] = "\U0000F00A", /* 小雪 */
|
||||
[74] = "\U0000F00A", [75] = "\U0000F00A", [76] = "\U0000F00A", [77] = "\U0000F00A", /* 大雪 雪 */
|
||||
[94] = "\U0000F00A", /* 小-中雪 */
|
||||
[26] = "\U0000F003", [27] = "\U0000F003", [28] = "\U0000F003", [83] = "\U0000F003", [84] = "\U0000F003", /* 雾 冻 */
|
||||
[29] = "\U0000F082", /* 沙尘暴 */
|
||||
[30] = "\U0000F063", [31] = "\U0000F063", [32] = "\U0000F063", /* 浮尘 尘卷风 扬沙 */
|
||||
[33] = "\U0000F082", /* 强沙尘暴 */
|
||||
[34] = "\U0000F0B6", [35] = "\U0000F0B6", [79] = "\U0000F0B6", /* 霾 */
|
||||
[37] = "\U0000F010", [38] = "\U0000F010", [39] = "\U0000F010", [40] = "\U0000F010", [41] = "\U0000F010", /* 雷雨 */
|
||||
[87] = "\U0000F010", [88] = "\U0000F010", [89] = "\U0000F010", [90] = "\U0000F010", /* 雷阵雨 */
|
||||
[42] = "\U0000F005", /* 雷电 */
|
||||
[43] = "\U0000F005", /* 雷暴 */
|
||||
[44] = "\U0000F068", [45] = "\U0000F068", /* 雷阵雨伴有冰雹 */
|
||||
[46] = "\U0000F004", [47] = "\U0000F004", [48] = "\U0000F004", /* 冰雹 冰针 冰粒*/
|
||||
[49] = "\U0000F006", [50] = "\U0000F006", /* 雨夹雪 */
|
||||
[64] = "\U0000F006", [65] = "\U0000F006", /* 冻雨 */
|
||||
};
|
||||
|
||||
static char *s_wind_levels[] = {
|
||||
"\U0000F0B7", "\U0000F0B8", "\U0000F0B9", "\U0000F0BA", /* 0-3 */
|
||||
"\U0000F0BB", "\U0000F0BC", "\U0000F0BD", "\U0000F0BE", /* 4-7 */
|
||||
"\U0000F0BF", "\U0000F0C0", "\U0000F0C1", "\U0000F0C2", /* 8-11 */
|
||||
"\U0000F0C3" /* 12 */
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
app_ui_cmd_t cmd;
|
||||
char *key;
|
||||
} app_weather_condition_kv_t;
|
||||
|
||||
static app_weather_condition_kv_t s_condition_kv[] = {
|
||||
{.cmd = APP_UI_CMD_SUNRISE, .key = "sunRise"},
|
||||
{.cmd = APP_UI_CMD_SUNSET, .key = "sunSet"},
|
||||
{.cmd = APP_UI_CMD_UVI, .key = "uvi"},
|
||||
{.cmd = APP_UI_CMD_UPDATED, .key = "updatetime"},
|
||||
{.cmd = APP_UI_CMD_TEMP, .key = "temp"},
|
||||
{.cmd = APP_UI_CMD_HUMID, .key = "humidity"},
|
||||
{.cmd = APP_UI_CMD_TEMP_REAL, .key = "realFeel"},
|
||||
{.cmd = APP_UI_CMD_WIND_SPEED, .key = "windSpeed"},
|
||||
{.cmd = APP_UI_CMD_WIND_LEVEL, .key = "windLevel"},
|
||||
{.cmd = APP_UI_CMD_COND, .key = "conditionId"},
|
||||
};
|
||||
|
||||
static int wxapi_request(char *api_type);
|
||||
static CborError get_condition_string(CborValue *it, char *key, char **value, uint32_t *size);
|
||||
static int windlevel_to_font(char *input, char **output);
|
||||
static int condition_to_font(char *input, char **output);
|
||||
|
||||
int app_weather_update(void) {
|
||||
char *topic;
|
||||
uint8_t *payload;
|
||||
uint32_t payload_len;
|
||||
|
||||
app_mqtt_subscribe("iot/weather/ESP32_Weather/response");
|
||||
|
||||
if (wxapi_request("condition") < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (uint32_t i = 0; i < sizeof(s_condition_kv) / sizeof(app_weather_condition_kv_t); i++) {
|
||||
if (get_condition_string(&it, s_condition_kv[i].key, &str, &size) == CborNoError) {
|
||||
if (s_condition_kv[i].cmd == APP_UI_CMD_WIND_LEVEL) {
|
||||
windlevel_to_font(str, &str);
|
||||
} else if (s_condition_kv[i].cmd == APP_UI_CMD_COND) {
|
||||
condition_to_font(str, &str);
|
||||
}
|
||||
|
||||
app_ui_update(s_condition_kv[i].cmd, str);
|
||||
free(str);
|
||||
}
|
||||
}
|
||||
|
||||
free(topic);
|
||||
free(payload);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wxapi_request(char *api_type) {
|
||||
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, api_type);
|
||||
|
||||
cbor_encode_text_stringz(&map_encoder, "city_id");
|
||||
cbor_encode_uint(&map_encoder, APP_CITY_ID);
|
||||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int condition_to_font(char *input, char **output) {
|
||||
*output = malloc(4);
|
||||
if (*output == NULL) return -1;
|
||||
|
||||
int wx_id = strtol(input, NULL, 10);
|
||||
|
||||
char *unicode = s_condition_icon_table_day[wx_id % sizeof(s_condition_icon_table_day)];
|
||||
|
||||
snprintf(*output, 4, "%s", unicode);
|
||||
free(input);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int windlevel_to_font(char *input, char **output) {
|
||||
*output = malloc(4);
|
||||
if (*output == NULL) return -1;
|
||||
|
||||
int level = strtol(input, NULL, 10);
|
||||
char *unicode = s_wind_levels[level % sizeof(s_wind_levels)];
|
||||
|
||||
snprintf(*output, 4, "%s", unicode);
|
||||
free(input);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static CborError 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;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef APP_WEATHER_H
|
||||
#define APP_WEATHER_H
|
||||
|
||||
int app_weather_update(void);
|
||||
|
||||
#endif // APP_WEATHER_H
|
Loading…
Reference in New Issue