WEMOS の ESP32 で クラウドの気象データを表示

WiFiにつながる安いESP32のボードで、クラウドに接続して、今の気象データを表示するIoTをしてみました。

![IMG_20181008_072437.jpg](https://qiita-image-store.s3.amazonaws.com/0/139524/ed566340-e61b-b422-89ff-deac3df516f1.jpeg)


# ESP32 WEMOS Lolin32

今回 WEMOS LOLIN32というESP32ボードを使いました。

(2020/02/06) WEMOS LOLIN32ボードの紹介は別ページに分離しました。
「WEMOS LOLIN32 の調査」
https://qiita.com/nanbuwks/items/111ee8cd69f3390d866f

まずは、動作確認まで終わらせておきます。

# OLEDをつけます。

手元にSPIのOLEDがあったので、つなげてみました。

接続は
GND --  GND
VDD --  5V
SCK --  14
SDA -- 13
RES -- 4
DC -- 21
CS -- 16

![IMG_20181001_022515.jpg](https://qiita-image-store.s3.amazonaws.com/0/139524/633ae581-3ff5-1605-417d-81f30276941d.jpeg)

ライブラリとして、

- Adafruit_GFX.h
- Adafruit_SSD1306.h

を使っています。

ライブラリをインストールすると出てくる、SSD1306_128x64_SPI を使い、

```
// using software SPI
#define OLED_MOSI  13
#define OLED_DC    21
#define OLED_CS    16
#define OLED_CLK   14
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);
```

だけ書き換えています。

# Wi-Fiにつなぐ

「スケッチの例」の「WiFi」「WiFiClientBasic」で動きました。
 ssid と passwd 、を書き換えるだけで Wi-Fiに接続しました。（接続後の!client.connect(host, port))）はうまく動かないみたい)

# お天気情報を取得する
openweathermap.org


![image](https://qiita-image-store.s3.amazonaws.com/0/139524/1e70f46f-52fc-d850-dcee-1fc262d13367.png)

からTokyoの天気を取得しました。

サインアップし、APIキーを取得します。

APIを使って、

```

http://api.openweathermap.org/data/2.5/weather?APPID=eac・・・(APIキー)・・・2e2&id=1850147&units=metric
```

id=1850147 は東京のコードです。都市の指定は、Tokyoとかの指定でもいいですがコードで指定するほうが無難ぽいです。
http://bulk.openweathermap.org/sample/ の city.list.json.gz に都市のリストがあります。

units=metric とすると温度が摂氏で得られます。

取得したJSONは以下のようになっていました。

```json

{"coord":{"lon":139.69,"lat":35.69} 
  ,"weather":[
   {"id":701,"main":"Mist","description":"mist","icon":"50n"}   
  ,{"id":721,"main":"Haze","description":"haze","icon":"50n"}
  ,{"id":520,"main":"Rain","description":"light intensity shower rain","icon":"09n"}
  ],"base":"stations"
  ,"main":{"temp":25.08,"pressure":980,"humidity":83,"temp_min":24,"temp_max":26},"visibility":3500     
  ,"clouds":{"all":75},"dt":1538331240
  ,"wind":{"speed":9.8,"deg":210,"gust":24.7}
  ,"sys":{"type":1,"id":7615,"message":0.0068,"country":"JP","sunrise":1538253334,"sunset":1538295968}
  ,"id":1850147,"name":"Tokyo","cod":200   
  }";
```
ArduinoJsonを使い、以下のようにパースしています。

```cpp
  #include <ArduinoJson.h>
   ・・・
  Serial.println(json);  # "json"にデータが入っている
  JsonObject& root = jsonBuffer.parseObject(json);
  if (!root.success()) {
    Serial.println("parseObject() failed");
  }
  const char* weather = root["weather"][0]["main"];
  const char* description = root["weather"][0]["description"];
  long pressure = root["main"]["pressure"];
  double temp = root["main"]["temp"];
```
["weather"][0]だけ取得していますが、先ほど示したように複数の値がやってくることがあります。とりあえずは一番最初のものだけを取得するようにしています。

# お天気情報を表示する

1分ごとにフェッチして、表示するようにしてみました。


![IMG_20181008_072501.jpg](https://qiita-image-store.s3.amazonaws.com/0/139524/40b4402e-36a7-7fe8-9107-5e670c8fc9b7.jpeg)

簡単に、まとめたプログラムコードが以下です。

```cpp

#include <ArduinoJson.h>
  
// 接続先のSSIDとパスワード
const char ssid[] = "hogehoge";
const char passwd[] = "hagehage";

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <HTTPClient.h>
#include <WiFi.h> // This liblaly cause error "min". Replace to "_min".

// using software SPI
#define OLED_MOSI  13
#define OLED_DC    21
#define OLED_CS    16
#define OLED_CLK   14
#define OLED_RESET 4
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

String accessHttpAPI(char host[]) {
  HTTPClient http;
  http.begin(host);
  int httpCode = http.GET();
  String result = "";
  if (httpCode < 0) {
    result = http.errorToString(httpCode);
  } else if (http.getSize() < 0) {
    result =  "size is invalid";
  } else {
    result = http.getString();
  }
  http.end();
  return result;
}

void setup()   {                
  Serial.begin(115200);
  WiFi.begin(ssid, passwd);
  Serial.print("WiFi connecting...");
    while(WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(100);
    }
    Serial.print(" connected. ");
    Serial.println(WiFi.localIP());
  display.begin(SSD1306_SWITCHCAPVCC);
  display.display();
  delay(2000);
  display.clearDisplay();
}

void loop() {
  StaticJsonBuffer<1500> jsonBuffer;
  String json = accessHttpAPI("http://api.openweathermap.org/data/2.5/weather?APPID=eac・・・(APIキー)・・・2e&id=1850147&units=metric");
  Serial.println(json);
  JsonObject& root = jsonBuffer.parseObject(json);
  if (!root.success()) {
    Serial.println("parseObject() failed");
  }
  const char* weather = root["weather"][0]["main"];
  const char* description = root["weather"][0]["description"];
  long pressure = root["main"]["pressure"];
  double temp = root["main"]["temp"];
  Serial.println(weather);
  Serial.println(description);
  Serial.println(pressure);
  Serial.println(temp);
   
  display.setTextSize(3);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println(weather);
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setTextSize(1);
  display.println(description);
  display.setTextColor(WHITE);
  display.setTextSize(2);
  display.print(pressure); display.println("hPa");
  display.print("temp:");display.print(temp);
  display.display();
  delay(60000);
  display.clearDisplay(); 
}
```