驴友花雕 发表于 2024-11-16 13:40:35

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



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中进行开发。


驴友花雕 发表于 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/





驴友花雕 发表于 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 版本。我们建议使用相同的版本。


驴友花雕 发表于 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 文件旁边。



驴友花雕 发表于 2024-11-16 13:51:56

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


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




驴友花雕 发表于 2024-11-16 13:55:41

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

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

实验开源代码

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

#include <lvgl.h>
#include <TFT_eSPI.h>
#include "weather_images.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// Replace with your network credentials
const char* ssid = "zhz3";
const char* password = "z156721";

// Replace with the latitude and longitude to where you want to get the weather
String latitude = "41.14961";
String longitude = "-8.61099";
// Enter your location
String location = "Porto";
// Type the timezone you want to get the time for
String timezone = "Europe/Lisbon";

// Store date and time
String current_date;
String last_weather_update;
String temperature;
String humidity;
int is_day;
int weather_code = 0;
String weather_description;

// SET VARIABLE TO 0 FOR TEMPERATURE IN FAHRENHEIT DEGREES
#define TEMP_CELSIUS 1

#if TEMP_CELSIUS
String temperature_unit = "";
const char degree_symbol[] = "\u00B0C";
#else
String temperature_unit = "&temperature_unit=fahrenheit";
const char degree_symbol[] = "\u00B0F";
#endif

#define SCREEN_WIDTH 240
#define SCREEN_HEIGHT 320

#define DRAW_BUF_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT / 10 * (LV_COLOR_DEPTH / 8))
uint32_t draw_buf;

// If logging is enabled, it will inform the user about what is happening in the library
void log_print(lv_log_level_t level, const char * buf) {
LV_UNUSED(level);
Serial.println(buf);
Serial.flush();
}

static lv_obj_t * weather_image;
static lv_obj_t * text_label_date;
static lv_obj_t * text_label_temperature;
static lv_obj_t * text_label_humidity;
static lv_obj_t * text_label_weather_description;
static lv_obj_t * text_label_time_location;

static void timer_cb(lv_timer_t * timer){
LV_UNUSED(timer);
get_weather_data();
get_weather_description(weather_code);
lv_label_set_text(text_label_date, current_date.c_str());
lv_label_set_text(text_label_temperature, String("      " + temperature + degree_symbol).c_str());
lv_label_set_text(text_label_humidity, String("   " + humidity + "%").c_str());
lv_label_set_text(text_label_weather_description, weather_description.c_str());
lv_label_set_text(text_label_time_location, String("Last Update: " + last_weather_update + "|" + location).c_str());
}

void lv_create_main_gui(void) {
LV_IMAGE_DECLARE(image_weather_sun);
LV_IMAGE_DECLARE(image_weather_cloud);
LV_IMAGE_DECLARE(image_weather_rain);
LV_IMAGE_DECLARE(image_weather_thunder);
LV_IMAGE_DECLARE(image_weather_snow);
LV_IMAGE_DECLARE(image_weather_night);
LV_IMAGE_DECLARE(image_weather_temperature);
LV_IMAGE_DECLARE(image_weather_humidity);

// Get the weather data from open-meteo.com API
get_weather_data();

weather_image = lv_image_create(lv_screen_active());
lv_obj_align(weather_image, LV_ALIGN_CENTER, -80, -20);

get_weather_description(weather_code);

text_label_date = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_date, current_date.c_str());
lv_obj_align(text_label_date, LV_ALIGN_CENTER, 70, -70);
lv_obj_set_style_text_font((lv_obj_t*) text_label_date, &lv_font_montserrat_26, 0);
lv_obj_set_style_text_color((lv_obj_t*) text_label_date, lv_palette_main(LV_PALETTE_TEAL), 0);

lv_obj_t * weather_image_temperature = lv_image_create(lv_screen_active());
lv_image_set_src(weather_image_temperature, &image_weather_temperature);
lv_obj_align(weather_image_temperature, LV_ALIGN_CENTER, 30, -25);
text_label_temperature = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_temperature, String("      " + temperature + degree_symbol).c_str());
lv_obj_align(text_label_temperature, LV_ALIGN_CENTER, 70, -25);
lv_obj_set_style_text_font((lv_obj_t*) text_label_temperature, &lv_font_montserrat_22, 0);

lv_obj_t * weather_image_humidity = lv_image_create(lv_screen_active());
lv_image_set_src(weather_image_humidity, &image_weather_humidity);
lv_obj_align(weather_image_humidity, LV_ALIGN_CENTER, 30, 20);
text_label_humidity = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_humidity, String("   " + humidity + "%").c_str());
lv_obj_align(text_label_humidity, LV_ALIGN_CENTER, 70, 20);
lv_obj_set_style_text_font((lv_obj_t*) text_label_humidity, &lv_font_montserrat_22, 0);

text_label_weather_description = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_weather_description, weather_description.c_str());
lv_obj_align(text_label_weather_description, LV_ALIGN_BOTTOM_MID, 0, -40);
lv_obj_set_style_text_font((lv_obj_t*) text_label_weather_description, &lv_font_montserrat_18, 0);

// Create a text label for the time and timezone aligned center in the bottom of the screen
text_label_time_location = lv_label_create(lv_screen_active());
lv_label_set_text(text_label_time_location, String("Last Update: " + last_weather_update + "|" + location).c_str());
lv_obj_align(text_label_time_location, LV_ALIGN_BOTTOM_MID, 0, -10);
lv_obj_set_style_text_font((lv_obj_t*) text_label_time_location, &lv_font_montserrat_12, 0);
lv_obj_set_style_text_color((lv_obj_t*) text_label_time_location, lv_palette_main(LV_PALETTE_GREY), 0);

lv_timer_t * timer = lv_timer_create(timer_cb, 600000, NULL);
lv_timer_ready(timer);
}

/*
WMO Weather interpretation codes (WW)- Code        Description
0        Clear sky
1, 2, 3        Mainly clear, partly cloudy, and overcast
45, 48        Fog and depositing rime fog
51, 53, 55        Drizzle: Light, moderate, and dense intensity
56, 57        Freezing Drizzle: Light and dense intensity
61, 63, 65        Rain: Slight, moderate and heavy intensity
66, 67        Freezing Rain: Light and heavy intensity
71, 73, 75        Snow fall: Slight, moderate, and heavy intensity
77        Snow grains
80, 81, 82        Rain showers: Slight, moderate, and violent
85, 86        Snow showers slight and heavy
95 *        Thunderstorm: Slight or moderate
96, 99 *        Thunderstorm with slight and heavy hail
*/
void get_weather_description(int code) {
switch (code) {
    case 0:
      if(is_day==1) { lv_image_set_src(weather_image, &image_weather_sun); }
      else { lv_image_set_src(weather_image, &image_weather_night); }
      weather_description = "CLEAR SKY";
      break;
    case 1:
      if(is_day==1) { lv_image_set_src(weather_image, &image_weather_sun); }
      else { lv_image_set_src(weather_image, &image_weather_night); }
      weather_description = "MAINLY CLEAR";
      break;
    case 2:
      lv_image_set_src(weather_image, &image_weather_cloud);
      weather_description = "PARTLY CLOUDY";
      break;
    case 3:
      lv_image_set_src(weather_image, &image_weather_cloud);
      weather_description = "OVERCAST";
      break;
    case 45:
      lv_image_set_src(weather_image, &image_weather_cloud);
      weather_description = "FOG";
      break;
    case 48:
      lv_image_set_src(weather_image, &image_weather_cloud);
      weather_description = "DEPOSITING RIME FOG";
      break;
    case 51:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "DRIZZLE LIGHT INTENSITY";
      break;
    case 53:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "DRIZZLE MODERATE INTENSITY";
      break;
    case 55:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "DRIZZLE DENSE INTENSITY";
      break;
    case 56:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "FREEZING DRIZZLE LIGHT";
      break;
    case 57:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "FREEZING DRIZZLE DENSE";
      break;
    case 61:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "RAIN SLIGHT INTENSITY";
      break;
    case 63:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "RAIN MODERATE INTENSITY";
      break;
    case 65:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "RAIN HEAVY INTENSITY";
      break;
    case 66:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "FREEZING RAIN LIGHT INTENSITY";
      break;
    case 67:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "FREEZING RAIN HEAVY INTENSITY";
      break;
    case 71:
      lv_image_set_src(weather_image, &image_weather_snow);
      weather_description = "SNOW FALL SLIGHT INTENSITY";
      break;
    case 73:
      lv_image_set_src(weather_image, &image_weather_snow);
      weather_description = "SNOW FALL MODERATE INTENSITY";
      break;
    case 75:
      lv_image_set_src(weather_image, &image_weather_snow);
      weather_description = "SNOW FALL HEAVY INTENSITY";
      break;
    case 77:
      lv_image_set_src(weather_image, &image_weather_snow);
      weather_description = "SNOW GRAINS";
      break;
    case 80:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "RAIN SHOWERS SLIGHT";
      break;
    case 81:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "RAIN SHOWERS MODERATE";
      break;
    case 82:
      lv_image_set_src(weather_image, &image_weather_rain);
      weather_description = "RAIN SHOWERS VIOLENT";
      break;
    case 85:
      lv_image_set_src(weather_image, &image_weather_snow);
      weather_description = "SNOW SHOWERS SLIGHT";
      break;
    case 86:
      lv_image_set_src(weather_image, &image_weather_snow);
      weather_description = "SNOW SHOWERS HEAVY";
      break;
    case 95:
      lv_image_set_src(weather_image, &image_weather_thunder);
      weather_description = "THUNDERSTORM";
      break;
    case 96:
      lv_image_set_src(weather_image, &image_weather_thunder);
      weather_description = "THUNDERSTORM SLIGHT HAIL";
      break;
    case 99:
      lv_image_set_src(weather_image, &image_weather_thunder);
      weather_description = "THUNDERSTORM HEAVY HAIL";
      break;
    default:
      weather_description = "UNKNOWN WEATHER CODE";
      break;
}
}

void get_weather_data() {
if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    // Construct the API endpoint
    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");
    http.begin(url);
    int httpCode = http.GET(); // Make the GET request

    if (httpCode > 0) {
      // Check for the response
      if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      //Serial.println("Request information:");
      //Serial.println(payload);
      // Parse the JSON to extract the time
      JsonDocument doc;
      DeserializationError error = deserializeJson(doc, payload);
      if (!error) {
          const char* datetime = doc["current"]["time"];
          temperature = String(doc["current"]["temperature_2m"]);
          humidity = String(doc["current"]["relative_humidity_2m"]);
          is_day = String(doc["current"]["is_day"]).toInt();
          weather_code = String(doc["current"]["weather_code"]).toInt();
          /*Serial.println(temperature);
          Serial.println(humidity);
          Serial.println(is_day);
          Serial.println(weather_code);
          Serial.println(String(timezone));*/
          // Split the datetime into date and time
          String datetime_str = String(datetime);
          int splitIndex = datetime_str.indexOf('T');
          current_date = datetime_str.substring(0, splitIndex);
          last_weather_update = datetime_str.substring(splitIndex + 1, splitIndex + 9); // Extract time portion
      } else {
          Serial.print("deserializeJson() failed: ");
          Serial.println(error.c_str());
      }
      }
      else {
      Serial.println("Failed");
      }
    } else {
      Serial.printf("GET request failed, error: %s\n", http.errorToString(httpCode).c_str());
    }
    http.end(); // Close connection
} else {
    Serial.println("Not connected to Wi-Fi");
}
}

void setup() {
String LVGL_Arduino = String("LVGL Library Version: ") + lv_version_major() + "." + lv_version_minor() + "." + lv_version_patch();
Serial.begin(115200);
Serial.println(LVGL_Arduino);

// Connect to Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Connecting");
while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
}
Serial.print("\nConnected to Wi-Fi network with IP Address: ");
Serial.println(WiFi.localIP());

// Start LVGL
lv_init();
// Register print function for debugging
lv_log_register_print_cb(log_print);

// Create a display object
lv_display_t * disp;
// Initialize the TFT display using the TFT_eSPI library
disp = lv_tft_espi_create(SCREEN_WIDTH, SCREEN_HEIGHT, draw_buf, sizeof(draw_buf));
lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_270);

// Function to draw the GUI
lv_create_main_gui();
}

void loop() {
lv_task_handler();// let the GUI do its work
lv_tick_inc(5);   // tell LVGL how much time has passed
delay(5);         // let this time pass
}

驴友花雕 发表于 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数字气象站

实验串口返回情况




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

驴友花雕 发表于 2024-11-16 14:14:03

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

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


页: [1]
查看完整版本: 【花雕学编程】Arduino动手做(238)---ESP32 CYD数字气象站