esp32 OpenWeatherMap에서 실시간 날씨 정보 받기

OpenWeatherMap.org#

OpenWeatherMap은 세계 각 지역의 현재 날씨, 예보, 과거 날씨 데이터를 제공하는 사이트입니다. (몇가지 제약이 있긴 하지만) 회원가입을 통해서 API Key를 생성하고 이를 통해 무료로 실시간 날씨 정보를 얻을 수 있습니다.


Free Current weather and forecasts collection#


Current weather collections API Key 생성#

  1. Sign Up을 클릭하여 회원가입을 하고,



  2. Sign In을 클릭하여 로그인한 뒤, API Keys를 누릅니다.



  3. Default로 지정되어 있는 Key를 복사하거나, 새로운 Key를 생성합니다.


  1. API Key를 이용하는 방법은 메인홈페이지 메뉴의 API 탭을 누른뒤, 얻고자 하는 날씨정보(예를 들어 Current weather data)의 API doc을 참고하세요.

  2. 먼저 인터넷 브라우저를 통해 날씨정보가 어떻게 출력되는지 알아보기위하여 아래 홈페이지 주소에 접속해봅니다. 이때 주소의 끝부분에 있는 YOUR_API_KEY 대신 본인의 API Key를 입력합니다.


https://api.openweathermap.org/data/2.5/weather?q=Seoul,KR&units=metric&APPID=1bf3d5e1bd2e5934aadd86..........

https://api.openweathermap.org/data/2.5/weather?q=London,GB&units=metric&APPID=1bf3d5e1bd2e5934aadd86..........

https://api.openweathermap.org/data/2.5/weather?q=Shanghai,CN&units=metric&APPID=1bf3d5e1bd2e5934aadd86..........

브라우저에 출력되는 내용#

{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"base":"stations","main":{"temp":277.16,"pressure":1007,"humidity":86,"temp_min":274.82,"temp_max":279.26},"visibility":8000,"wind":{"speed":5.1,"deg":90},"clouds":{"all":90},"dt":1574300635,"sys":{"type":1,"id":1414,"country":"GB","sunrise":1574321288,"sunset":1574352288},"timezone":0,"id":2643743,"name":"London","cod":200}

그밖의 도시 및 국가명은 Maps> Weather maps를 클릭하여 표시되는 지도를 통해 확인할 수 있습니다.



ESP32에서 사용하는 경우#

wifi 접속 설정#

const char* ssid     = "your ssid";                  // 연결할 SSID
const char* password = "your password";              // 연결할 SSID의 비밀번호
  • wifi에 접속하기 위한 ssid와 password를 설정

OpenWeatherMap.org 접속 설정#

const String endpoint = "https://api.openweathermap.org";
const String ver = "/data/2.5/weather?q=";
const String city = "Shanghai,CN";                 // City,Country (띄어쓰기 금지)
const String appid = "&units=metric&APPID=";       // Units: metric
const String key = "1bf3d5e1bd2e5934aadd86..........";    // API Key
  • 날씨 데이터를 받아올 도시, 국가를 지정 (Shanghai,CN) (※주의: Shanghai,CN 사이에 띄어쓰기를 하면 안됨)
  • key 변수에 본의 API Key를 입력

sketch#

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

const char* ssid     = "your ssid";                  // 연결할 SSID
const char* password = "your password";              // 연결할 SSID의 비밀번호

// OpenWeatherMap.org: Shanghai,CN
const String endpoint = "https://api.openweathermap.org";
const String ver = "/data/2.5/weather?q=";
const String city = "Shanghai,CN";                 // City,Country (띄어쓰기 금지)
const String appid = "&units=metric&APPID=";       // Units: metric
const String key = "1bf3d5e1bd2e5934aadd86..........";    // API Key

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

    // 와이파이 연결
    while (WiFi.status() != WL_CONNECTED) {
      delay(1000);
      Serial.println("Connecting to WiFi..");
    }

    Serial.println("Connected to the WiFi network");
}

// 연결 여부 로그 출력
void loop() {
  if ((WiFi.status() == WL_CONNECTED)) {    // Check the current connection status
 
    HTTPClient http;
 
    http.begin(endpoint + ver + city + appid + key); // Specify the URL
    int httpCode = http.GET();                       // Make the request
 
    if (httpCode > 0) {                              // Check for the returning code
 
        String json = http.getString();         // get JSON format data
        Serial.println(httpCode);
        Serial.println(json);
    }
    else {
      Serial.println("Error on HTTP request");
    }
 
    http.end();                                     // Free the resources
  }
 
  delay(30000); 
}

