WiFiにつながる安いESP32のボードで、クラウドに接続して、今の気象データを表示するIoTをしてみました。
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
ライブラリとして、
- 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
から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は以下のようになっていました。
{"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を使い、以下のようにパースしています。
#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分ごとにフェッチして、表示するようにしてみました。
簡単に、まとめたプログラムコードが以下です。
# 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();
}