229浏览
查看: 229|回复: 8

[项目] 【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

[复制链接]
【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图2

ESP32-CYD(2432S028)液晶2.8寸屏开发板使用ESP32-WROOM-32模块作为主控,主控是一款双核MCU,集成了Wi-Fi和蓝牙功能,主频可达240MHz,具有520KB的SRAM、448KB的ROM,闪存容量为4MB+4MB,显示分辨率为240x320,采用电阻式触控式屏幕。该模块包括LCD显示器、背光控制电路、触控式屏幕控制电路、扬声器驱动电路、光敏电路和RGB LED控制电路。支持TF卡界面、序列界面、温湿度感测器界面(DHT11界面)和保留的IO口界面,该模块支持在Arduino IDE、ESP IDE、MicroPython和Mixly中进行开发。

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 13:41:53

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

安装TFT_eSPI、XPT2046_Touchscreen、BasicLinearAlgebra和LVGL库
网址:
TFT_eSPI库的网址:https://github.com/Bodmer/TFT_eSPI
XPT2046_Touchscreen库的网址: https://github.com/PaulStoffregen/XPT2046_Touchscreen
BasicLinearAlgebra库:https://github.com/tomstewart89/BasicLinearAlgebra

要正确使用 TFT_eSPI 库,需要根据不同开发板与TFT屏幕正确配置User_Setup.h和lv_conf.h文件。

LVGL中文开发手册:https://lvgl.100ask.net/master/

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图2

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 13:45:10

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

安装 ArduinoJson 库对于此项目,您需要安装 ArduinoJSON 库,以便在向 WorldTimeAPI 发出请求时处理 JSON 响应。
在 Arduino IDE 中,转到 Sketch > Include Library > Manage Libraries。搜索 ArduinoJSON 并安装 Benoit Blanchon 提供的库。我们使用的是 7.0.4 版本。我们建议使用相同的版本。

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1
回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 13:49:51

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

ESP32 CYD 气象站 – weather_images.h 文件
要使用 LVGL 加载自定义图像,您需要创建一个名为 weather_images.h 的额外文件,该文件必须放在 sketch 文件夹中。我们已经为您准备了该文件。为了加载此气象站项目的自定义图像,您需要下载这个文件。

重要提示:weather_images.h 文件应放置在工程的 sketch 文件夹中的 .ino 文件旁边。

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 13:51:56

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站