출력 DATA#

출력 데이터는 JSON(JavaScript Object Notation)을 기반으로 합니다. JSON은 프로그래밍 언어에 관계없이 데이터를 생성하고 읽을 수 있도록 만들어졌으며, 이를 통해 상호간에 보다 쉽게 데이터를 교환이 가능한 텍스트 기반의 데이터 교환 방식입니다. OpenWeatherMap에서도 이 방식을 사용하여 날씨 데이터를 생성하여 출력하고 있으며, 출력 데이터의 형태는 아래와 같습니다.

스케치 맨 아래라인의 delay 명령으로 인해 10초마다 1번씩 data를 출력합니다. 단, OpenWeatherMap free service의 update time이 2시간 이하로 되어 있으므로, 자료 갱신이 매 출력시마다 진행되지는 않습니다.


Firefox 등의 몇몇 인터넷 브라우저에서는 JSON 데이터를 보다 직관적으로 이해할 수 있도록 계층별로 나누어 출력해주기도 합니다.



JSON Parsing#

위와 같이 복잡한 형태로 출력되는 날씨 데이터 중에서 필요한 날씨 정보를 추출하기 위하여 JSON (JavaScript Object Notation) 파싱 과정을 거쳐야 하는데요. 이를 위해 아두이노 IDE에서 Json 파싱을 위한 라이브러리를 설치하여야 합니다.


라이브러리 설치#

ArduinoJson (by Benoit Blanchon) 라이브러리 (version 6)를 설치합니다.

스케치> 라이브러리 포함하기> 라이브러리 관리



Memory pool 크기 계산#

  1. JSON 파싱에 사용할 배열의 크기를 계산하여 메모리를 확보합니다. 이를 위해 샘플로 사용할 JSON데이터가 필요하므로, 먼저 웹브라우저에서 OpenWeatherMap에 접속한 뒤,
https://api.openweathermap.org/data/2.5/weather?q=Shanghai,CN&units=metric&APPID=1bf3d5e1bd2e5934aadd86..........

  1. 출력되는 JSON 데이터를 드래그하여 복사합니다.
{"coord":{"lon":-0.13,"lat":51.51},"weather":[{"id":804,"main":"Clouds","description":"overcast clouds","icon":"04n"}],"base":"stations","main":{"temp":277.16,"pressure":1007,"humidity":86,"temp_min":274.82,"temp_max":279.26},"visibility":8000,"wind":{"speed":5.1,"deg":90},"clouds":{"all":90},"dt":1574300635,"sys":{"type":1,"id":1414,"country":"GB","sunrise":1574321288,"sunset":1574352288},"timezone":0,"id":2643743,"name":"London","cod":200}

  1. https://arduinojson.org/assistant 에 접속한 뒤, Input란에 있는 내용을 모두 지우고 복사한 JSON데이터를 붙여넣기하면, Memory pool size가 자동으로 계산됩니다.


  1. Memory pool size의 Expression부분을 드래그하여 복사하고, Additional bytes for strings dubplucation 부분의 숫자를 이용하여 스케치에서 다음의 형식으로 변수를 생성합니다.
const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + 2*JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(13) + 240;

실제로는 아래 Parsing Program에 이미 변수가 설정되어 있으므로, 이 과정은 수행하지 않아도 됩니다.


Parsing program#

  1. Memory pool size가 출력된 화면의 아래쪽에 Parsing program도 함께 출력됩니다.


  1. 우선 Parsing Program 전체를 복사한 뒤, 스케치의 void loop() 부분에 붙여넣기 합니다.

  1. 밑줄친 부분의 json 변수가 나타나 있는 라인을 모두 지우고
const char* json = "{\"coord\":{\"lon\":121.49,\"lat\":31.23},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"base\":\"stations\",\"main\":{\"temp\":293.02,\"pressure\":1027,\"humidity\":55,\"temp_min\":289.82,\"temp_max\":298.71},\"visibility\":10000,\"wind\":{\"speed\":3,\"deg\":60},\"clouds\":{\"all\":94},\"dt\":1574303919,\"sys\":{\"type\":1,\"id\":9659,\"country\":\"CN\",\"sunrise\":1574288762,\"sunset\":1574326426},\"timezone\":28800,\"id\":1796236,\"name\":\"Shanghai\",\"cod\":200}";

  1. OpenWeatherMap에서 실시간으로 받는 String 형식의 데이터 변수로 바꿔줍니다.
