Arduino
ifttt
IoT
ESP8266
BME280

ESP8266を使って温度センサ情報をIFTTTに投げる

やったこと

Boschの温度・気圧・湿度センサ(BME280)をWifiボードESP8266に接続。
IFTTTと連携してデータをスプレッドシートに格納

はじめに

 近年、IoTという言葉で表されるように、センサ機器をインターネットに接続することで、センサ情報を手軽に、リアルタイムに、集約的に扱うことが可能になってきました。

 ホビーユースでこのブームに火をつけた要因の一つはなんといってもESP8266だと思います。それ以前だと、センサ情報を処理してインターネットに接続することを考えると、ArduinoとWifiボードを用いるか、もしくはラズパイを用いることを考えました。どちらも数千円のコストがかかります。

 ESP8266ならば、数百円、評価用ボードを用いても2000円くらいで済んでしまいます。

 最近では後継機種であるESP32も出てきており、こちらはWiFiに加えてBluetoothも扱えるようですが、ESP8266もまだまだ現役ですし、先行機種であるがゆえに情報の蓄積も多いと思います。

 今回は記事としては目新しさはないですが、ESP8266と温度(+湿度+圧力)センサであるBME280を接続し、WiFiアクセスによりIFTTTに情報を投げてみます。

ソースコードはgithubに公開しています。

設定

ESP8266

Arduino用の開発環境を用います。
また、センサ情報は5分に一回IFTTT側に送ればいいと考えから、deepsleepモードを使っています。
deepsleepに関する記事はこちらが参考になりました。
ESP8266の真骨頂Deep-Sleepモードの使い方
IFTTTサーバへの接続状態を判断するために4番ピンにLEDを接続し、接続試行中にLEDが点滅するようにしています。

BME280

BME280は通信にSPIとI2Cが使えますが、今回はI2Cを選択します。
I2Cアドレスを0x76として使うために、BME280のSDO端子をグラウンドに落としておきます。

コードは基本的に、スイッチサイエンスさんが公開しているBME280用のサンプルコード をベースに、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と連携して「今の温度は?」と聞いたら答えてくれるようにできたらと思っています。また進展しましたら記事にしたいと思います。