Openweathermap에서 날씨를 받아와 사용하려 했는데 데이터 변환 과정에서 골치아픈 부분이 있었습니다.
차후 4.2" 전자잉크 등 보다 화면이 넓은 기기를 사용하기 위해서 당일의 온도변화, 7일치의 날씨변화 등도 있었으면 했고요.
무엇보다 현재 날씨는 알 수 있는데 당일 날씨나 최저, 최고 온도 등 우리가 흔히 쓰는 기준으로 데이터를 얻기가 힘들더군요.
그리고 이 모든 것을 ChatGPT4.0 에게 맡겼습니다.
저는 그냥 이렇게 해줘, 저렇게 해줘, 여기 틀렸잖아
를 반복하다 보니 코드는 손도 안대고 좋은 결과가 나오더군요
금일 온도 / 최저 / 최고온도 / 체감온도/ 구름 / 풍속 / 강수량 / 강설량 등이 잘 정리되어 출력된 것을 볼 수 있습니다.
5일간 날씨 데이터도 마찬가지로 정리되어 나오고 있고요
아래는 이 코드입니다.
#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>
// WiFi 설정
const char* ssid = "Yourssid";
const char* password = "yourPW";
// OpenWeatherMap API 키
String openWeatherMapApiKey = "YourAPI";
// 서울의 도시명과 국가 코드
String city = "Seoul";
String countryCode = "KR";
// 업데이트 주기 설정 (15초)
unsigned long lastTime = 0;
unsigned long timerDelay = 15000;
void setup() {
Serial.begin(115200); // 시리얼 모니터 시작
Serial.println("serial start"); // 디버깅 메시지 추가
WiFi.begin(ssid, password); // WiFi 연결 시작
Serial.println("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nConnected to WiFi");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// 즉시 첫 번째 API 호출을 위해 lastTime 초기화
lastTime = millis() - timerDelay;
}
void loop() {
// 타이머가 만료되었을 때 데이터 요청
if ((millis() - lastTime) > timerDelay) {
if (WiFi.status() == WL_CONNECTED) {
// API 요청 URL 구성 - 3시간 간격의 5일 예보 데이터
String serverPath = "https://api.openweathermap.org/data/2.5/forecast?q=" + city + "," + countryCode + "&appid=" + openWeatherMapApiKey + "&units=metric";
// 데이터 요청 및 수신
String weatherData = httpGETRequest(serverPath.c_str());
if (weatherData != "{}") {
parseWeatherData(weatherData); // 수신된 데이터 파싱
}
lastTime = millis();
} else {
Serial.println("WiFi Disconnected");
}
}
}
// HTTP GET 요청 함수
String httpGETRequest(const char* serverName) {
WiFiClientSecure client;
client.setInsecure(); // SSL 인증서 검증 무시
HTTPClient http;
http.begin(client, serverName); // HTTPS 연결 시작
Serial.println("Requesting URL: " + String(serverName));
int httpResponseCode = http.GET();
String payload = "{}";
if (httpResponseCode == 200) {
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
payload = http.getString();
} else {
Serial.print("Error code: ");
Serial.println(httpResponseCode);
payload = http.getString();
Serial.println("Error response: " + payload);
}
http.end();
return payload;
}
// 타임스탬프를 한국 표준시(KST)로 변환하는 함수
String convertUnixTimeToKST(long unixTime) {
unixTime += 9 * 3600; // UTC+9 시간대 보정
time_t t = unixTime;
struct tm *tmStruct = localtime(&t);
char buffer[30];
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", tmStruct);
return String(buffer);
}
// 날씨 데이터 파싱 함수
void parseWeatherData(String json) {
JSONVar myObject = JSON.parse(json);
if (JSON.typeof(myObject) == "undefined") {
Serial.println("Parsing failed!");
return;
}
// 오늘 날씨 데이터 파싱 및 출력
Serial.println("Today's Weather Data:");
JSONVar list = myObject["list"];
// 하루 동안의 데이터에서 최저/최고 온도 계산
float dayMinTemp = 1000;
float dayMaxTemp = -1000;
for (int i = 0; i < 8; i++) { // 24시간 내의 3시간 간격 데이터
JSONVar data = list[i];
float temp_min = (float)(double)data["main"]["temp_min"];
float temp_max = (float)(double)data["main"]["temp_max"];
if (temp_min < dayMinTemp) dayMinTemp = temp_min;
if (temp_max > dayMaxTemp) dayMaxTemp = temp_max;
}
JSONVar todayData = list[0];
float temp = (float)(double)todayData["main"]["temp"];
float feels_like = (float)(double)todayData["main"]["feels_like"];
const char* weather_description = (const char*)(todayData["weather"][0]["description"]);
float humidity = (float)(double)todayData["main"]["humidity"];
float clouds = (float)(double)todayData["clouds"]["all"];
float wind_speed = (float)(double)todayData["wind"]["speed"];
float rain = todayData.hasOwnProperty("rain") ? (float)(double)todayData["rain"]["3h"] : 0;
float snow = todayData.hasOwnProperty("snow") ? (float)(double)todayData["snow"]["3h"] : 0;
Serial.print("Temp: ");
Serial.println(temp);
Serial.print("Min Temp: ");
Serial.println(dayMinTemp);
Serial.print("Max Temp: ");
Serial.println(dayMaxTemp);
Serial.print("Feels Like: ");
Serial.println(feels_like);
Serial.print("Humidity: ");
Serial.println(humidity);
Serial.print("Clouds: ");
Serial.println(clouds);
Serial.print("Weather: ");
Serial.println(weather_description);
Serial.print("Wind Speed: ");
Serial.println(wind_speed);
Serial.print("Rain Volume (3h): ");
Serial.println(rain);
Serial.print("Snow Volume (3h): ");
Serial.println(snow);
Serial.println("-------");
// 5일간 날씨 데이터 파싱 및 출력
Serial.println("5 Days Weather Data:");
for (int day = 0; day < 5; day++) {
float minTemp = 1000;
float maxTemp = -1000;
float avgHumidity = 0;
float avgClouds = 0;
float avgWindSpeed = 0;
float totalRain = 0;
float totalSnow = 0;
int count = 0;
String weatherDescriptions = "";
for (int i = day * 8; i < (day + 1) * 8 && i < list.length(); i++) {
JSONVar dayData = list[i];
float temp_min = (float)(double)dayData["main"]["temp_min"];
float temp_max = (float)(double)dayData["main"]["temp_max"];
float humidity = (float)(double)dayData["main"]["humidity"];
float clouds = (float)(double)dayData["clouds"]["all"];
float wind_speed = (float)(double)dayData["wind"]["speed"];
float rain = dayData.hasOwnProperty("rain") ? (float)(double)dayData["rain"]["3h"] : 0;
float snow = dayData.hasOwnProperty("snow") ? (float)(double)dayData["snow"]["3h"] : 0;
const char* weather_description = (const char*)(dayData["weather"][0]["description"]);
if (temp_min < minTemp) minTemp = temp_min;
if (temp_max > maxTemp) maxTemp = temp_max;
avgHumidity += humidity;
avgClouds += clouds;
avgWindSpeed += wind_speed;
totalRain += rain;
totalSnow += snow;
weatherDescriptions = String(weather_description);
count++;
}
avgHumidity /= count;
avgClouds /= count;
avgWindSpeed /= count;
long date = (long)list[day * 8]["dt"];
Serial.print("Date: ");
Serial.print(convertUnixTimeToKST(date));
Serial.print(", Min Temp: ");
Serial.print(minTemp);
Serial.print(", Max Temp: ");
Serial.print(maxTemp);
Serial.print(", Humidity: ");
Serial.print(avgHumidity);
Serial.print(", Clouds: ");
Serial.print(avgClouds);
Serial.print(", Wind Speed: ");
Serial.print(avgWindSpeed);
Serial.print(", Rain Volume (3h): ");
Serial.print(totalRain);
Serial.print(", Snow Volume (3h): ");
Serial.print(totalSnow);
Serial.print(", Weather: ");
Serial.println(weatherDescriptions);
Serial.println("-------");
}
}
그렇지만 이 모든 걸 갈아엎게 되는데.. 다음 포스팅에 이어서 쓰겠습니다.
'Making > ESP32 날씨 표시기' 카테고리의 다른 글
ESP32 날씨 표시기 - 재정리 (0) | 2025.01.25 |
---|---|
ESP32 날씨 표시기 #5 - ChatGPT 코드 정리. (0) | 2024.05.29 |
ESP32 날씨 표시기 #4 - 공공 데이터 포털. (0) | 2024.05.29 |
ESP32 날씨 표시기 #2 - openweathemap에서 날씨 받아오기 (0) | 2024.05.12 |
ESP32 날씨 표시기 #1 (2) | 2024.05.06 |