String json = http.getString();

  1. Timezone 반영을 위하여, 붙여넣기 한 Parsing program의 아래 부분에 아래 내용을 추가합니다.
dt = dt + timezone;                     // for GMT+8 -> +28800, for GMT+9 -> +32400
sys_sunrise = sys_sunrise + timezone;
sys_sunset = sys_sunset + timezone;

  1. UNIX Timestamp로 표기되는 시간을 일반적인 날짜, 시간으로 표기되도록 변환해줍니다. 이를 위해서 timelib.h 파일을 이용해야하는데, 이 파일은 Time 라이브러리(by Michael Margolis)에 포함되어 있지요. 그러므로 라이브러리 매니저를 통해 Time라이브러리를 찾아 설치해줍니다.

year(dt), month(dt), day(dt), hour(dt), minute(dt), second(dt), weekday(dt));

​ 위의 스케치를 통해서 UTC를 YYYY.MM.DD HH:MM:SS(요일) 형태의 날짜를 변환하며, printf문을 통해 출력할 수 있습니다.


Data 출력에 사용한 variables#

JSON 형식의 데이터를 파싱할때 사용한 변수들입니다.

내용형식변수unit
UNIX Time(UTC)longdt
Weather IDintweather_0_id
Weather Mainconst char*weather_0_main
Weather Descriptionconst char*weather_0_description
Weather Icon IDconst char*weather_0_icon
Temperaturefloatmain_temp
Temperature Max.floatmain_temp_max
Temperature Min.floatmain_temp_min
Pressureintmain_pressurehPa
Humidityintmain_humidity%
Visibilityintvisibilitym
Wind Speedintwind_speedm/s
Wind Degreeintwind_degº
Cloudsintclouds_all
Sunriselongsys_sunrise
Sunsetlongsys_sunset
City IDlongid
City nameconst char*name
Countryconst char*sys_country
Longitudefloatcoord_lonº
Latitudefloatcoord_latº
GMTinttimezone (※timezone/3600)hour
intsys_type
intsys_id
Baseconst char*base
CODintcod


sketch: 전체#

위의 과정을 통해 만들진 부분 스케치를 병합하여 JSON 파싱을 위한 전체 스케치를 구성해봅니다.

ArduinoJson 라이브러리의 경우 version 5와 6의 사용 문법이 조금 다릅니다. 현재 Arduino IDE에서 라이브러리 추가과정을 통해 다운로드 받을 수 있는 최신 라이브러리 버전이 ArduinoJson 6이므로, 이에 맞게 작성하여야합니다. (기존의 ArduinoJson 5에 맞게 작성된 스케치는 컴파일이 되지 않으므로, Migrating from version 5 to 6 문서를 참고하여 스케치를 변경해야 합니다.)

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TimeLib.h>
 
const char* ssid     = "your ssid";                  // 연결할 SSID
const char* password = "your password";              // 연결할 SSID의 비밀번호
 
const String endpoint = "https://api.openweathermap.org";
const String ver = "/data/2.5/weather?q=";
const String city = "Shanghai,CN";                 // City,Country (띄어쓰기 금지)
const String appid = "&units=metric&APPID=";       // Units: metric
const String key = "1bf3d5e1bd2e5934aadd86..........";    // API Key

unsigned long offset_days = 3;     // 3 days for convert unix timestamp to datetime

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 the WiFi network");
}
 
void loop() {
  if ((WiFi.status() == WL_CONNECTED)) {      // Check the current connection status
 
    HTTPClient http;
 
    http.begin(endpoint + ver + city + appid + key); // Specify the URL
    int httpCode = http.GET();                       // Make the request
 
    if (httpCode > 0) {                              // Check for the returning code
      // 데이터 파싱
      const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + 2*JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(13) + 270;
      DynamicJsonDocument doc(capacity);

      String json = http.getString();                // get JSON format data

      deserializeJson(doc, json);

      float coord_lon = doc["coord"]["lon"]; // 121.49
      float coord_lat = doc["coord"]["lat"]; // 31.23

      JsonObject weather_0 = doc["weather"][0];
      int weather_0_id = weather_0["id"]; // 804
      const char* weather_0_main = weather_0["main"]; // "Clouds"
      const char* weather_0_description = weather_0["description"]; // "overcast clouds"
      const char* weather_0_icon = weather_0["icon"]; // "04d"

      /*
      JsonObject weather_1 = weather[1];
      int weather_1_id = weather_1["id"]; // 701
      const char* weather_1_main = weather_1["main"]; // "Mist"
      const char* weather_1_description = weather_1["description"]; // "mist"
      const char* weather_1_icon = weather_1["icon"]; // "50n"

      JsonObject weather_2 = weather[2];
      int weather_2_id = weather_2["id"]; // 741
      const char* weather_2_main = weather_2["main"]; // "Fog"
      const char* weather_2_description = weather_2["description"]; // "fog"
      const char* weather_2_icon = weather_2["icon"]; // "50n"
      */

      const char* base = doc["base"]; // "stations"

      JsonObject main = doc["main"];
      float main_temp = main["temp"]; // 293.02
      int main_pressure = main["pressure"]; // 1027
      int main_humidity = main["humidity"]; // 55
      float main_temp_min = main["temp_min"]; // 289.82
      float main_temp_max = main["temp_max"]; // 298.71

      int visibility = doc["visibility"]; // 10000

      int wind_speed = doc["wind"]["speed"]; // 3
      int wind_deg = doc["wind"]["deg"]; // 60

      int clouds_all = doc["clouds"]["all"]; // 94
      
      long dt = doc["dt"]; // 1574303919

      JsonObject sys = doc["sys"];
      int sys_type = sys["type"]; // 1
      int sys_id = sys["id"]; // 9659
      //float sys_message = sys["message"]; // Internal parameter (0.0226)
      const char* sys_country = sys["country"]; // "CN"
      long sys_sunrise = sys["sunrise"]; // 1574288762
      long sys_sunset = sys["sunset"]; // 1574326426

      int timezone = doc["timezone"]; // 28800
      long id = doc["id"]; // 1796236
      const char* name = doc["name"]; // "Shanghai"
      int cod = doc["cod"]; // 200

      dt = dt + timezone;                // for GMT+8 -> +28800, for GMT+9 -> +32400
      sys_sunrise = sys_sunrise + timezone;
      sys_sunset = sys_sunset + timezone;

      //int main_sea_level = main["sea_level"]; // Atmospheric pressure hPa on the sea level
      //int main_grnd_level = main["grnd_level"]; // Atmospheric pressure hPa on the ground level     
      //int rain_1h = doc["rain"]["1h"]; // Rain volume for the last 1 hour, mm
      //int rain_3h = doc["rain"]["3h"]; // Rain volume for the last 3 hour, mm
      //int snow_1h = doc["snow"]["1h"]; // Snow volume for the last 1 hour, mm
      //int snow_3h = doc["snow"]["3h"]; // Snow volume for the last 3 hour, mm

      //데이터 출력
      Serial.print("UNIX Time of Weather: "); Serial.println(dt);
      Serial.printf("Time of Weather: %4d-%02d-%02d %02d:%02d:%02d(%1d)\n", year(dt), month(dt), day(dt), hour(dt), minute(dt), second(dt), weekday(dt));
      Serial.print("Weather ID: "); Serial.println(weather_0_id);
      Serial.print("Weather Main: "); Serial.println(weather_0_main);
      Serial.print("Weather Description: "); Serial.println(weather_0_description);
      Serial.print("Weather Icon: "); Serial.println(weather_0_icon);
      Serial.print("Temperature(℃): "); Serial.println(main_temp);
      Serial.print("Temperature Max(℃): "); Serial.println(main_temp_max);
      Serial.print("Temperature Min(℃): "); Serial.println(main_temp_min);
      Serial.print("Pressure(hPa): "); Serial.println(main_pressure);
      Serial.print("Humidity(%): "); Serial.println(main_humidity);
      Serial.print("Visibility(m): "); Serial.println(visibility);
      Serial.print("Wind Speed(m/s): "); Serial.println(wind_speed);
      Serial.print("Wind Degree(º): "); Serial.println(wind_deg);
      Serial.print("Clouds: "); Serial.println(clouds_all);
      Serial.printf("Sunrise: %02d:%02d:%02d\n", hour(sys_sunrise), minute(sys_sunrise), second(sys_sunrise));
      Serial.printf("Sunset:  %02d:%02d:%02d\n", hour(sys_sunset), minute(sys_sunset), second(sys_sunset));
      Serial.print("City/Country: "); Serial.print(name); Serial.print("/"); Serial.println(sys_country);
      Serial.print("longitude/latidude: "); Serial.print(coord_lon); Serial.print("/"); Serial.println(coord_lat);
      Serial.print("Timezone: GMT+"); Serial.println(timezone/3600);

      /*
      Serial.print("Sea Level(hPa): "); Serial.println(main_sea_level);
      Serial.print("Ground Level(hPa): "); Serial.println(main_grnd_level);
      Serial.print("Rain 1h(mm): "); Serial.println(rain_1h);
      Serial.print("Rain 3h(mm): "); Serial.println(rain_3h);
      Serial.print("Snow 1h(mm): "); Serial.println(snow_1h);
      Serial.print("Snow 3h(mm): "); Serial.println(snow_3h);
      */
    }
 
    else {
      Serial.println("Error on HTTP request");
    }
 
    http.end();
  }
 
  delay(30000);
}

출력 Data#



Weather Condition Code#

Group 2xx: Thunderstorm#

IDMainDescriptionIcon
200Thunderstormthunderstorm with light rainimg 11d
201Thunderstormthunderstorm with rainimg 11d
202Thunderstormthunderstorm with heavy rainimg 11d
210Thunderstormlight thunderstormimg 11d
211Thunderstormthunderstormimg 11d
212Thunderstormheavy thunderstormimg 11d
221Thunderstormragged thunderstormimg 11d
230Thunderstormthunderstorm with light drizzleimg 11d
231Thunderstormthunderstorm with drizzleimg 11d
232Thunderstormthunderstorm with heavy drizzleimg 11d

Group 3xx: Drizzle#

IDMainDescriptionIcon
300Drizzlelight intensity drizzleimg 09d
301Drizzledrizzleimg 09d
302Drizzleheavy intensity drizzleimg 09d
310Drizzlelight intensity drizzle rainimg 09d
311Drizzledrizzle rainimg 09d
312Drizzleheavy intensity drizzle rainimg 09d
313Drizzleshower rain and drizzleimg 09d
314Drizzleheavy shower rain and drizzleimg 09d
321Drizzleshower drizzleimg 09d

Group 5xx: Rain#

IDMainDescriptionIcon
500Rainlight rainimg 10d
501Rainmoderate rainimg 10d
502Rainheavy intensity rainimg 10d
503Rainvery heavy rainimg 10d
504Rainextreme rainimg 10d
511Rainfreezing rainimg 13d
520Rainlight intensity shower rainimg 09d
521Rainshower rainimg 09d
522Rainheavy intensity shower rainimg 09d
531Rainragged shower rainimg 09d

Group 6xx: Snow#

IDMainDescriptionIcon
600Snowlight snowimg 13d
601SnowSnowimg 13d
602SnowHeavy snowimg 13d
611SnowSleetimg 13d
612SnowLight shower sleetimg 13d
613SnowShower sleetimg 13d
615SnowLight rain and snowimg 13d
616SnowRain and snowimg 13d
620SnowLight shower snowimg 13d
621SnowShower snowimg 13d
622SnowHeavy shower snowimg 13d

Group 7xx: Atmosphere#

IDMainDescriptionIcon
701Mistmistimg 50d
711SmokeSmokeimg 50d
721HazeHazeimg 50d
731Dustsand/ dust whirlsimg 50d
741Fogfogimg 50d
751Sandsandimg 50d
761Dustdustimg 50d
762Ashvolcanic ashimg 50d
771Squallsquallsimg 50d
781Tornadotornadoimg 50d

Group 800: Clear#

IDMainDescriptionIcon
800Clearclear skyimg 01d img 01n

Group 80x: Clouds#

IDMainDescriptionIcon
801Cloudsfew clouds: 11-25%img 02d img 02n
802Cloudsscattered clouds: 25-50%img 03d img 03n
803Cloudsbroken clouds: 51-84%img 04d img 04n
804Cloudsovercast clouds: 85-100%img 04d img 04n

ICON 출력방법#

Weather ID 801에 해당하는 아이콘 code가 02d이므로 URL을 다음과 같이 지정하면

http://openweathermap.org/img/wn/10d.png

ICON크기를 크게 출력하고 싶은 경우에는 아이콘 code에 @2x를 덧붙입니다.

http://openweathermap.org/img/wn/10d@2x.png



1602 LCD에 날씨 정보 출력하기#

여러가지 날씨 정보 중에서 현재 온도를 1602 LCD(I2C)에 출력해보겠습니다.


라이브러리 설치하기#

스케치> 라이브러리 포함하기> 라이브러리 관리

  • LiquidCrystal I2C (by Frank de Brabander) 검색하여 설치

schematic#


sketch#

#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <TimeLib.h>

const char* ssid     = "your ssid";                  // 연결할 SSID
const char* password = "your password";              // 연결할 SSID의 비밀번호
 
const String endpoint = "https://api.openweathermap.org";
const String ver = "/data/2.5/weather?q=";
const String city = "Shanghai,CN";                 // City,Country (띄어쓰기 금지)
const String appid = "&units=metric&APPID=";       // Units: metric
const String key = "1bf3d5e1bd2e5934aadd86..........";    // API Key

unsigned long offset_days = 3;                            // 3 days for convert unix timestamp to datetime
float main_temp;

// set the LCD
#include <LiquidCrystal_I2C.h>

int lcdColumns = 16;
int lcdRows = 2;

// set LCD address, number of columns and rows
// if you don't know your display address, run an I2C scanner sketch
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);  

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 the WiFi network");

  // initialize LCD
  lcd.init();
  // turn on LCD backlight                      
  lcd.backlight();
}
 
void loop() {
  if ((WiFi.status() == WL_CONNECTED)) {            // Check the current connection status
 
    HTTPClient http;
 
    http.begin(endpoint + ver + city + appid + key); // Specify the URL
    int httpCode = http.GET();                       // Make the request
 
    if (httpCode > 0) {                              // Check for the returning code
      // 데이터 파싱
      const size_t capacity = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + 2*JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(13) + 270;
      DynamicJsonDocument doc(capacity);

      String json = http.getString();                // get JSON format data

      deserializeJson(doc, json);

      float coord_lon = doc["coord"]["lon"]; // 121.49
      float coord_lat = doc["coord"]["lat"]; // 31.23

      JsonObject weather_0 = doc["weather"][0];
      int weather_0_id = weather_0["id"]; // 804
      const char* weather_0_main = weather_0["main"]; // "Clouds"
      const char* weather_0_description = weather_0["description"]; // "overcast clouds"
      const char* weather_0_icon = weather_0["icon"]; // "04d"

      /*
      JsonObject weather_1 = weather[1];
      int weather_1_id = weather_1["id"]; // 701
      const char* weather_1_main = weather_1["main"]; // "Mist"
      const char* weather_1_description = weather_1["description"]; // "mist"
      const char* weather_1_icon = weather_1["icon"]; // "50n"

      JsonObject weather_2 = weather[2];
      int weather_2_id = weather_2["id"]; // 741
      const char* weather_2_main = weather_2["main"]; // "Fog"
      const char* weather_2_description = weather_2["description"]; // "fog"
      const char* weather_2_icon = weather_2["icon"]; // "50n"
      */

      const char* base = doc["base"]; // "stations"

      JsonObject main = doc["main"];
      float main_temp = main["temp"]; // 293.02
      int main_pressure = main["pressure"]; // 1027
      int main_humidity = main["humidity"]; // 55
      float main_temp_min = main["temp_min"]; // 289.82
      float main_temp_max = main["temp_max"]; // 298.71

      int visibility = doc["visibility"]; // 10000

      int wind_speed = doc["wind"]["speed"]; // 3
      int wind_deg = doc["wind"]["deg"]; // 60

      int clouds_all = doc["clouds"]["all"]; // 94
      
      long dt = doc["dt"]; // 1574303919

      JsonObject sys = doc["sys"];
      int sys_type = sys["type"]; // 1
      int sys_id = sys["id"]; // 9659
      //float sys_message = sys["message"]; // Internal parameter (0.0226)
      const char* sys_country = sys["country"]; // "CN"
      long sys_sunrise = sys["sunrise"]; // 1574288762
      long sys_sunset = sys["sunset"]; // 1574326426

      int timezone = doc["timezone"]; // 28800
      long id = doc["id"]; // 1796236
      const char* name = doc["name"]; // "Shanghai"
      int cod = doc["cod"]; // 200

      dt = dt + timezone;                     // for GMT+8 -> +28800, for GMT+9 -> +32400
      sys_sunrise = sys_sunrise + timezone;
      sys_sunset = sys_sunset + timezone;

      //int main_sea_level = main["sea_level"]; // Atmospheric pressure hPa on the sea level
      //int main_grnd_level = main["grnd_level"]; // Atmospheric pressure hPa on the ground level     
      //int rain_1h = doc["rain"]["1h"]; // Rain volume for the last 1 hour, mm
      //int rain_3h = doc["rain"]["3h"]; // Rain volume for the last 3 hour, mm
      //int snow_1h = doc["snow"]["1h"]; // Snow volume for the last 1 hour, mm
      //int snow_3h = doc["snow"]["3h"]; // Snow volume for the last 3 hour, mm

      //데이터 출력
      Serial.print("UNIX Time of Weather: "); Serial.println(dt);
      Serial.printf("Time of Weather: %4d-%02d-%02d %02d:%02d:%02d(%1d)\n", year(dt), month(dt), day(dt), hour(dt), minute(dt), second(dt), weekday(dt));
      Serial.print("Weather ID: "); Serial.println(weather_0_id);
      Serial.print("Weather Main: "); Serial.println(weather_0_main);
      Serial.print("Weather Description: "); Serial.println(weather_0_description);
      Serial.print("Weather Icon: "); Serial.println(weather_0_icon);
      Serial.print("Temperature(℃): "); Serial.println(main_temp);
      Serial.print("Temperature Max(℃): "); Serial.println(main_temp_max);
      Serial.print("Temperature Min(℃): "); Serial.println(main_temp_min);
      Serial.print("Pressure(hPa): "); Serial.println(main_pressure);
      Serial.print("Humidity(%): "); Serial.println(main_humidity);
      Serial.print("Visibility(m): "); Serial.println(visibility);
      Serial.print("Wind Speed(m/s): "); Serial.println(wind_speed);
      Serial.print("Wind Degree(º): "); Serial.println(wind_deg);
      Serial.print("Clouds: "); Serial.println(clouds_all);
      Serial.printf("Sunrise: %02d:%02d:%02d\n", hour(sys_sunrise), minute(sys_sunrise), second(sys_sunrise));
      Serial.printf("Sunset:  %02d:%02d:%02d\n", hour(sys_sunset), minute(sys_sunset), second(sys_sunset));
      Serial.print("City/Country: "); Serial.print(name); Serial.print("/"); Serial.println(sys_country);
      Serial.print("longitude/latidude: "); Serial.print(coord_lon); Serial.print("/"); Serial.println(coord_lat);
      Serial.print("Timezone: GMT+"); Serial.println(timezone/3600);

      /*
      Serial.print("Sea Level(hPa): "); Serial.println(main_sea_level);
      Serial.print("Ground Level(hPa): "); Serial.println(main_grnd_level);
      Serial.print("Rain 1h(mm): "); Serial.println(rain_1h);
      Serial.print("Rain 3h(mm): "); Serial.println(rain_3h);
      Serial.print("Snow 1h(mm): "); Serial.println(snow_1h);
      Serial.print("Snow 3h(mm): "); Serial.println(snow_3h);
      */
      lcd.setCursor(0, 0);
      lcd.print("Temperature : ");
      lcd.setCursor(0, 1);
      lcd.print(main_temp);
    }
 
    else {
      Serial.println("Error on HTTP request");
    }
 
    http.end();
  }

  delay(30000);
  
  lcd.setCursor(0, 1);
  lcd.print("                ");
}

Arduino IDE에서 컴파일시 *““경고: 라이브러리 LiquidCrystal_I2C가 avr 아키텍처에서 실행되며 esp32아키텍처에서 실행되는 현재보드에서는 호환되지 않을 수 있습니다.”"*라는 메세지가 나타나지만, LCD 출력에는 문제가 없습니다.



공공데이터 활용하기#

위의 방법을 응용하면 국가별, 관련 업체별로 제공되는 여러가지 공공데이터를 활용할 수 있습니다.

그밖에 활용가능한 공공데이터가 어떤 것이 있는지, 살펴보세요~