esp32 OpenWeatherMap에서 실시간 날씨 정보 받기
OpenWeatherMap.org
OpenWeatherMap은 세계 각 지역의 현재 날씨, 예보, 과거 날씨 데이터를 제공하는 사이트입니다. (몇가지 제약이 있긴 하지만) 회원가입을 통해서 API Key를 생성하고 이를 통해 무료로 실시간 날씨 정보를 얻을 수 있습니다.
Free Current weather and forecasts collection
- 60 Calls per minute (no more than)
- Current weather API
- 5 days/3 hour forecast API
- Weather maps 1.0
- UV index
- Weather alerts
- Availability 95%
- Weather API data update < 2 hours
- Weather maps data update < 3 hours
- API lifetime support : Current version
- Historical weather collection은 모두 Starter 이상(유료)
Current weather collections API Key 생성
Sign Up을 클릭하여 회원가입을 하고,
Sign In을 클릭하여 로그인한 뒤, API Keys를 누릅니다.
Default로 지정되어 있는 Key를 복사하거나, 새로운 Key를 생성합니다.
API Key를 이용하는 방법은 메인홈페이지 메뉴의 API 탭을 누른뒤, 얻고자 하는 날씨정보(예를 들어 Current weather data)의 API doc을 참고하세요.
먼저 인터넷 브라우저를 통해 날씨정보가 어떻게 출력되는지 알아보기위하여 아래 홈페이지 주소에 접속해봅니다. 이때 주소의 끝부분에 있는 YOUR_API_KEY 대신 본인의 API Key를 입력합니다.
1 | https://api.openweathermap.org/data/2.5/weather?q=Seoul,KR&units=metric&APPID=1bf3d5e1bd2e5934aadd86.......... |
1 | https://api.openweathermap.org/data/2.5/weather?q=London,GB&units=metric&APPID=1bf3d5e1bd2e5934aadd86.......... |
1 | https://api.openweathermap.org/data/2.5/weather?q=Shanghai,CN&units=metric&APPID=1bf3d5e1bd2e5934aadd86.......... |
브라우저에 출력되는 내용
1 | {"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 접속 설정
1 | const char* ssid = "your ssid"; // 연결할 SSID |
- wifi에 접속하기 위한 ssid와 password를 설정
OpenWeatherMap.org 접속 설정
1 | const String endpoint = "https://api.openweathermap.org"; |
- 날씨 데이터를 받아올 도시, 국가를 지정 (Shanghai,CN) (※주의: Shanghai,CN 사이에 띄어쓰기를 하면 안됨)
- key 변수에 본의 API Key를 입력
sketch
1 |
|
출력 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 크기 계산
- JSON 파싱에 사용할 배열의 크기를 계산하여 메모리를 확보합니다. 이를 위해 샘플로 사용할 JSON데이터가 필요하므로, 먼저 웹브라우저에서 OpenWeatherMap에 접속한 뒤,
1 | https://api.openweathermap.org/data/2.5/weather?q=Shanghai,CN&units=metric&APPID=1bf3d5e1bd2e5934aadd86.......... |
- 출력되는 JSON 데이터를 드래그하여 복사합니다.
1 | {"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} |
- https://arduinojson.org/assistant 에 접속한 뒤, Input란에 있는 내용을 모두 지우고 복사한 JSON데이터를 붙여넣기하면, Memory pool size가 자동으로 계산됩니다.
- Memory pool size의 Expression부분을 드래그하여 복사하고, Additional bytes for strings dubplucation 부분의 숫자를 이용하여 스케치에서 다음의 형식으로 변수를 생성합니다.
1 | 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
- Memory pool size가 출력된 화면의 아래쪽에 Parsing program도 함께 출력됩니다.
- 우선 Parsing Program 전체를 복사한 뒤, 스케치의 void loop() 부분에 붙여넣기 합니다.
- 밑줄친 부분의 json 변수가 나타나 있는 라인을 모두 지우고
1 | 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}"; |
- OpenWeatherMap에서 실시간으로 받는 String 형식의 데이터 변수로 바꿔줍니다.
1 | String json = http.getString(); |
- Timezone 반영을 위하여, 붙여넣기 한 Parsing program의 아래 부분에 아래 내용을 추가합니다.
1 | dt = dt + timezone; // for GMT+8 -> +28800, for GMT+9 -> +32400 |
UNIX Timestamp로 표기되는 시간을 일반적인 날짜, 시간으로 표기되도록 변환해줍니다. 이를 위해서 timelib.h 파일을 이용해야하는데, 이 파일은 Time 라이브러리(by Michael Margolis)에 포함되어 있지요. 그러므로 라이브러리 매니저를 통해 Time라이브러리를 찾아 설치해줍니다.
1 | 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) | long | dt | |
Weather ID | int | weather_0_id | |
Weather Main | const char* | weather_0_main | |
Weather Description | const char* | weather_0_description | |
Weather Icon ID | const char* | weather_0_icon | |
Temperature | float | main_temp | ℃ |
Temperature Max. | float | main_temp_max | ℃ |
Temperature Min. | float | main_temp_min | ℃ |
Pressure | int | main_pressure | hPa |
Humidity | int | main_humidity | % |
Visibility | int | visibility | m |
Wind Speed | int | wind_speed | m/s |
Wind Degree | int | wind_deg | º |
Clouds | int | clouds_all | |
Sunrise | long | sys_sunrise | |
Sunset | long | sys_sunset | |
City ID | long | id | |
City name | const char* | name | |
Country | const char* | sys_country | |
Longitude | float | coord_lon | º |
Latitude | float | coord_lat | º |
GMT | int | timezone (※timezone/3600) | hour |
int | sys_type | ||
int | sys_id | ||
Base | const char* | base | |
COD | int | cod |
sketch: 전체
위의 과정을 통해 만들진 부분 스케치를 병합하여 JSON 파싱을 위한 전체 스케치를 구성해봅니다.
ArduinoJson 라이브러리의 경우 version 5와 6의 사용 문법이 조금 다릅니다. 현재 Arduino IDE에서 라이브러리 추가과정을 통해 다운로드 받을 수 있는 최신 라이브러리 버전이 ArduinoJson 6이므로, 이에 맞게 작성하여야합니다. (기존의 ArduinoJson 5에 맞게 작성된 스케치는 컴파일이 되지 않으므로, Migrating from version 5 to 6 문서를 참고하여 스케치를 변경해야 합니다.)
1 |
|
출력 Data
Weather Condition Code
Group 2xx: Thunderstorm
ID | Main | Description | Icon |
---|---|---|---|
200 | Thunderstorm | thunderstorm with light rain | 11d |
201 | Thunderstorm | thunderstorm with rain | 11d |
202 | Thunderstorm | thunderstorm with heavy rain | 11d |
210 | Thunderstorm | light thunderstorm | 11d |
211 | Thunderstorm | thunderstorm | 11d |
212 | Thunderstorm | heavy thunderstorm | 11d |
221 | Thunderstorm | ragged thunderstorm | 11d |
230 | Thunderstorm | thunderstorm with light drizzle | 11d |
231 | Thunderstorm | thunderstorm with drizzle | 11d |
232 | Thunderstorm | thunderstorm with heavy drizzle | 11d |
Group 3xx: Drizzle
ID | Main | Description | Icon |
---|---|---|---|
300 | Drizzle | light intensity drizzle | 09d |
301 | Drizzle | drizzle | 09d |
302 | Drizzle | heavy intensity drizzle | 09d |
310 | Drizzle | light intensity drizzle rain | 09d |
311 | Drizzle | drizzle rain | 09d |
312 | Drizzle | heavy intensity drizzle rain | 09d |
313 | Drizzle | shower rain and drizzle | 09d |
314 | Drizzle | heavy shower rain and drizzle | 09d |
321 | Drizzle | shower drizzle | 09d |
Group 5xx: Rain
ID | Main | Description | Icon |
---|---|---|---|
500 | Rain | light rain | 10d |
501 | Rain | moderate rain | 10d |
502 | Rain | heavy intensity rain | 10d |
503 | Rain | very heavy rain | 10d |
504 | Rain | extreme rain | 10d |
511 | Rain | freezing rain | 13d |
520 | Rain | light intensity shower rain | 09d |
521 | Rain | shower rain | 09d |
522 | Rain | heavy intensity shower rain | 09d |
531 | Rain | ragged shower rain | 09d |
Group 6xx: Snow
ID | Main | Description | Icon |
---|---|---|---|
600 | Snow | light snow | 13d |
601 | Snow | Snow | 13d |
602 | Snow | Heavy snow | 13d |
611 | Snow | Sleet | 13d |
612 | Snow | Light shower sleet | 13d |
613 | Snow | Shower sleet | 13d |
615 | Snow | Light rain and snow | 13d |
616 | Snow | Rain and snow | 13d |
620 | Snow | Light shower snow | 13d |
621 | Snow | Shower snow | 13d |
622 | Snow | Heavy shower snow | 13d |
Group 7xx: Atmosphere
ID | Main | Description | Icon |
---|---|---|---|
701 | Mist | mist | 50d |
711 | Smoke | Smoke | 50d |
721 | Haze | Haze | 50d |
731 | Dust | sand/ dust whirls | 50d |
741 | Fog | fog | 50d |
751 | Sand | sand | 50d |
761 | Dust | dust | 50d |
762 | Ash | volcanic ash | 50d |
771 | Squall | squalls | 50d |
781 | Tornado | tornado | 50d |
Group 800: Clear
ID | Main | Description | Icon |
---|---|---|---|
800 | Clear | clear sky | 01d 01n |
Group 80x: Clouds
ID | Main | Description | Icon |
---|---|---|---|
801 | Clouds | few clouds: 11-25% | 02d 02n |
802 | Clouds | scattered clouds: 25-50% | 03d 03n |
803 | Clouds | broken clouds: 51-84% | 04d 04n |
804 | Clouds | overcast clouds: 85-100% | 04d 04n |
ICON 출력방법
Weather ID 801에 해당하는 아이콘 code가 02d이므로 URL을 다음과 같이 지정하면
1 | http://openweathermap.org/img/wn/10d.png |
ICON크기를 크게 출력하고 싶은 경우에는 아이콘 code에 @2x를 덧붙입니다.
1 | http://openweathermap.org/img/wn/10d@2x.png |
1602 LCD에 날씨 정보 출력하기
여러가지 날씨 정보 중에서 현재 온도를 1602 LCD(I2C)에 출력해보겠습니다.
라이브러리 설치하기
스케치> 라이브러리 포함하기> 라이브러리 관리
- LiquidCrystal I2C (by Frank de Brabander) 검색하여 설치
schematic
sketch
1 |
|
Arduino IDE에서 컴파일시 *””경고: 라이브러리 LiquidCrystal_I2C가 avr 아키텍처에서 실행되며 esp32아키텍처에서 실행되는 현재보드에서는 호환되지 않을 수 있습니다.””*라는 메세지가 나타나지만, LCD 출력에는 문제가 없습니다.
공공데이터 활용하기
위의 방법을 응용하면 국가별, 관련 업체별로 제공되는 여러가지 공공데이터를 활용할 수 있습니다.
- 대기질 관련 데이터 : https://aqicn.org/api/
- (한국)공공데이터포털 : https://www.data.go.kr/
- (미국)공공데이터포털 : https://www.data.gov/
그밖에 활용가능한 공공데이터가 어떤 것이 있는지, 살펴보세요~