', { cookie_domain: 'auto', cookie_flags: 'max-age=0;domain=.tistory.com', cookie_expires: 7 * 24 * 60 * 60 // 7 days, in seconds }); ESP32 날씨 표시기 #5 - ChatGPT 코드 정리. :: MakerLee's Workspace
728x90

아무래도 제 개인의 코딩 능력을 많이 벗어난 데이터셋 정리 등이 필요하다 보니 ChatGPT에게 도움을 청했습니다. 

한동안 이녀석과 질답을 주고받으며 코드를 많이 쌓긴 했습니다

하지만 대화가 길어지면 점점 버벅대고 결과가 산으로 가기도 하네요.

 

그래서 일단 단계별로 진행하고 코드 내용을 따로 기록하기로 합니다.

 

#include <WiFi.h>
#include <HTTPClient.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "GetLocate.h"
#include <Arduino_JSON.h>

// Wi-Fi 설정
const char* ssid = "ssid";
const char* password = "password";

const char* apiKey = "API_KEY";
const long utcOffsetInSeconds = 3600 * 9; // 한국 표준시 (UTC+9)

// 타임서버 설정
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", utcOffsetInSeconds);

// 업데이트 간격 (예: 10분)
unsigned long updateInterval = 600000;
unsigned long previousMillis = 0;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");

  // 타임서버 연결
  timeClient.begin();
  timeClient.update();

  // 위치 정보 가져오기
  Location loc = getLocation();
  Serial.print("Location - Country: "); Serial.print(loc.country);
  Serial.print(", Region: "); Serial.print(loc.regionName);
  Serial.print(", City: "); Serial.println(loc.city);

  // 초기 날씨 정보 업데이트
  getWeatherUpdate();
}

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= updateInterval) {
    previousMillis = currentMillis;

    // 타임서버 업데이트
    timeClient.update();

    // 현재 시간 출력
    Serial.print("Current time: ");
    Serial.println(timeClient.getFormattedTime());

    // 날씨 정보 업데이트
    getWeatherUpdate();
  }
}

// 날씨 정보를 업데이트하는 함수
void getWeatherUpdate() {
  Location loc = getLocation();
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    String weatherURL = "http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst";
    weatherURL += "?serviceKey=" + String(apiKey);
    weatherURL += "&numOfRows=60&pageNo=1&base_date=" + getCurrentDate();
    weatherURL += "&base_time=0630&nx=" + String(loc.nx) + "&ny=" + String(loc.ny);
    weatherURL += "&dataType=JSON"; // JSON 형식으로 요청

    http.begin(weatherURL);
    int httpCode = http.GET();

    if (httpCode > 0) {
      String payload = http.getString();
      Serial.println("Weather Data: ");
      
      // 특수문자 및 따옴표 제거 및 줄바꿈 출력
      String formattedPayload = formatPayload(payload);
      Serial.println(formattedPayload);
    } else {
      Serial.print("Error on HTTP request: ");
      Serial.println(httpCode);
    }
    http.end();
  }
}

// 날씨 API의 응답 데이터를 포맷하는 함수
// 이 함수는 JSON 응답에서 불필요한 특수문자와 따옴표를 제거하고,
// 쉼표를 기준으로 줄바꿈을 추가하여 가독성을 높인다.
String formatPayload(String payload) {
  payload.replace("{", ""); // '{' 제거
  payload.replace("}", ""); // '}' 제거
  payload.replace("[", ""); // '[' 제거
  payload.replace("]", ""); // ']' 제거
  payload.replace("(", ""); // '(' 제거
  payload.replace(")", ""); // ')' 제거
  payload.replace("\"", ""); // '"' 제거
  payload.replace(",", ",\n"); // ',' 뒤에 줄바꿈 추가
  return payload;
}

// 현재 날짜를 YYYYMMDD 형식으로 반환하는 함수
// 이 함수는 NTPClient를 사용하여 현재 시간을 가져오고,
// tm 구조체를 사용하여 로컬 시간으로 변환한 후, strftime 함수를 사용하여
// 날짜를 문자열 형식으로 반환한다.
String getCurrentDate() {
  time_t now = timeClient.getEpochTime(); // 현재 epoch 시간 가져오기
  struct tm* timeinfo = localtime(&now); // epoch 시간을 로컬 시간으로 변환
  char buffer[11]; // 날짜를 저장할 버퍼
  strftime(buffer, sizeof(buffer), "%Y%m%d", timeinfo); // 날짜를 YYYYMMDD 형식으로 포맷팅
  return String(buffer); // 문자열로 반환
}

이게 메인 코드이고요

 

 

 

#include <WiFi.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

// Grid 구조체 정의
struct Grid {
  int x;
  int y;
};

// dfs_xy_conv 함수 선언
Grid dfs_xy_conv(const char* code, double v1, double v2);

// Location 구조체 정의
struct Location {
  String country;
  String regionName;
  String city;
  int nx;
  int ny;
};

Location getLocation() {
  HTTPClient http;
  Location loc;
  http.begin("http://ip-api.com/json");
  int httpCode = http.GET();

  if (httpCode > 0) {
    String payload = http.getString();
    JSONVar doc = JSON.parse(payload);

    if (JSON.typeof(doc) != "undefined" && strcmp((const char*)doc["status"], "success") == 0) {
      loc.country = (const char*)doc["country"];
      loc.regionName = (const char*)doc["regionName"];
      loc.city = (const char*)doc["city"];
      float lat = (double)doc["lat"];
      float lon = (double)doc["lon"];

      // 좌표를 NX, NY로 변환
      auto grid = dfs_xy_conv("toXY", lat, lon);
      loc.nx = grid.x;
      loc.ny = grid.y;
    } else {
      Serial.println("Failed to parse location data");
    }
  } else {
    Serial.println("Failed to retrieve location data");
  }
  http.end();
  return loc;
}

