やったこと
Boschの温度・気圧・湿度センサ(BME280)をWifiボードESP8266に接続。
IFTTTと連携してデータをスプレッドシートに格納
esp8266に温度、気圧、湿度センサー(BME280)を接続してIFTTTに送信するモジュール。給電はUSBもしくは右上の端子台から電池で#ESP8266 #BME280 #IFTTT pic.twitter.com/1uOxQMDeKW
— triwave33 (@triwave33) 2018年7月11日
はじめに
近年、IoTという言葉で表されるように、センサ機器をインターネットに接続することで、センサ情報を手軽に、リアルタイムに、集約的に扱うことが可能になってきました。
ホビーユースでこのブームに火をつけた要因の一つはなんといってもESP8266だと思います。それ以前だと、センサ情報を処理してインターネットに接続することを考えると、ArduinoとWifiボードを用いるか、もしくはラズパイを用いることを考えました。どちらも数千円のコストがかかります。
ESP8266ならば、数百円、評価用ボードを用いても2000円くらいで済んでしまいます。
最近では後継機種であるESP32も出てきており、こちらはWiFiに加えてBluetoothも扱えるようですが、ESP8266もまだまだ現役ですし、先行機種であるがゆえに情報の蓄積も多いと思います。
今回は記事としては目新しさはないですが、ESP8266と温度(+湿度+圧力)センサであるBME280を接続し、WiFiアクセスによりIFTTTに情報を投げてみます。
ソースコードは[github] (https://github.com/triwave33/ESP8266_BME280_IFTTT)に公開しています。
設定
ESP8266
Arduino用の開発環境を用います。
また、センサ情報は5分に一回IFTTT側に送ればいいと考えから、deepsleepモードを使っています。
deepsleepに関する記事はこちらが参考になりました。
ESP8266の真骨頂Deep-Sleepモードの使い方
IFTTTサーバへの接続状態を判断するために4番ピンにLEDを接続し、接続試行中にLEDが点滅するようにしています。
BME280
BME280は通信にSPIとI2Cが使えますが、今回はI2Cを選択します。
I2Cアドレスを0x76として使うために、BME280のSDO端子をグラウンドに落としておきます。
コードは基本的に、スイッチサイエンスさんが公開しているBME280用の[サンプルコード] (https://github.com/SWITCHSCIENCE/BME280/blob/master/Arduino/BME280_I2C/BME280_I2C.ino) をベースに、ESP8266の機能や、IFTTTへの接続部分を追加していきます。
ESP8266とBME280の接続
留意点、ピン配置としては
- Wire.begin関数で12,13番ピンを指定
- ESP8266の12番ピンをBME280のSDI番に接続
- ESP8266の13番ピンをBME280のSCKに接続
ESP8266によるI2Cの使い方は
macsbug - ESP8266 と I2C
BME280のI2C接続での使い方は
AmbientでIoTをはじめよう
WiFiの設定
- SSID
- パスワード
を把握
IFTTTの設定
- event名
- WebHookアプリのsecret keyを設定
IFTTT側の設定は特に書かないので各自やりたいことをやってください。設定方法は例えば
ESP8266とBME280とIFTTTでIoTボタンをつくった
に詳しく書かれています。同じような事をしていらっしゃるかたが既にいました。
コードの解説
Wifi, IFTTTの設定
#include <ESP8266WiFi.h>
#include <Wire.h>
char* ssid = "put your SSID";
const char* password = "put your password"
const char* host = "maker.ifttt.com";
const char* event = "put your event";
const char* secretkey = "put your secretkey";
最初の2行はSSID名、パスワードを指定します。下の3行はIFTTT側の設定。通知したいイベント名を設定します。また、Webhooksを用いるので、 webhookのsecretkeyを入手しておき、指定しておきます。
secretkeyの確認に関してはこちらなどが参考になると思います。eventはIFTTT側の設定と同じにしておきます。
ちなみにこのコードではポート80を使ってhttp通信をおこなっています。つまり、パスワードが平文で流れるので、セキュリティ的に非常によろしくないです。ゲスト用のアクセスポイントを使うなどしてください。(それでもwebhook側のsecret keyはわかってしまいますが)。https通信については確認中です。(180711)
データの取得とIFTTTへのデータ転送
void loop()
{
double temp_act = 0.0, press_act = 0.0, hum_act = 0.0;
signed long int temp_cal;
unsigned long int press_cal, hum_cal;
readData();
temp_cal = calibration_T(temp_raw);
press_cal = calibration_P(pres_raw);
hum_cal = calibration_H(hum_raw);
temp_act = (double)temp_cal / 100.0;
press_act = (double)press_cal / 100.0;
hum_act = (double)hum_cal / 1024.0;
Serial.print("TEMP : ");
Serial.print(temp_act);
Serial.print(" DegC PRESS : ");
Serial.print(press_act);
Serial.print(" hPa HUM : ");
Serial.print(hum_act);
Serial.println(" %");
Serial.print("connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// We now create a URI for the request
String url = "/trigger/";
url += event;
url += "/with/key/";
url += secretkey;
url += "?value1=";
url += String(temp_act);
url += "&value2=";
url += String(press_act);
url += "&value3=";
url += String(hum_act);
Serial.print("Requesting URL: ");
Serial.println(url);
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
// Read all the lines of the reply from server and print them to Serial
while (client.available()) {
String line = client.readStringUntil('\r');
Serial.print(line);
}
}
readData関数でI2C通信を用いてBME280から温度、圧力、湿度データを取得します。
取得したデータはグローバル変数であるtemp_raw, pres_raw, hum_rawに格納され、
さらにcalibration_X (X=T, P, H)関数とスケール変換により実際の値に変換されます。
その後、WiFiClientクラスのインスタンス変数clientを作成し、host変数を用いてIFTTTに接続します。
先ほどの測定値を文字列に変換し、event, secretkeyと連結することでリクエストのためのURIを作成します。
最後にclientインスタンスのprintメソッドでサーバーにGETリクエストを送信します。
さらにサーバーからの返信があればシリアルコンソールに表示します。
Deep sleepモード
Serial.println("Deep sleep start!");
ESP.deepSleep(300 * 1000 * 1000, WAKE_RF_DEFAULT);
delay(1000);
loop関数の最後に上記のように記述してESP8266をディープスリープさせます。時間の単位はマイクロ秒なので、ここでは止めたい時間である300秒を1,000,000倍しています。
WAKE_RF_DEFAULTと最後のdelay関数に関しては
ESP8266の真骨頂Deep-Sleepモードの使い方
を参考にしてみてください。
deepSleepモードに入ったあとは、設定時間後にもう一度プログラムが再起動されます。起動から接続、データ送信完了まで大体数秒でしょうか。ですので、10秒とか20秒間隔でデータを送信したい場合はdeepsleepモードは有効ではありません。(もっともそんな使い方する人はいないと思いますが。。)
最後に
簡単にですが、ESP8266を用いてIFTTTにセンサ情報を投げる方法を解説しました。
私の使い方としてはwebhookを受け取った後にgoogle spreadsheetに書き込んでいます。
実はこのあとが本当にやりたいことで、google homeと連携して「今の温度は?」と聞いたら答えてくれるようにできたらと思っています。また進展しましたら記事にしたいと思います。