ESP32 教程 43/55 - 物聯網互聯網天氣站 | SunFounder 嘅 ESP32 物聯網學習套件
喺呢個教學入面,我哋會用SunFounder嘅ESP32同佢嘅相機擴展板嚟整一個連上互聯網嘅天氣站。呢個項目令到ESP32可以攞到即時天氣數據,包括溫度同濕度,並且顯示喺LCD屏幕上面。呢個應用程式唔單止展示咗ESP32嘅能力,仲示範咗點樣由外部API攞數據同解析數據。

隨住我哋喺教學入面逐步推進,我哋會接駁零件、設定程式碼,同埋確保所有嘢可以順暢咁一齊運作。最終嘅結果會係一個功能齊全嘅天氣站,每10秒更新一次讀數,提供清晰簡潔嘅當前天氣狀況顯示(喺影片00:30度)。
硬件解說
呢個項目用到嘅主要零件包括ESP32微控制器、一個LCD顯示屏,同埋必要嘅接線。ESP32內置Wi-Fi同藍牙,令到佢可以連上互聯網攞數據。LCD顯示屏會顯示當前天氣資訊,包括溫度同濕度。
我哋用嘅LCD係一個16x2字元顯示屏,即係話佢可以顯示兩行,每行16個字元。呢個對於我哋嘅天氣資訊輸出嚟講已經足夠。ESP32會透過I2C同LCD通訊,呢個只用兩條數據線,簡化咗接線。
數據表詳情
| 製造商 | Espressif |
|---|---|
| 零件編號 | 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解析錯誤,令數據攞取更加穩健。
接線指示

要接駁零件,首先將LCD連接到ESP32。LCD會用I2C介面,所以將LCD嘅SDA針腳連到ESP32嘅GPIO21,SCL針腳連到GPIO22。確保將LCD嘅電源同接地針腳分別連到ESP32嘅5V同GND針腳。
跟住,確保ESP32用跟機嘅鋰電池或者USB連接正確供電。電池提供便攜性,而USB連接就適合用嚟編程同除錯。最後,檢查所有連接都穩固,避免任何鬆動接線問題影響功能。
程式碼範例同講解
喺程式嘅設定階段,我哋初始化串列通訊,並用提供嘅SSID同密碼連接到Wi-Fi網絡。以下程式碼片段處理Wi-Fi連接:
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("Connected to WiFi network with IP Address: ");
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"); // "°" char
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 代碼入面嘅JASON元素
- 20:23 喺Arduino IDE揀ESP32板同COM埠
- 22:05 LCD1602天氣站示範
- 23:45 LCD2004天氣站示範
/*
Rui Santos
Complete project details at Complete project details at https://RandomNerdTutorials.com/esp32-http-get-open-weather-map-thingspeak-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
*/
#include <LiquidCrystal_I2C.h>
#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>
// Replace the next variables with your SSID/Password combination
const char* ssid = "SSID";
const char* password = "PASSWORD";
// Your Domain name with URL path or IP address with path
String openWeatherMapApiKey = "openWeatherMapApiKey";
// Replace with your country code and city
// Fine the country code by https://openweathermap.org/find
String city = "CITY";
String countryCode = "COUNTRY CODE";
// THE DEFAULT TIMER IS SET TO 10 SECONDS FOR TESTING PURPOSES
// For a final application, check the API call limits per hour/minute to avoid getting blocked/banned
unsigned long lastTime = 0;
// Timer set to 10 minutes (600000)
//unsigned long timerDelay = 600000;
// Set timer to 10 seconds (10000)
unsigned long timerDelay = 10000;
String jsonBuffer;
// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
// set LCD address, number of columns and rows
// SDA -> GPIO21, SCL -> GPIO22
// lcd address is 0x27, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
// NTP Server time
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.");
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
}
void loop() {
// Send an HTTP GET request
if ((millis() - lastTime) > timerDelay) {
// Check WiFi connection status
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) can be used to get the type of the var
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing input failed!");
return;
}
// Serial.print("JSON object = ");
// Serial.println(myObject);
// Serial.print("Temperature: ");
// Serial.println(myObject["main"]["temp"]);
// Serial.print("Pressure: ");
// Serial.println(myObject["main"]["pressure"]);
// Serial.print("Humidity: ");
// Serial.println(myObject["main"]["humidity"]);
// Serial.print("Wind Speed: ");
// Serial.println(myObject["wind"]["speed"]);
// Get time
gmtOffset_sec = myObject["timezone"];
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
// time =
String time = printLocalTime();
// LCD Print
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"); // "°" char
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");
// get time format 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;
// Your Domain name with URL path or IP address with path
http.begin(client, serverName);
// Send HTTP POST request
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);
}
// Free resources
http.end();
return payload;
}
Common Course Links
Common Course Files
資源與參考資料
-
文件记录ESP32 Tutorial 43/55 - SunFounder doc page for IoT Internet Weather Stationdocs.sunfounder.com
文件📁
冇文件可用。