// dfs_xy_conv 함수 정의
Grid dfs_xy_conv(const char* code, double v1, double v2) {
  const double RE = 6371.00877;
  const double GRID = 5.0;
  const double SLAT1 = 30.0;
  const double SLAT2 = 60.0;
  const double OLON = 126.0;
  const double OLAT = 38.0;
  const double XO = 43;
  const double YO = 136;

  const double DEGRAD = M_PI / 180.0;
  const double RADDEG = 180.0 / M_PI;

  double re = RE / GRID;
  double slat1 = SLAT1 * DEGRAD;
  double slat2 = SLAT2 * DEGRAD;
  double olon = OLON * DEGRAD;
  double olat = OLAT * DEGRAD;

  double sn = tan(M_PI * 0.25 + slat2 * 0.5) / tan(M_PI * 0.25 + slat1 * 0.5);
  sn = log(cos(slat1) / cos(slat2)) / log(sn);
  double sf = tan(M_PI * 0.25 + slat1 * 0.5);
  sf = pow(sf, sn) * cos(slat1) / sn;
  double ro = tan(M_PI * 0.25 + olat * 0.5);
  ro = re * sf / pow(ro, sn);

  Grid rs = {0, 0};
  if (strcmp(code, "toXY") == 0) {
    double ra = tan(M_PI * 0.25 + (v1) * DEGRAD * 0.5);
    ra = re * sf / pow(ra, sn);
    double theta = v2 * DEGRAD - olon;
    if (theta > M_PI) theta -= 2.0 * M_PI;
    if (theta < -M_PI) theta += 2.0 * M_PI;
    theta *= sn;
    rs.x = floor(ra * sin(theta) + XO + 0.5);
    rs.y = floor(ro - ra * cos(theta) + YO + 0.5);
  }
  return rs;
}

 

이건 GetLocate.h 코드입니다.

Wifi 주소를 추적해서 현재 위치를 파악하고, 그 위치정보를 기상청 API에서 요구하는 그리드 격자정보로 변환합니다.
https://gist.github.com/fronteer-kr/14d7f779d52a21ac2f16
의 코드를 참조하도록 했습니다. 

 

 

이 코드를 실행한 결과는 다음과 같습니다.

Connecting to WiFi...
Connecting to WiFi...
Connected to WiFi
Location - Country: South Korea, Region: Gyeonggi-do, City: Seongnam-si
Weather Data: 
response:header:resultCode:00,
resultMsg:NORMAL_SERVICE,
body:dataType:JSON,
items:item:baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1000,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:LGT,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1000,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:PTY,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0700,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0800,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:0900,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1000,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1100,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:RN1,
fcstDate:20240529,
fcstTime:1200,
fcstValue:媛뺤닔?놁쓬,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0700,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0800,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1100,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:SKY,
fcstDate:20240529,
fcstTime:1200,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0700,
fcstValue:17,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0800,
fcstValue:19,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:0900,
fcstValue:21,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1000,
fcstValue:23,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1100,
fcstValue:24,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:T1H,
fcstDate:20240529,
fcstTime:1200,
fcstValue:25,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0700,
fcstValue:75,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0800,
fcstValue:70,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:0900,
fcstValue:65,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1000,
fcstValue:60,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1100,
fcstValue:50,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:REH,
fcstDate:20240529,
fcstTime:1200,
fcstValue:45,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0700,
fcstValue:-0.8,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0800,
fcstValue:-0.4,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:0900,
fcstValue:0.5,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1100,
fcstValue:2.2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:UUU,
fcstDate:20240529,
fcstTime:1200,
fcstValue:2.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0700,
fcstValue:0.5,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0800,
fcstValue:0.9,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1.1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1000,
fcstValue:1.1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1100,
fcstValue:0.8,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VVV,
fcstDate:20240529,
fcstTime:1200,
fcstValue:0.6,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0700,
fcstValue:118,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0800,
fcstValue:151,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:0900,
fcstValue:204,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1000,
fcstValue:236,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1100,
fcstValue:250,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:VEC,
fcstDate:20240529,
fcstTime:1200,
fcstValue:257,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0700,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0800,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:0900,
fcstValue:1,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1000,
fcstValue:2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1100,
fcstValue:2,
nx:62,
ny:122,
baseDate:20240529,
baseTime:0630,
category:WSD,
fcstDate:20240529,
fcstTime:1200,
fcstValue:3,
nx:62,
ny:122,
pageNo:1,
numOfRows:60,
totalCount:60

 

현재 위치정보는 성남시로 나오는데요.

핸드폰 핫스팟으로 접속했더니 현재 위치정보가 좀 많이 어긋나네요. 

이건 급한게 아니니 천천히 수정하려고 합니다. 

 

 

항목설명

baseDate 예보 발표 날짜 (YYYYMMDD 형식)
baseTime 예보 발표 시각 (HHMM 형식)
category 예보 항목 코드
fcstDate 예보 날짜 (YYYYMMDD 형식)
fcstTime 예보 시각 (HHMM 형식)
fcstValue 예보 값
nx 예보 지점의 X 좌표
ny 예보 지점의 Y 좌표

 

코드 (category)설명

LGT 낙뢰 가능성
PTY 강수 형태
RN1 1시간 강수량
SKY 하늘 상태
T1H 1시간 기온
REH 습도
UUU 동서바람성분
VVV 남북바람성분
VEC 풍향
WSD 풍속

 

 

모든 코드와 자료정리는 ChatGPT가 했습니다. 
다음은 이 데이터를 간결하게 정리해서 저장하는 부분을 추가하려고 합니다. 

728x90

+ Recent posts