搜索代码

ESP32教程43/55 - 物联网互联网气象站 | SunFounder的ESP32物联网学习套件

ESP32教程43/55 - 物联网互联网气象站 | SunFounder的ESP32物联网学习套件

在本教程中,我们将使用ESP32及其来自SunFounder的摄像头扩展板构建一个连接互联网的气象站。该项目使ESP32能够获取实时天气数据,包括温度和湿度,并将其显示在LCD屏幕上。此应用不仅展示了ESP32的功能,还演示了如何从外部API获取和解析数据。

随着教程的推进,我们将连接组件、配置代码,并确保一切无缝协同工作。最终结果将是一个功能齐全的气象站,每10秒更新一次读数,清晰简洁地显示当前天气状况(视频中00:30处)。

硬件说明

本项目中使用的主要组件包括ESP32微控制器、LCD显示屏以及必要的接线。ESP32内置Wi-Fi和蓝牙,使其能够连接互联网并获取数据。LCD显示屏将显示当前天气信息,包括温度和湿度。

我们使用的LCD是16x2字符显示屏,这意味着它可以显示两行,每行16个字符。这对于我们的天气信息输出来说已经足够。ESP32将通过I2C与LCD通信,这仅使用两条数据线,简化了接线。

数据手册详情

制造商乐鑫
零件编号ESP32-WROOM-32
逻辑/IO电压3.3 V
电源电压3.0–3.6 V
输出电流(每通道)最大12 mA
峰值电流(每通道)40 mA
PWM频率建议1 kHz
输入逻辑阈值0.3 V(低),0.7 V(高)
压降 / RDS(on) / 饱和0.5 V
热限制-40至85 °C
封装QFN48
备注 / 变体包含适用于不同应用的多种变体

  • 确保ESP32使用稳定的3.3 V电源供电。
  • 为所有组件使用公共接地,以避免通信问题。
  • 使用I2C扫描器检查LCD的I2C地址。
  • 监控Wi-Fi连接状态,以避免在数据获取期间断开连接。
  • 处理JSON解析错误,以增强数据检索的稳健性。

接线说明

esp32-43-weather_station-wiring

要连接组件,首先将LCD连接到ESP32。LCD将使用I2C接口,因此将LCD的SDA引脚连接到ESP32上的GPIO21,将SCL引脚连接到GPIO22。确保将LCD的电源和接地引脚分别连接到ESP32上的5V和GND引脚。

接下来,确保使用随附的锂电池或USB连接正确为ESP32供电。电池提供便携性,而USB连接则适用于编程和调试。最后,检查所有连接是否牢固,以避免可能干扰功能的松动接线问题。

代码示例与讲解

在程序的设置阶段,我们初始化串行通信并使用提供的SSID和密码连接到Wi-Fi网络。以下代码片段处理Wi-Fi连接:

WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("已连接到Wi-Fi网络,IP地址:");
Serial.println(WiFi.localIP());

此代码确保ESP32在进行任何数据获取之前连接到指定的Wi-Fi网络。如果连接失败,它将持续尝试重新连接。

接下来,我们需要发送HTTP GET请求以获取天气数据。这通过以下代码片段实现:

String serverPath = "http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&units=metric" + "&APPID=" + openWeatherMapApiKey;
jsonBuffer = httpGETRequest(serverPath.c_str());

在这里,我们构建API请求的URL,其中包含城市、国家代码和我们的API密钥。然后调用httpGETRequest函数来获取天气数据。

最后,我们解析JSON响应并将相关数据显示在LCD上:

lcd.clear(); 
lcd.setCursor(0, 0); 
lcd.print(time);
lcd.print(" ");        
lcd.print(myObject["weather"][0]["main"]);             
lcd.setCursor(0, 1);
lcd.print("T:");    
lcd.print(myObject["main"]["temp"]); 
lcd.print("\xDF");  // "°"字符
lcd.print("C ");    
lcd.print("H:");    
lcd.print(myObject["main"]["humidity"]);  
lcd.print("%");

此代码片段使用当前时间、天气状况、温度和湿度更新LCD显示。它清除之前的显示并将光标设置到每行的适当位置。

演示 / 预期效果

成功接线和编程后,您的气象站将连接到Wi-Fi并开始每10秒获取一次天气数据。您将看到当前温度、湿度和天气状况显示在LCD屏幕上。如果ESP32无法连接到Wi-Fi,它将在串行监视器上打印错误消息。

请注意API调用限制,以免被OpenWeatherMap服务屏蔽。如果在数据获取过程中遇到任何问题,请检查您的API密钥,并确保城市和国家代码填写正确(视频15:45处有说明)。

视频时间戳

  • 00:00 开始
  • 2:00 项目介绍
  • 5:04 OpenWeather账户
  • 6:11 接线
  • 8:05 Arduino代码详解
  • 14:13 代码中的JSON元素
  • 20:23 在Arduino IDE中选择ESP32开发板和COM端口
  • 22:05 LCD1602气象站演示
  • 23:45 LCD2004气象站演示

