OpenWeatherMap 是一個提供全球氣象資料的線上平台,可透過 API (Application Programming Interface) 取得即時天氣、預報、歷史天氣、空氣品質等資料,廣泛應用於網站、APP、IoT(物聯網)與學術研究。使用 API 前需註冊帳號,並取得 API 金鑰,資料為 JSON 格式,利用 JSON 函式庫解析後即可進一步應用。
該網站可使用的免費項目:Current weather and forecasts,基本語法如下:
https://api.openweathermap.org/data/2.5/weather?lat=緯度&lon=經度&units=metric&appid=API金鑰
https://api.openweathermap.org/data/2.5/weather?lat=25.03&lon=121.54&units=metric&appid=API金鑰
{"coord":{"lon":121.54,"lat":25.03},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"stations","main":{"temp":33.38,"feels_like":40.38,"temp_min":31.68,"temp_max":33.83,"pressure":1003,"humidity":62,"sea_level":1003,"grnd_level":985},"visibility":10000,"wind":{"speed":2.24,"deg":300,"gust":8.49},"clouds":{"all":75},"dt":1747985425,"sys":{"type":2,"id":266033,"country":"TW","sunrise":1747947985,"sunset":1747996502},"timezone":28800,"id":1675720,"name":"Xianeibu","cod":200}
{
"coord": {
"lon": 121.54,
"lat": 25.03
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
],
"base": "stations",
"main": {
"temp": 33.38,
"feels_like": 40.38,
"temp_min": 31.68,
"temp_max": 33.83,
"pressure": 1003,
"humidity": 62,
"sea_level": 1003,
"grnd_level": 985
},
"visibility": 10000,
"wind": {
"speed": 2.24,
"deg": 300,
"gust": 8.49
},
"clouds": {
"all": 75
},
"dt": 1747985425,
"sys": {
"type": 2,
"id": 266033,
"country": "TW",
"sunrise": 1747947985,
"sunset": 1747996502
},
"timezone": 28800,
"id": 1675720,
"name": "Xianeibu",
"cod": 200
}
https://api.openweathermap.org/data/2.5/weather?q=城市,國家或地區&units=metric&appid=API金鑰
https://api.openweathermap.org/data/2.5/weather?q=Taipei,TW&units=metric&appid=API金鑰
{"coord":{"lon":121.5319,"lat":25.0478},"weather":[{"id":803,"main":"Clouds","description":"broken clouds","icon":"04d"}],"base":"stations","main":{"temp":33.42,"feels_like":40.42,"temp_min":31.7,"temp_max":33.84,"pressure":1002,"humidity":62,"sea_level":1002,"grnd_level":985},"visibility":10000,"wind":{"speed":1.54,"deg":100},"clouds":{"all":75},"dt":1747984953,"sys":{"type":2,"id":266033,"country":"TW","sunrise":1747947985,"sunset":1747996506},"timezone":28800,"id":1668341,"name":"Taipei","cod":200}
{
"coord": {
"lon": 121.5319,
"lat": 25.0478
},
"weather": [
{
"id": 803,
"main": "Clouds",
"description": "broken clouds",
"icon": "04d"
}
],
"base": "stations",
"main": {
"temp": 33.42,
"feels_like": 40.42,
"temp_min": 31.7,
"temp_max": 33.84,
"pressure": 1002,
"humidity": 62,
"sea_level": 1002,
"grnd_level": 985
},
"visibility": 10000,
"wind": {
"speed": 1.54,
"deg": 100
},
"clouds": {
"all": 75
},
"dt": 1747984953,
"sys": {
"type": 2,
"id": 266033,
"country": "TW",
"sunrise": 1747947985,
"sunset": 1747996506
},
"timezone": 28800,
"id": 1668341,
"name": "Taipei",
"cod": 200
}
JSON內容有經緯度座標、天氣概況、溫度、溼度、大氣壓力、風速等資料。
HTTP請求取得網站資料
ESP32可透過HTTPClient函式庫取得OpenWeatherMap網站的資料,方法如下:
//---------------------------------------------------------------
#include <WiFi.h>
const char *ssid = "SSID"; // 連上無線基地臺的SSID
const char *password = "密碼"; // 連上無線基地臺的密碼
//---------------------------------------------------------------
void connect_to_wifi()
{
WiFi.begin(ssid, password); // 啟動WiFi連線
Serial.printf("Connecting to %s ", ssid);
while(WiFi.status() != WL_CONNECTED) // 只要WiFi連線狀態不正常
{
delay(500); // 每0.5秒印出一個點
Serial.print(".");
}
Serial.println(" CONNECTED!");
Serial.print("SSID: ");
Serial.println(WiFi.SSID()); // 印出SSID
Serial.print("IP: ");
Serial.println(WiFi.localIP()); // 印出IP
Serial.print("Subnet Mask IP: ");
Serial.println(WiFi.subnetMask()); // 印出子網路遮罩
Serial.print("Gateway IP: ");
Serial.println(WiFi.gatewayIP()); // 印出閘道IP
Serial.print("DNS IP: ");
Serial.println(WiFi.dnsIP()); // 印出DNS IP
}
//---------------------------------------------------------------
#include <HTTPClient.h> // 發送http請求,取得網站資料
HTTPClient http;
String url = "https://api.openweathermap.org/data/2.5/weather?q=Taipei,TW&units=metric&appid=API金鑰"; // 網址
//---------------------------------------------------------------
void setup()
{
//------------------------------------------------------------------------------
Serial.begin(9600); // 啟用串列埠監看視窗
//------------------------------------------------------------------------------
connect_to_wifi(); // 連線到WiFi
//------------------------------------------------------------------------------
http.begin(url); // 開始連接網頁
int httpCode = http.GET(); // 執行GET請求,回傳碼儲存於httpCode
if (httpCode == HTTP_CODE_OK) // 如果連線正常
{
String payload = http.getString(); // 傳回的網頁內容儲存於字串變數payload(承載量)
Serial.println(payload); // 印出傳回的網頁內容
}
else
{
Serial.print("HTTP GET failed, error code: "); // 印出錯誤訊息
Serial.println(httpCode);
}
http.end(); // 結束連線
//------------------------------------------------------------------------------
}
void loop()
{
}
傳回結果與瀏覽器相同,只要再經過JSON解析之後,即可將各項資料進一步運用。
JSON格式解析
ESP32可透過ArduinoJson函式庫解析網站的JSON資料,方法如下:
//---------------------------------------------------------------
#include <WiFi.h>
const char *ssid = "SSID"; // 連上無線基地臺的SSID
const char *password = "密碼"; // 連上無線基地臺的密碼
//---------------------------------------------------------------
void connect_to_wifi()
{
WiFi.begin(ssid, password); // 啟動WiFi連線
Serial.printf("Connecting to %s ", ssid);
while(WiFi.status() != WL_CONNECTED) // 只要WiFi連線狀態不正常
{
delay(500); // 每0.5秒印出一個點
Serial.print(".");
}
Serial.println(" CONNECTED!");
Serial.print("SSID: ");
Serial.println(WiFi.SSID()); // 印出SSID
Serial.print("IP: ");
Serial.println(WiFi.localIP()); // 印出IP
Serial.print("Subnet Mask IP: ");
Serial.println(WiFi.subnetMask()); // 印出子網路遮罩
Serial.print("Gateway IP: ");
Serial.println(WiFi.gatewayIP()); // 印出閘道IP
Serial.print("DNS IP: ");
Serial.println(WiFi.dnsIP()); // 印出DNS IP
}
//---------------------------------------------------------------
#include <HTTPClient.h> // 發送http請求,取得網站資料
HTTPClient http;
// String url = "https://api.openweathermap.org/data/2.5/weather?q=Taipei,TW&units=metric&appid=API金鑰"; // 網址
// 將網址中的城市、地區、API金鑰設定為變數,以方便後續程式操控
String city = "Taipei";
String countryCode = "TW";
String ApiKey = "API金鑰";
String url = "https://api.openweathermap.org/data/2.5/weather?q=" + city + "," + countryCode + "&units=metric&appid=" + ApiKey; // 網址
//---------------------------------------------------------------
#include <ArduinoJson.h> // 解析JSON資料
String weatherDescription; // 天氣概況
String temp; // 溫度
String pressure; // 大氣壓力
String humidity; // 溼度
//---------------------------------------------------------------
void get_weather_data()
{
http.begin(url); // 開始連接網頁
int httpCode = http.GET(); // 執行GET請求,回傳碼儲存於httpCode
if (httpCode == HTTP_CODE_OK) // 如果連線正常
{
String payload = http.getString(); // 傳回的網頁內容儲存於字串變數payload(承載量)
// Serial.println(payload); // 印出傳回的網頁內容
// -------------------------------------------------------------
// OpenWeatherMap JSON格式解析
// -------------------------------------------------------------
DynamicJsonDocument WeatherJson(payload.length() * 2); // 宣告一個Json文件,名稱為WeatherJson(陣列格式)
deserializeJson(WeatherJson, payload); // 解析payload為JSON Array格式
weatherDescription = WeatherJson["weather"][0]["description"].as<String>(); // 取得天氣概況,weather是陣列,[0]是索引值
temp = WeatherJson["main"]["temp"].as<String>(); // 取得溫度
pressure = WeatherJson["main"]["pressure"].as<String>(); // 取得氣壓
humidity = WeatherJson["main"]["humidity"].as<String>(); // 取得溼度
Serial.println("----------------------------------");
Serial.print("Weather description: ");
Serial.println(weatherDescription);
Serial.print("Temp: ");
Serial.print(temp);
Serial.println(" °C");
Serial.print("Pressure: ");
Serial.print(pressure);
Serial.println(" hPa");
Serial.print("Humidity: ");
Serial.print(humidity);
Serial.println(" %");
Serial.println("----------------------------------");
}
else
{
Serial.print("HTTP GET failed, error code: "); // 印出錯誤訊息
Serial.println(httpCode);
}
http.end(); // 結束連線
}
void setup()
{
//-------------------------------------------
Serial.begin(9600); // 啟用串列埠監看視窗
//-------------------------------------------
connect_to_wifi(); // 連線到WiFi
//-------------------------------------------
get_weather_data(); // 取得天氣資料
//-------------------------------------------
}
void loop()
{
}
作業練習1:請利用ESP32取得時間(每秒1次)、天氣資料(每10秒1次),將結果顯示在監看視窗上。
作業練習2:
- 請利用ESP32的WiFi功能,連上網路取得NTP時間資料及OpenWeatherMap天氣資料,利用紅外線遙控器、紅外線接收器,可選擇臺灣不同的城市,將時間、天氣概況、溫度、溼度、大氣壓力等訊息呈現在LCD上。
- 基本功能:
- 請自行定義10個城市。
- 按下0-9數字鍵,可對應定義的城市,並顯示時間及天氣訊息在LCD上,一個頁面不夠顯示時,可用二個頁面交替顯示。
- 按下PREV、NEXT鍵,可切換前一個或下一個城市,可在城市0~9之間循環切換。
- 按下VOL+、VOL-鍵,可切換當前城市的時間及天氣訊息。
- 按下EQ鍵,可顯示當下日期時間,時間每秒更新一次。
- 進階功能可自行補充,例如:
- 超過10個以上的城市。
- 不同天氣,可在RGB LED燈上顯示不同的顏色。
- 請拍照、錄影,並完成實習報告,上傳Google Classroom作業。
- 實習報告須包含下列內容:(1)摘要 (2)動機 (3)主題 (4)實作步驟 (5)實作結果 (6)心得與討論 (7)參考資料。
成果影片: