LVGL -- Prosta stacja pogodowa

Tu wszystko o LVGL
ODPOWIEDZ
Awatar użytkownika
SunRiver
Użytkownik
Posty: 1353
Rejestracja: 08 paź 2017, 11:27
Lokalizacja: Festung Oppeln
Kontakt:

LVGL -- Prosta stacja pogodowa

Post autor: SunRiver »

Teraz zrobimy prostą stację pogodową WIFI z użyciem LVGL naszego LCD 2,4" z dotykiem XPT2046.
Użyjemy tu API pogodowego - OpenWeatherMap. Zwraca ono dane w formacie JSON. Oczywiście by uzyskać dane musimy się zarejestrować w serwisie OpenWeatherMap i uzyskać w ten sposób klucz API.

kolejną rzeczą jest dodanie zależności w pliku idf_components.yml powinny być już tam ale warto sprawdzić.
  1.  
  2. dependencies:
  3.   lvgl:
  4.     path: components/lvgl
  5.   lvgl_esp32_drivers:
  6.     path: components/lvgl_esp32_drivers
  7.   esp_http_client:
  8.     path: $ENV{IDF_PATH}/components/esp_http_client
  9.  
  10.  
Musicie też sobie przygotować ikony pogodowe w formacie c dla opcji : słonecznie , deszczowo, pochmurno i zapisać je jako pliki.c w katalogu projektu. Tu warto użyć np dostępnego online narzędzia LVGL Image Converter.
Jeśli wszystko się zgadza możemy napisać prosty kod:
  1.  
  2. #include "freertos/FreeRTOS.h"
  3. #include "freertos/task.h"
  4. #include "esp_wifi.h"
  5. #include "esp_log.h"
  6. #include "nvs_flash.h"
  7. #include "esp_http_client.h"
  8. #include "cJSON.h"
  9. #include "lvgl/lvgl.h"
  10. #include "lvgl_helpers.h"
  11.  
  12. // Deklaracja ikon pogodowych
  13. extern lv_img_dsc_t sunny_icon;
  14. extern lv_img_dsc_t cloudy_icon;
  15. extern lv_img_dsc_t rainy_icon;
  16.  
  17. #define WIFI_SSID "your_wifi_ssid"
  18. #define WIFI_PASS "your_wifi_password"
  19. #define WEATHER_API_KEY "your_openweathermap_api_key"
  20. #define CITY_ID "your_city_id" // Find your city ID on OpenWeatherMap
  21. #define WEATHER_URL "http://api.openweathermap.org/data/2.5/weather?id=" CITY_ID "&appid=" WEATHER_API_KEY "&units=metric"
  22.  
  23. static const char *TAG = "weather_station";
  24.  
  25. // Obiekty LVGL do wyświetlania danych pogodowych
  26. static lv_obj_t *label_temp;
  27. static lv_obj_t *label_humidity;
  28. static lv_obj_t *label_pressure;
  29. static lv_obj_t *img_weather_icon;
  30.  
  31. static void lv_tick_task(void *arg) {
  32.     (void) arg;
  33.     lv_tick_inc(portTICK_PERIOD_MS);
  34. }
  35.  
  36. static void update_weather_display(const char* temp, const char* humidity, const char* pressure, const char* icon) {
  37.     lv_label_set_text_fmt(label_temp, "Temp: %s °C", temp);
  38.     lv_label_set_text_fmt(label_humidity, "Humidity: %s %%", humidity);
  39.     lv_label_set_text_fmt(label_pressure, "Pressure: %s hPa", pressure);
  40.  
  41.     if (strcmp(icon, "01d") == 0 || strcmp(icon, "01n") == 0) {
  42.         lv_img_set_src(img_weather_icon, &sunny_icon);
  43.     } else if (strcmp(icon, "02d") == 0 || strcmp(icon, "02n") == 0 ||
  44.                strcmp(icon, "03d") == 0 || strcmp(icon, "03n") == 0 ||
  45.                strcmp(icon, "04d") == 0 || strcmp(icon, "04n") == 0) {
  46.         lv_img_set_src(img_weather_icon, &cloudy_icon);
  47.     } else if (strcmp(icon, "09d") == 0 || strcmp(icon, "09n") == 0 ||
  48.                strcmp(icon, "10d") == 0 || strcmp(icon, "10n") == 0) {
  49.         lv_img_set_src(img_weather_icon, &rainy_icon);
  50.     }
  51. }
  52.  
  53. static void http_get_weather_data(void *pvParameters) {
  54.     esp_http_client_config_t config = {
  55.         .url = WEATHER_URL,
  56.     };
  57.     esp_http_client_handle_t client = esp_http_client_init(&config);
  58.     esp_err_t err = esp_http_client_perform(client);
  59.  
  60.     if (err == ESP_OK) {
  61.         int len = esp_http_client_get_content_length(client);
  62.         char *buffer = malloc(len + 1);
  63.         esp_http_client_read(client, buffer, len);
  64.         buffer[len] = 0;
  65.  
  66.         cJSON *json = cJSON_Parse(buffer);
  67.         if (json != NULL) {
  68.             cJSON *main = cJSON_GetObjectItemCaseSensitive(json, "main");
  69.             cJSON *weather = cJSON_GetObjectItemCaseSensitive(json, "weather");
  70.             if (main != NULL && weather != NULL) {
  71.                 cJSON *temp = cJSON_GetObjectItemCaseSensitive(main, "temp");
  72.                 cJSON *humidity = cJSON_GetObjectItemCaseSensitive(main, "humidity");
  73.                 cJSON *pressure = cJSON_GetObjectItemCaseSensitive(main, "pressure");
  74.                 cJSON *weather_item = cJSON_GetArrayItem(weather, 0);
  75.                 cJSON *icon = cJSON_GetObjectItemCaseSensitive(weather_item, "icon");
  76.  
  77.                 if (temp != NULL && humidity != NULL && pressure != NULL && icon != NULL) {
  78.                     ESP_LOGI(TAG, "Temp: %.2f °C, Humidity: %d %%, Pressure: %d hPa, Icon: %s",
  79.                              temp->valuedouble, humidity->valueint, pressure->valueint, icon->valuestring);
  80.                     char temp_str[16], humidity_str[16], pressure_str[16];
  81.                     snprintf(temp_str, sizeof(temp_str), "%.1f", temp->valuedouble);
  82.                     snprintf(humidity_str, sizeof(humidity_str), "%d", humidity->valueint);
  83.                     snprintf(pressure_str, sizeof(pressure_str), "%d", pressure->valueint);
  84.                     update_weather_display(temp_str, humidity_str, pressure_str, icon->valuestring);
  85.                 }
  86.             }
  87.             cJSON_Delete(json);
  88.         }
  89.  
  90.         free(buffer);
  91.     } else {
  92.         ESP_LOGE(TAG, "HTTP GET request failed: %s", esp_err_to_name(err));
  93.     }
  94.  
  95.     esp_http_client_cleanup(client);
  96.     vTaskDelete(NULL);
  97. }
  98.  
  99. static void wifi_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
  100.     if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
  101.         esp_wifi_connect();
  102.     } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
  103.         esp_wifi_connect();
  104.     } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
  105.         xTaskCreate(http_get_weather_data, "http_get_weather_data", 4096, NULL, 5, NULL);
  106.     }
  107. }
  108.  
  109. void wifi_init(void) {
  110.     esp_netif_init();
  111.     esp_event_loop_create_default();
  112.     esp_netif_create_default_wifi_sta();
  113.     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
  114.     esp_wifi_init(&cfg);
  115.  
  116.     esp_event_handler_instance_t instance_any_id;
  117.     esp_event_handler_instance_t instance_got_ip;
  118.     esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, &instance_any_id);
  119.     esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, &instance_got_ip);
  120.  
  121.     wifi_config_t wifi_config = {
  122.         .sta = {
  123.             .ssid = WIFI_SSID,
  124.             .password = WIFI_PASS,
  125.         },
  126.     };
  127.     esp_wifi_set_mode(WIFI_MODE_STA);
  128.     esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
  129.     esp_wifi_start();
  130. }
  131.  
  132. void app_main() {
  133.     // Inicjalizacja NVS
  134.     esp_err_t ret = nvs_flash_init();
  135.     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  136.         ESP_ERROR_CHECK(nvs_flash_erase());
  137.         ret = nvs_flash_init();
  138.     }
  139.     ESP_ERROR_CHECK(ret);
  140.  
  141.     // Inicjalizacja Wi-Fi
  142.     wifi_init();
  143.  
  144.     // Inicjalizacja LVGL
  145.     lv_init();
  146.  
  147.     // Inicjalizacja sterownika ekranu i dotyku
  148.     lvgl_driver_init();
  149.  
  150.     // Inicjalizacja bufora dla LVGL
  151.     static lv_disp_draw_buf_t draw_buf;
  152.     static lv_color_t buf1[DISP_BUF_SIZE];
  153.     lv_disp_draw_buf_init(&draw_buf, buf1, NULL, DISP_BUF_SIZE);
  154.  
  155.     // Inicjalizacja wyświetlacza
  156.     static lv_disp_drv_t disp_drv;
  157.     lv_disp_drv_init(&disp_drv);
  158.     disp_drv.draw_buf = &draw_buf;
  159.     disp_drv.flush_cb = disp_driver_flush;
  160.     disp_drv.hor_res = 320; // Dostępna rozdzielczość pozioma
  161.     disp_drv.ver_res = 240; // Dostępna rozdzielczość pionowa
  162.     lv_disp_drv_register(&disp_drv);
  163.  
  164.     // Inicjalizacja sterownika dotykowego
  165.     static lv_indev_drv_t indev_drv;
  166.     lv_indev_drv_init(&indev_drv);
  167.     indev_drv.type = LV_INDEV_TYPE_POINTER;
  168.     indev_drv.read_cb = touch_driver_read;
  169.     lv_indev_drv_register(&indev_drv);
  170.  
  171.     // Inicjalizacja ticków dla LVGL
  172.     const esp_timer_create_args_t periodic_timer_args = {
  173.         .callback = &lv_tick_task,
  174.         .name = "periodic_gui"
  175.     };
  176.     esp_timer_handle_t periodic_timer;
  177.     esp_timer_create(&periodic_timer_args, &periodic_timer);
  178.     esp_timer_start_periodic(periodic_timer, 1 * 1000U);
  179.  
  180.     // Utworzenie obiektów GUI
  181.     label_temp = lv_label_create(lv_scr_act());
  182.     lv_obj_align(label_temp, LV_ALIGN_TOP_LEFT, 10, 10);
  183.     label_humidity = lv_label_create(lv_scr_act());
  184.     lv_obj_align(label_humidity, LV_ALIGN_TOP_LEFT, 10, 40);
  185.     label_pressure = lv_label_create(lv_scr_act());
  186.     lv_obj_align(label_pressure, LV_ALIGN_TOP_LEFT, 10, 70);
  187.     img_weather_icon = lv_img_create(lv_scr_act());
  188.     lv_obj_align(img_weather_icon, LV_ALIGN_CENTER, 0, 0);
  189.  
  190.     // Główna pętla
  191.     while (1) {
  192.         lv_task_handler();
  193.         vTaskDelay(pdMS_TO_TICKS(10));
  194.     }
  195. }
  196.  
  197.  
Zakładam użycie 3ch ikon pogodowych w tym przykładzie:
sunny_icon.c
cloudy_icon.c
rainy_icon.c

Przykład dla sunny_icon.c
  1.  
  2. #include "lvgl/lvgl.h"
  3.  
  4. LV_IMG_DECLARE(sunny_icon);
  5.  
  6. lv_img_dsc_t sunny_icon = {
  7.     .header.always_zero = 0,
  8.     .header.w = 64,
  9.     .header.h = 64,
  10.     .data_size = sizeof(sunny_icon_map),
  11.     .header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA,
  12.     .data = sunny_icon_map,
  13. };
  14.  
w taki sam sposób dodajemy kolejne icony.

Oczywiście przed kompilacją należy zamienić your_wifi_ssid, your_wifi_password, your_openweathermap_api_key i your_city_id na odpowiednie wartości.
Można również dodać więcej ikon pogodowych, aby obsłużyć inne warunki pogodowe.

To tylko taki prosty przykładzik.
ODPOWIEDZ

Wróć do „LVGL - dla ESP32”