ESP32 Arduino程式 將台中市36小時天氣資料輸出到Telegram
https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001?Authorization=CWB-40C25FFF-1224-4250-B9D9-3735AAE17DBF&format=JSON&locationName=%E8%87%BA%E4%B8%AD%E5%B8%82
%E8%87%BA%E4%B8%AD%E5%B8%82 = 台中市
{
"success": "true",
"result": {
"resource_id": "F-C0032-001",
"fields": [
{
"id": "datasetDescription",
"type": "String"
},
{
"id": "locationName",
"type": "String"
},
{
"id": "parameterName",
"type": "String"
},
{
"id": "parameterValue",
"type": "String"
},
{
"id": "parameterUnit",
"type": "String"
},
{
"id": "startTime",
"type": "Timestamp"
},
{
"id": "endTime",
"type": "Timestamp"
}
]
},
"records": {
"datasetDescription": "三十六小時天氣預報",
"location": [
{
"locationName": "臺中市",
"weatherElement": [
{
"elementName": "Wx",
"time": [
{
"startTime": "2025-06-05 18:00:00",
"endTime": "2025-06-06 06:00:00",
"parameter": {
"parameterName": "陰短暫陣雨或雷雨",
"parameterValue": "18"
}
},
{
"startTime": "2025-06-06 06:00:00",
"endTime": "2025-06-06 18:00:00",
"parameter": {
"parameterName": "多雲午後短暫雷陣雨",
"parameterValue": "22"
}
},
{
"startTime": "2025-06-06 18:00:00",
"endTime": "2025-06-07 06:00:00",
"parameter": {
"parameterName": "多雲時晴",
"parameterValue": "3"
}
}
]
},
{
"elementName": "PoP",
"time": [
{
"startTime": "2025-06-05 18:00:00",
"endTime": "2025-06-06 06:00:00",
"parameter": {
"parameterName": "50",
"parameterUnit": "百分比"
}
},
{
"startTime": "2025-06-06 06:00:00",
"endTime": "2025-06-06 18:00:00",
"parameter": {
"parameterName": "30",
"parameterUnit": "百分比"
}
},
{
"startTime": "2025-06-06 18:00:00",
"endTime": "2025-06-07 06:00:00",
"parameter": {
"parameterName": "20",
"parameterUnit": "百分比"
}
}
]
},
{
"elementName": "MinT",
"time": [
{
"startTime": "2025-06-05 18:00:00",
"endTime": "2025-06-06 06:00:00",
"parameter": {
"parameterName": "25",
"parameterUnit": "C"
}
},
{
"startTime": "2025-06-06 06:00:00",
"endTime": "2025-06-06 18:00:00",
"parameter": {
"parameterName": "25",
"parameterUnit": "C"
}
},
{
"startTime": "2025-06-06 18:00:00",
"endTime": "2025-06-07 06:00:00",
"parameter": {
"parameterName": "26",
"parameterUnit": "C"
}
}
]
},
{
"elementName": "CI",
"time": [
{
"startTime": "2025-06-05 18:00:00",
"endTime": "2025-06-06 06:00:00",
"parameter": {
"parameterName": "舒適至悶熱"
}
},
{
"startTime": "2025-06-06 06:00:00",
"endTime": "2025-06-06 18:00:00",
"parameter": {
"parameterName": "舒適至悶熱"
}
},
{
"startTime": "2025-06-06 18:00:00",
"endTime": "2025-06-07 06:00:00",
"parameter": {
"parameterName": "舒適至悶熱"
}
}
]
},
{
"elementName": "MaxT",
"time": [
{
"startTime": "2025-06-05 18:00:00",
"endTime": "2025-06-06 06:00:00",
"parameter": {
"parameterName": "28",
"parameterUnit": "C"
}
},
{
"startTime": "2025-06-06 06:00:00",
"endTime": "2025-06-06 18:00:00",
"parameter": {
"parameterName": "31",
"parameterUnit": "C"
}
},
{
"startTime": "2025-06-06 18:00:00",
"endTime": "2025-06-07 06:00:00",
"parameter": {
"parameterName": "29",
"parameterUnit": "C"
}
}
]
}
]
}
]
}
}
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h> // 請安裝此庫: 工具 -> 管理程式庫 -> 搜尋 "ArduinoJson"
// Wi-Fi 設定
const char* ssid = "Wokwi-GUEST"; // 請替換為您的Wi-Fi SSID
const char* password = ""; // 請替換為您的Wi-Fi 密碼
// 中央氣象署開放資料平台設定
const char* cwa_api_url = "https://opendata.cwa.gov.tw/api/v1/rest/datastore/F-C0032-001";
const char* cwa_authorization_code = "CWB-404C25FFF-1242F4-4250-B9D9-37635AAE177DBF"; // 您的CWB授權碼
const char* location_name = "臺中市"; // 要爬取資料的縣市
// Telegram Bot 設定
const char* telegram_bot_token = "773798940254:AAHbrWu9ovb1BKPQyW9sbNSjNxfCGCrEWU-o"; // 請替換為您的Telegram Bot Token
const char* telegram_chat_id = "7496152148469"; // 請替換為您的Telegram Chat ID
void setup() {
Serial.begin(115200);
// 連線到Wi-Fi
Serial.print("Connecting to WiFi: ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("\nWiFi connected.");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// 獲取天氣資料並發送到Telegram
getWeatherAndSendToTelegram();
}
void loop() {
// 您可以在這裡加入定時更新的邏輯,例如每小時更新一次
delay(30000); // 每30Sec更新一次
getWeatherAndSendToTelegram();
}
void getWeatherAndSendToTelegram() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = String(cwa_api_url) + "?Authorization=" + cwa_authorization_code + "&format=JSON&locationName=" + location_name;
Serial.print("Fetching weather data from: ");
Serial.println(url);
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0) {
Serial.printf("HTTP Code: %d\n", httpCode);
if (httpCode == HTTP_CODE_OK) {
String payload = http.getString();
// Serial.println(payload); // 暫時取消註解這行,用於調試原始JSON,確認是您提供的結構
// 解析JSON
DynamicJsonDocument doc(40000); // 確保足夠的緩衝區大小
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
sendTelegramMessage("Failed to parse weather data. Error: " + String(error.f_str()));
return;
}
sendTelegramMessage("✨ 臺中市36小時天氣預報 ✨"); // 先發送標題
// *** 關鍵修正點:JSON 路徑從 doc["records"]["locations"][0]["location"] 改為 doc["records"]["location"] ***
JsonArray locations = doc["records"]["location"];
if (locations.isNull()) {
Serial.println("Error: 'location' array not found in JSON.");
sendTelegramMessage("無法找到天氣地區資料。");
return;
}
for (JsonObject location : locations) {
if (String(location["locationName"]) == location_name) {
JsonArray weatherElements = location["weatherElement"];
if (weatherElements.isNull()) {
Serial.println("Error: 'weatherElement' array not found for 臺中市.");
sendTelegramMessage("無法找到臺中市的天氣元素資料。");
return;
}
// 先找到 Wx 元素,用它的時間來做主導遍歷
JsonArray times_to_iterate;
for (JsonObject element : weatherElements) {
if (String(element["elementName"]) == "Wx") {
times_to_iterate = element["time"];
break; // 找到 Wx 元素後就跳出迴圈
}
}
if (times_to_iterate.isNull()) {
Serial.println("Error: Wx element or its time data not found.");
sendTelegramMessage("無法取得天氣現象時間資料。");
return;
}
for (JsonObject time_period : times_to_iterate) {
String periodMessage = "--- 🗓️ 時段預報 ---\n";
periodMessage += "時間: " + String(time_period["startTime"]) + " ~ " + String(time_period["endTime"]) + "\n";
// 遍歷所有天氣元素,找到對應時間段的資料
for (JsonObject element : weatherElements) {
String elementName = element["elementName"];
JsonArray innerTimes = element["time"];
if (innerTimes.isNull()) continue; // 如果該元素沒有時間數據,跳過
for (JsonObject innerTime : innerTimes) {
// 比較時間區間
if (String(innerTime["startTime"]) == String(time_period["startTime"]) &&
String(innerTime["endTime"]) == String(time_period["endTime"])) {
if (elementName == "Wx") {
periodMessage += "天氣: " + String(innerTime["parameter"]["parameterName"]) + "\n";
} else if (elementName == "MaxT") {
periodMessage += "最高溫: " + String(innerTime["parameter"]["parameterName"]) + "°C\n";
} else if (elementName == "MinT") {
periodMessage += "最低溫: " + String(innerTime["parameter"]["parameterName"]) + "°C\n";
} else if (elementName == "CI") {
periodMessage += "舒適度: " + String(innerTime["parameter"]["parameterName"]) + "\n";
} else if (elementName == "PoP") {
periodMessage += "降雨機率: " + String(innerTime["parameter"]["parameterName"]) + "%\n";
}
// 如果有其他需要顯示的元素,可以在這裡添加
break; // 找到對應時間的元素就跳出內層迴圈
}
}
}
sendTelegramMessage(periodMessage); // 發送每個時間段的訊息
delay(200); // 稍作延遲,避免連續發送過快
}
}
}
} else {
Serial.printf("Error getting weather data. HTTP code: %d\n", httpCode);
sendTelegramMessage("Error getting weather data. HTTP code: " + String(httpCode));
}
} else {
Serial.printf("HTTP GET request failed. Error: %s\n", http.errorToString(httpCode).c_str());
sendTelegramMessage("HTTP GET request failed. Error: " + String(http.errorToString(httpCode).c_str()));
}
http.end();
} else {
Serial.println("WiFi not connected. Cannot get weather data.");
sendTelegramMessage("WiFi not connected. Cannot get weather data.");
}
}
void sendTelegramMessage(String message) {
HTTPClient http;
String url = "https://api.telegram.org/bot" + String(telegram_bot_token) + "/sendMessage";
http.begin(url);
http.addHeader("Content-Type", "application/json");
// 對訊息內容進行 JSON 安全編碼,特別是對於雙引號
message.replace("\"", "\\\"");
String httpRequestData = "{\"chat_id\": \"" + String(telegram_chat_id) + "\", \"text\": \"" + message + "\"}";
Serial.print("Sending to Telegram: ");
Serial.println(httpRequestData);
int httpCode = http.POST(httpRequestData);
if (httpCode > 0) {
Serial.printf("Telegram API response code: %d\n", httpCode);
if (httpCode == HTTP_CODE_OK) {
String response = http.getString();
Serial.println(response);
}
} else {
Serial.printf("Error sending message to Telegram. HTTP code: %d\n", httpCode);
Serial.printf("Error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
}








沒有留言:
張貼留言