为了获得您所在位置的准确天气描述,我们将使用免费的 Open-Meteo API(https://open-meteo.com/en/docs/cma-api)。要从 API 获取数据,ESP32 需要连接到互联网,因此您需要在周围环境中安装路由器,以便 ESP32 可以连接到它。



【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1
回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 13:55:41

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

  【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
  项目实验之二十五:带 LVGL 的 ESP32 CYD:气象站(天气描述、温度和湿度)

实验开源代码

  1. /*
  2.   【Arduino】168种传感器模块系列实验(资料代码+仿真编程+图形编程)
  3.   实验二百三十八:ESP32开发板WiFi蓝牙2.8寸240*320智能液晶显示屏带触摸屏TFT模块
  4.   项目实验之二十五:带 LVGL 的 ESP32 CYD:气象站(天气描述、温度和湿度)
  5. */
  6. #include <lvgl.h>
  7. #include <TFT_eSPI.h>
  8. #include "weather_images.h"
  9. #include <WiFi.h>
  10. #include <HTTPClient.h>
  11. #include <ArduinoJson.h>
  12. // Replace with your network credentials
  13. const char* ssid = "zhz3";
  14. const char* password = "z156721";
  15. // Replace with the latitude and longitude to where you want to get the weather
  16. String latitude = "41.14961";
  17. String longitude = "-8.61099";
  18. // Enter your location
  19. String location = "Porto";
  20. // Type the timezone you want to get the time for
  21. String timezone = "Europe/Lisbon";
  22. // Store date and time
  23. String current_date;
  24. String last_weather_update;
  25. String temperature;
  26. String humidity;
  27. int is_day;
  28. int weather_code = 0;
  29. String weather_description;
  30. // SET VARIABLE TO 0 FOR TEMPERATURE IN FAHRENHEIT DEGREES
  31. #define TEMP_CELSIUS 1
  32. #if TEMP_CELSIUS
  33.   String temperature_unit = "";
  34.   const char degree_symbol[] = "\u00B0C";
  35. #else
  36.   String temperature_unit = "&temperature_unit=fahrenheit";
  37.   const char degree_symbol[] = "\u00B0F";
  38. #endif
  39. #define SCREEN_WIDTH 240
  40. #define SCREEN_HEIGHT 320
  41. #define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
  42. uint32_t draw_buf[DRAW_BUF_SIZE / 4];
  43. // If logging is enabled, it will inform the user about what is happening in the library
  44. void log_print(lv_log_level_t level, const char * buf) {
  45.   LV_UNUSED(level);
  46.   Serial.println(buf);
  47.   Serial.flush();
  48. }
  49. static lv_obj_t * weather_image;
  50. static lv_obj_t * text_label_date;
  51. static lv_obj_t * text_label_temperature;
  52. static lv_obj_t * text_label_humidity;
  53. static lv_obj_t * text_label_weather_description;
  54. static lv_obj_t * text_label_time_location;
  55. static void timer_cb(lv_timer_t * timer){
  56.   LV_UNUSED(timer);
  57.   get_weather_data();
  58.   get_weather_description(weather_code);
  59.   lv_label_set_text(text_label_date, current_date.c_str());
  60.   lv_label_set_text(text_label_temperature, String("      " + temperature + degree_symbol).c_str());
  61.   lv_label_set_text(text_label_humidity, String("   " + humidity + "%").c_str());
  62.   lv_label_set_text(text_label_weather_description, weather_description.c_str());
  63.   lv_label_set_text(text_label_time_location, String("Last Update: " + last_weather_update + "  |  " + location).c_str());
  64. }
  65. void lv_create_main_gui(void) {
  66.   LV_IMAGE_DECLARE(image_weather_sun);
  67.   LV_IMAGE_DECLARE(image_weather_cloud);
  68.   LV_IMAGE_DECLARE(image_weather_rain);
  69.   LV_IMAGE_DECLARE(image_weather_thunder);
  70.   LV_IMAGE_DECLARE(image_weather_snow);
  71.   LV_IMAGE_DECLARE(image_weather_night);
  72.   LV_IMAGE_DECLARE(image_weather_temperature);
  73.   LV_IMAGE_DECLARE(image_weather_humidity);
  74.   // Get the weather data from open-meteo.com API
  75.   get_weather_data();
  76.   weather_image = lv_image_create(lv_screen_active());
  77.   lv_obj_align(weather_image, LV_ALIGN_CENTER, -80, -20);
  78.   
  79.   get_weather_description(weather_code);
  80.   text_label_date = lv_label_create(lv_screen_active());
  81.   lv_label_set_text(text_label_date, current_date.c_str());
  82.   lv_obj_align(text_label_date, LV_ALIGN_CENTER, 70, -70);
  83.   lv_obj_set_style_text_font((lv_obj_t*) text_label_date, &lv_font_montserrat_26, 0);
  84.   lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_TEAL), 0);
  85.   lv_obj_t * weather_image_temperature = lv_image_create(lv_screen_active());
  86.   lv_image_set_src(weather_image_temperature, &image_weather_temperature);
  87.   lv_obj_align(weather_image_temperature, LV_ALIGN_CENTER, 30, -25);
  88.   text_label_temperature = lv_label_create(lv_screen_active());
  89.   lv_label_set_text(text_label_temperature, String("      " + temperature + degree_symbol).c_str());
  90.   lv_obj_align(text_label_temperature, LV_ALIGN_CENTER, 70, -25);
  91.   lv_obj_set_style_text_font((lv_obj_t*) text_label_temperature, &lv_font_montserrat_22, 0);
  92.   lv_obj_t * weather_image_humidity = lv_image_create(lv_screen_active());
  93.   lv_image_set_src(weather_image_humidity, &image_weather_humidity);
  94.   lv_obj_align(weather_image_humidity, LV_ALIGN_CENTER, 30, 20);
  95.   text_label_humidity = lv_label_create(lv_screen_active());
  96.   lv_label_set_text(text_label_humidity, String("   " + humidity + "%").c_str());
  97.   lv_obj_align(text_label_humidity, LV_ALIGN_CENTER, 70, 20);
  98.   lv_obj_set_style_text_font((lv_obj_t*) text_label_humidity, &lv_font_montserrat_22, 0);
  99.   text_label_weather_description = lv_label_create(lv_screen_active());
  100.   lv_label_set_text(text_label_weather_description, weather_description.c_str());
  101.   lv_obj_align(text_label_weather_description, LV_ALIGN_BOTTOM_MID, 0, -40);
  102.   lv_obj_set_style_text_font((lv_obj_t*) text_label_weather_description, &lv_font_montserrat_18, 0);
  103.   // Create a text label for the time and timezone aligned center in the bottom of the screen
  104.   text_label_time_location = lv_label_create(lv_screen_active());
  105.   lv_label_set_text(text_label_time_location, String("Last Update: " + last_weather_update + "  |  " + location).c_str());
  106.   lv_obj_align(text_label_time_location, LV_ALIGN_BOTTOM_MID, 0, -10);
  107.   lv_obj_set_style_text_font((lv_obj_t*) text_label_time_location, &lv_font_montserrat_12, 0);
  108.   lv_obj_set_style_text_color((lv_obj_t*) text_label_time_location, lv_palette_main(LV_PALETTE_GREY), 0);
  109.   lv_timer_t * timer = lv_timer_create(timer_cb, 600000, NULL);
  110.   lv_timer_ready(timer);
  111. }
  112. /*
  113.   WMO Weather interpretation codes (WW)- Code        Description
  114.   0        Clear sky
  115.   1, 2, 3        Mainly clear, partly cloudy, and overcast
  116.   45, 48        Fog and depositing rime fog
  117.   51, 53, 55        Drizzle: Light, moderate, and dense intensity
  118.   56, 57        Freezing Drizzle: Light and dense intensity
  119.   61, 63, 65        Rain: Slight, moderate and heavy intensity
  120.   66, 67        Freezing Rain: Light and heavy intensity
  121.   71, 73, 75        Snow fall: Slight, moderate, and heavy intensity
  122.   77        Snow grains
  123.   80, 81, 82        Rain showers: Slight, moderate, and violent
  124.   85, 86        Snow showers slight and heavy
  125.   95 *        Thunderstorm: Slight or moderate
  126.   96, 99 *        Thunderstorm with slight and heavy hail
  127. */
  128. void get_weather_description(int code) {
  129.   switch (code) {
  130.     case 0:
  131.       if(is_day==1) { lv_image_set_src(weather_image, &image_weather_sun); }
  132.       else { lv_image_set_src(weather_image, &image_weather_night); }
  133.       weather_description = "CLEAR SKY";
  134.       break;
  135.     case 1:
  136.       if(is_day==1) { lv_image_set_src(weather_image, &image_weather_sun); }
  137.       else { lv_image_set_src(weather_image, &image_weather_night); }
  138.       weather_description = "MAINLY CLEAR";
  139.       break;
  140.     case 2:
  141.       lv_image_set_src(weather_image, &image_weather_cloud);
  142.       weather_description = "PARTLY CLOUDY";
  143.       break;
  144.     case 3:
  145.       lv_image_set_src(weather_image, &image_weather_cloud);
  146.       weather_description = "OVERCAST";
  147.       break;
  148.     case 45:
  149.       lv_image_set_src(weather_image, &image_weather_cloud);
  150.       weather_description = "FOG";
  151.       break;
  152.     case 48:
  153.       lv_image_set_src(weather_image, &image_weather_cloud);
  154.       weather_description = "DEPOSITING RIME FOG";
  155.       break;
  156.     case 51:
  157.       lv_image_set_src(weather_image, &image_weather_rain);
  158.       weather_description = "DRIZZLE LIGHT INTENSITY";
  159.       break;
  160.     case 53:
  161.       lv_image_set_src(weather_image, &image_weather_rain);
  162.       weather_description = "DRIZZLE MODERATE INTENSITY";
  163.       break;
  164.     case 55:
  165.       lv_image_set_src(weather_image, &image_weather_rain);
  166.       weather_description = "DRIZZLE DENSE INTENSITY";
  167.       break;
  168.     case 56:
  169.       lv_image_set_src(weather_image, &image_weather_rain);
  170.       weather_description = "FREEZING DRIZZLE LIGHT";
  171.       break;
  172.     case 57:
  173.       lv_image_set_src(weather_image, &image_weather_rain);
  174.       weather_description = "FREEZING DRIZZLE DENSE";
  175.       break;
  176.     case 61:
  177.       lv_image_set_src(weather_image, &image_weather_rain);
  178.       weather_description = "RAIN SLIGHT INTENSITY";
  179.       break;
  180.     case 63:
  181.       lv_image_set_src(weather_image, &image_weather_rain);
  182.       weather_description = "RAIN MODERATE INTENSITY";
  183.       break;
  184.     case 65:
  185.       lv_image_set_src(weather_image, &image_weather_rain);
  186.       weather_description = "RAIN HEAVY INTENSITY";
  187.       break;
  188.     case 66:
  189.       lv_image_set_src(weather_image, &image_weather_rain);
  190.       weather_description = "FREEZING RAIN LIGHT INTENSITY";
  191.       break;
  192.     case 67:
  193.       lv_image_set_src(weather_image, &image_weather_rain);
  194.       weather_description = "FREEZING RAIN HEAVY INTENSITY";
  195.       break;
  196.     case 71:
  197.       lv_image_set_src(weather_image, &image_weather_snow);
  198.       weather_description = "SNOW FALL SLIGHT INTENSITY";
  199.       break;
  200.     case 73:
  201.       lv_image_set_src(weather_image, &image_weather_snow);
  202.       weather_description = "SNOW FALL MODERATE INTENSITY";
  203.       break;
  204.     case 75:
  205.       lv_image_set_src(weather_image, &image_weather_snow);
  206.       weather_description = "SNOW FALL HEAVY INTENSITY";
  207.       break;
  208.     case 77:
  209.       lv_image_set_src(weather_image, &image_weather_snow);
  210.       weather_description = "SNOW GRAINS";
  211.       break;
  212.     case 80:
  213.       lv_image_set_src(weather_image, &image_weather_rain);
  214.       weather_description = "RAIN SHOWERS SLIGHT";
  215.       break;
  216.     case 81:
  217.       lv_image_set_src(weather_image, &image_weather_rain);
  218.       weather_description = "RAIN SHOWERS MODERATE";
  219.       break;
  220.     case 82:
  221.       lv_image_set_src(weather_image, &image_weather_rain);
  222.       weather_description = "RAIN SHOWERS VIOLENT";
  223.       break;
  224.     case 85:
  225.       lv_image_set_src(weather_image, &image_weather_snow);
  226.       weather_description = "SNOW SHOWERS SLIGHT";
  227.       break;
  228.     case 86:
  229.       lv_image_set_src(weather_image, &image_weather_snow);
  230.       weather_description = "SNOW SHOWERS HEAVY";
  231.       break;
  232.     case 95:
  233.       lv_image_set_src(weather_image, &image_weather_thunder);
  234.       weather_description = "THUNDERSTORM";
  235.       break;
  236.     case 96:
  237.       lv_image_set_src(weather_image, &image_weather_thunder);
  238.       weather_description = "THUNDERSTORM SLIGHT HAIL";
  239.       break;
  240.     case 99:
  241.       lv_image_set_src(weather_image, &image_weather_thunder);
  242.       weather_description = "THUNDERSTORM HEAVY HAIL";
  243.       break;
  244.     default:
  245.       weather_description = "UNKNOWN WEATHER CODE";
  246.       break;
  247.   }
  248. }
  249. void get_weather_data() {
  250.   if (WiFi.status() == WL_CONNECTED) {
  251.     HTTPClient http;
  252.     // Construct the API endpoint
  253.     String url = String("http://api.open-meteo.com/v1/forecast?latitude=" + latitude + "&longitude=" + longitude + "¤t=temperature_2m,relative_humidity_2m,is_day,precipitation,rain,weather_code" + temperature_unit + "&timezone=" + timezone + "&forecast_days=1");
  254.     http.begin(url);
  255.     int httpCode = http.GET(); // Make the GET request
  256.     if (httpCode > 0) {
  257.       // Check for the response
  258.       if (httpCode == HTTP_CODE_OK) {
  259.         String payload = http.getString();
  260.         //Serial.println("Request information:");
  261.         //Serial.println(payload);
  262.         // Parse the JSON to extract the time
  263.         JsonDocument doc;
  264.         DeserializationError error = deserializeJson(doc, payload);
  265.         if (!error) {
  266.           const char* datetime = doc["current"]["time"];
  267.           temperature = String(doc["current"]["temperature_2m"]);
  268.           humidity = String(doc["current"]["relative_humidity_2m"]);
  269.           is_day = String(doc["current"]["is_day"]).toInt();
  270.           weather_code = String(doc["current"]["weather_code"]).toInt();
  271.           /*Serial.println(temperature);
  272.           Serial.println(humidity);
  273.           Serial.println(is_day);
  274.           Serial.println(weather_code);
  275.           Serial.println(String(timezone));*/
  276.           // Split the datetime into date and time
  277.           String datetime_str = String(datetime);
  278.           int splitIndex = datetime_str.indexOf('T');
  279.           current_date = datetime_str.substring(0, splitIndex);
  280.           last_weather_update = datetime_str.substring(splitIndex + 1, splitIndex + 9); // Extract time portion
  281.         } else {
  282.           Serial.print("deserializeJson() failed: ");
  283.           Serial.println(error.c_str());
  284.         }
  285.       }
  286.       else {
  287.         Serial.println("Failed");
  288.       }
  289.     } else {
  290.       Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
  291.     }
  292.     http.end(); // Close connection
  293.   } else {
  294.     Serial.println("Not connected to Wi-Fi");
  295.   }
  296. }
  297. void setup() {
  298.   String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
  299.   Serial.begin(115200);
  300.   Serial.println(LVGL_Arduino);
  301.   // Connect to Wi-Fi
  302.   WiFi.begin(ssid, password);
  303.   Serial.print("Connecting");
  304.   while (WiFi.status() != WL_CONNECTED) {
  305.     delay(500);
  306.     Serial.print(".");
  307.   }
  308.   Serial.print("\nConnected to Wi-Fi network with IP Address: ");
  309.   Serial.println(WiFi.localIP());
  310.   
  311.   // Start LVGL
  312.   lv_init();
  313.   // Register print function for debugging
  314.   lv_log_register_print_cb(log_print);
  315.   // Create a display object
  316.   lv_display_t * disp;
  317.   // Initialize the TFT display using the TFT_eSPI library
  318.   disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
  319.   lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);
  320.   
  321.   // Function to draw the GUI
  322.   lv_create_main_gui();
  323. }
  324. void loop() {
  325.   lv_task_handler();  // let the GUI do its work
  326.   lv_tick_inc(5);     // tell LVGL how much time has passed
  327.   delay(5);           // let this time pass
  328. }
复制代码


回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 14:03:08

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

这段代码是一个使用ESP32开发板和2.8寸TFT显示屏(带触摸屏)的气象站项目,它通过LVGL图形库显示天气信息,包括天气描述、温度和湿度。以下是对代码的十点解读:

1、网络配置:
代码中包含了WiFi网络的SSID和密码,用于连接到互联网获取天气数据。
2、地理位置信息:
通过latitude和longitude变量设置了想要获取天气信息的地理位置,location变量用于标识位置名称。
3、时区设置:
timezone变量用于设置时区,这对于获取正确的日期和时间信息至关重要。
4、天气数据变量:
定义了多个字符串变量来存储当前日期、最后更新时间、温度、湿度和天气描述。
5、温度单位设置:
通过TEMP_CELSIUS宏定义来决定温度单位是摄氏度还是华氏度。
6、屏幕参数和绘图缓冲区:
定义了屏幕的宽度和高度,以及绘图缓冲区的大小,这对于TFT显示屏的正确显示是必要的。
7、日志打印函数:
log_print函数用于打印LVGL库的日志信息,方便调试。
8、GUI组件创建:
lv_create_main_gui函数中创建了多个GUI组件,包括天气图像、日期标签、温度标签、湿度标签和天气描述标签。
9、天气数据获取:
get_weather_data函数通过HTTP请求从open-meteo.comAPI获取天气数据,并解析JSON响应。
10天气描述映射:
get_weather_description函数根据天气代码映射到具体的天气描述,并设置相应的天气图像。

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 14:13:01

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

实验串口返回情况

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1


已连接到IP地址为192.168.28.13的Wi-Fi网络
GET请求失败,错误:连接丢失

回复

使用道具 举报

驴友花雕  中级技神
 楼主|

发表于 2024-11-16 14:14:03

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站

实验场景图 (只有LVGL,连接丢失没有数据)

【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站图1
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail