미세먼지 표시기를 날씨 정보도 표시하도록 업그레이드 해볼까 하여 날씨정보 관련 오픈API를 찾아 보았습니다.

그런데 오픈API로 받아오는 날씨 정보가 너무 양이 많아서 기존의 간단한 XML파싱으로는 해결이 불가능하여 아두이노용 JSON 라이브러리가 있는지 검색해 보았습니다.


간단히 나오더군요.

https://arduinojson.org/

https://github.com/bblanchon/ArduinoJson


위의 두 링크는 같은 JSON 라이브러리에 관한 곳이고 꽤나 많이 쓰이는 것으로 보입니다.

따라서 믿고 쓰기로 결정. 


스케치의 라이브러리 매니저에서 json으로 검색하여 해당 라이브러리를 설치.

예제 중에서 JsonParseExample이라는 예제를 살펴보았습니다.

그리고 날씨정보 오픈API 결과값을 파싱하기 위한 예제를 작성해서 테스트를 해보았습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <ArduinoJson.h>
 
// Enough space for: 멤버가 3개인 오브젝트 1개와 멤버가 1개인 오브젝트 2개가 있는 Json문서 크기
// + 1 object with 3 members 
// + 2 objects with 1 member 
//const int capacity = JSON_OBJECT_SIZE(3) + 2 * JSON_OBJECT_SIZE(1);
 
// JSON_OBJECT_SIZE(the number of members in the object) : JSON 오브젝트 크기 계산(인자는 멤버의 수)
// 멤버가 8개인 오브젝트 40개(날씨정보), 멤버가 2개인 오브젝트 1개(헤더), 멤버가 5개인 오브젝트 1개(response)
const int capacity = 40 * JSON_OBJECT_SIZE(8+ JSON_OBJECT_SIZE(2+ JSON_OBJECT_SIZE(5);
 
// Using a char[], as shown here, enables the "zero-copy" mode. This mode uses
// the minimal amount of memory because the JsonDocument stores pointers to
// the input buffer.
// If you use another type of input, ArduinoJson must copy the strings from
// the input to the JsonDocument, so you need to increase the capacity of the
// JsonDocument.
// json 내용을 char[]로 받아야 zero-copy 모드가 된다고 함. zero-copy 모드는 메모리를 적게 사용. 
// 다른 타입을 사용할 때는 ArduinoJson 라이브러리에서 문자열을 복사하므로 Json문서 크기를 더 크게 잡야줘야 함.
const char json[] = "{\"response\":{\"header\":{\"resultCode\":\"0000\",\"resultMsg\":\"OK\"},\"body\":{\"items\":{\"item\":[{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"POP\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":10,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"PTY\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":0,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"R06\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":0,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"REH\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":80,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"S06\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":0,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"SKY\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":2,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"T3H\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":10,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"TMN\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":9.0,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"UUU\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":-0.3,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"VEC\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":172,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"VVV\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":2.7,\"nx\":62,\"ny\":121},{\"baseDate\":20190418,\"baseTime\":\"0200\",\"category\":\"WSD\",\"fcstDate\":20190418,\"fcstTime\":\"0600\",\"fcstValue\":2.7,\"nx\":62,\"ny\":121}]},\"numOfRows\":12,\"pageNo\":1,\"totalCount\":155}}}";
 
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial) continue;
  delay(100);
  Serial.println("setup() START");
  Serial.println(capacity);
 
  // Json문서의 크기가 작으면 stack을 사용해서 실행 크기를 줄이고 성능을 높일 수 있다고 함.(StaticJsonDocument 사용)
  // Json문서의 크기가 크면 heap을 쓰는게 타당하다고.(DynamicJsonDocument 사용)
  //StaticJsonDocument<capacity> doc;
  DynamicJsonDocument doc(capacity);
 
  // Deserialize the JSON document : Json문서 분석
  DeserializationError error = deserializeJson(doc, json);
 
  // Test if parsing succeeds. : 파싱 에러 발생 시 출력
  if (error) {
    Serial.print(F("deserializeJson() failed: "));
    Serial.println(error.c_str());
    return;
  }
 
  // Fetch values.
  // Most of the time, you can rely on the implicit casts.
  // In other case, you can do doc["time"].as<long>();
  const char* resultCode = doc["response"]["header"]["resultCode"];
  int baseDate = doc["response"]["body"]["items"]["item"][0]["baseDate"];
  const char* category = doc["response"]["body"]["items"]["item"][1]["category"];
 
  // Print values.
  Serial.println(resultCode);
  Serial.println(baseDate);
  Serial.println(category);
}
 
void loop() {
  // put your main code here, to run repeatedly:
 
}
cs


원하는 정보를 잘 가져오네요. 이걸 이용해서 날씨 정보를 표시해 주면 되겠네요.

사용법이 간단하여 기존의 미세먼지 오픈API 정보도 JSON으로 바꿔주는 것도 생각해 봐야겠습니다.

다만 메모리 관리의 필요성이 커지지만 프로그램 자체도 간단하고 LOLIN D1 mini의 마이크로컨트롤러인 ESP-8266EX의 플래시 메모리 용량도 준수하니(4M bytes) 아직은 크게 신경쓸 필요는 없어보이네요.

아두이노 우노/나노였으면 고민 좀 해야할 수도 있었겠습니다만...(ATmega328 메모리 32KB, 위 예제의 json문서 크기는 5KB 초과, 실제론 더 커질지도?)


결론적으로 위의 ArduinoJson 라이브러리는 좋아보입니다.

그리고 저는 아두이노 나노를 주로 쓰는데 그것보다는 LOLIN(WeMos) D1 mini를 더 많이 쓰게 될 것 같네요.(성능 월등하고 가격은 더 싸니...)

물론 만드는 것에 맞는 제품을 쓰는게 가장 좋겠지요.

'아두이노' 카테고리의 다른 글

[모듈] Raindrops Sensor 모듈  (0) 2019.04.19
[모듈] 4-LEDs 모듈  (0) 2019.04.19
[모듈] RC522 RFID 모듈  (0) 2019.04.16
[모듈] L298N 모터 드라이버  (0) 2019.04.15
[모듈] 0.96인치 OLED 디스플레이  (0) 2019.04.11

+ Recent posts