图像

esp32-43-weather_station-main
esp32-43-weather_station-main
esp32-43-weather_station-wiring
esp32-43-weather_station-wiring
844-ESP32 Tutorial 43/55- Arduino code for IoT Internet Weather Station
语言: C++
/*
 * 鲁伊·桑托斯  
 * 完整项目详情请访问 https://RandomNerdTutorials.com/esp32-http-get-open-weather-map-thingspeak-arduino/  
 * 
 * 在此免费授权任何获取本软件及相关文档文件副本的人。  
 * 
 * 上述版权声明和本许可声明应包含在所有副本或软件的重要部分中。
 */
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>


 // 将下列变量替换为您的SSID/密码组合。
const char* ssid = "SSID";
const char* password = "PASSWORD";

 // 您的域名及其 URL 路径或带路径的 IP 地址
String openWeatherMapApiKey = "openWeatherMapApiKey";

 // 用您的国家代码和城市替换
 // 通过 https://openweathermap.org/find 查找国家代码
String city = "CITY";
String countryCode = "COUNTRY CODE";

 // 默认定时器设置为 10 秒,供测试之用。
 // 对于最终应用程序,请检查每小时/每分钟的API调用限制,以避免被封锁/禁用。
unsigned long lastTime = 0;
 // 定时器设置为10分钟(600000)
 // 无符号长整型定时器延迟 = 600000;
 // 设置计时器为10秒(10000)
unsigned long timerDelay = 10000;

String jsonBuffer;

 // 设置液晶显示器的列数和行数
int lcdColumns = 16;
int lcdRows = 2;

 // 设置LCD地址、列数和行数
 // SDA -> GPIO21,SCL -> GPIO22
 // LCD地址是0x27,运行一个I2C扫描器代码。
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);

 // NTP服务器时间
const char* ntpServer = "pool.ntp.org";
long  gmtOffset_sec = 0;
int   daylightOffset_sec = 0; // 3600;

void setup() {
  Serial.begin(115200);

 // WiFi
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.println("Timer set to 10 seconds (timerDelay variable), it will take 10 seconds before publishing the first reading.");

 // 初始化LCD
  lcd.init();
 // 打开LCD背光
  lcd.backlight();

}

void loop() {
 // 发送一个HTTP GET请求
  if ((millis() - lastTime) > timerDelay) {
 // 检查WiFi连接状态
    if(WiFi.status()== WL_CONNECTED){
      String serverPath = "http: // api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&units=metric" + "&APPID=" + openWeatherMapApiKey;

      jsonBuffer = httpGETRequest(serverPath.c_str());
      Serial.println(jsonBuffer);
      JSONVar myObject = JSON.parse(jsonBuffer);

 // JSON.typeof(jsonVar) 可以用来获取变量的类型。
      if (JSON.typeof(myObject) == "undefined") {
        Serial.println("Parsing input failed!");
        return;
      }

 // JSON对象 = 
 // Serial.println(myObject);
 // 温度: 
 // Serial.println(myObject["main"]["temp"]);
 // 压力: 
 // Serial.println(myObject["main"]["pressure"]);
 // 湿度:
 // Serial.println(myObject["main"]["湿度"]);
 // 风速:
 // Serial.println(myObject["风"]["速度"]);

 // 获取时间
      gmtOffset_sec =  myObject["timezone"];
      configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
 // 时间 =
      String time = printLocalTime();

 // 液晶打印
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print(time);
      lcd.print(" ");
      lcd.print(myObject["weather"][0]["main"]);
      lcd.setCursor(0, 1);
      lcd.print("T:");
      lcd.print(myObject["main"]["temp"]);
      lcd.print("\xDF"); // "°" 字符
      lcd.print("C ");
      lcd.print("H:");
      lcd.print(myObject["main"]["humidity"]);
      lcd.print("%");

    }
    else {
      Serial.println("WiFi Disconnected");
    }
    lastTime = millis();
  }
}

String printLocalTime(){
  struct tm timeinfo;
  if(!getLocalTime(&timeinfo)){
    Serial.println("Failed to obtain time");
    return "null";
  }
 // Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

 // 获取时间格式 HH:MM
  char timeHour[3];
  strftime(timeHour,3, "%H", &timeinfo);
  char timeMinute[3];
  strftime(timeMinute,3, "%M", &timeinfo);
  String time = String(timeHour) + ":" + String(timeMinute);
  Serial.println(time)
;  return time;
}


String httpGETRequest(const char* serverName) {
  WiFiClient client;
  HTTPClient http;

 // 您的域名及其 URL 路径或带路径的 IP 地址
  http.begin(client, serverName);

 // 发送HTTP POST请求
  int httpResponseCode = http.GET();

  String payload = "{}";

  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
 // 免费资源
  http.end();

  return payload;
}

资源与参考

文件📁

没有可用的文件。