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

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

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">esp8266に温度、気圧、湿度センサー（BME280）を接続してIFTTTに送信するモジュール。給電はUSBもしくは右上の端子台から電池で<a href="https://twitter.com/hashtag/ESP8266?src=hash&amp;ref_src=twsrc%5Etfw">#ESP8266</a> <a href="https://twitter.com/hashtag/BME280?src=hash&amp;ref_src=twsrc%5Etfw">#BME280</a> <a href="https://twitter.com/hashtag/IFTTT?src=hash&amp;ref_src=twsrc%5Etfw">#IFTTT</a> <a href="https://t.co/1uOxQMDeKW">pic.twitter.com/1uOxQMDeKW</a></p>&mdash; triwave33 (@triwave33) <a href="https://twitter.com/triwave33/status/1016976747370143744?ref_src=twsrc%5Etfw">2018年7月11日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# はじめに

　近年、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モードの使い方](https://qiita.com/azusa9/items/65a5c3772c41631b5ca1)
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](https://macsbug.wordpress.com/2015/10/23/esp8266-%E3%81%A8-i2c/)
BME280のI2C接続での使い方は
[AmbientでIoTをはじめよう](http://pages.switch-science.com/letsiot/airquality/)


# WiFiの設定
- SSID
- パスワード
を把握

# IFTTTの設定

- event名
- WebHookアプリのsecret keyを設定

IFTTT側の設定は特に書かないので各自やりたいことをやってください。設定方法は例えば
[ESP8266とBME280とIFTTTでIoTボタンをつくった](http://ytkyk.info/blog/2017/01/01/esp8266%E3%81%A8bme280%E3%81%A8ifttt%E3%81%A7iot%E3%83%9C%E3%82%BF%E3%83%B3%E3%82%92%E3%81%A4%E3%81%8F%E3%81%A3%E3%81%9F/)
に詳しく書かれています。同じような事をしていらっしゃるかたが既にいました。



# コードの解説
## Wifi, IFTTTの設定

```C
#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の確認に関しては[こちら](https://dotstud.io/blog/nefry-ifttt-push-line/)などが参考になると思います。eventはIFTTT側の設定と同じにしておきます。

ちなみにこのコードではポート80を使ってhttp通信をおこなっています。つまり、パスワードが平文で流れるので、セキュリティ的に非常によろしくないです。ゲスト用のアクセスポイントを使うなどしてください。（それでもwebhook側のsecret keyはわかってしまいますが）。https通信については確認中です。（180711）

## データの取得とIFTTTへのデータ転送


```C

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モードの使い方](https://qiita.com/azusa9/items/65a5c3772c41631b5ca1)
を参考にしてみてください。

deepSleepモードに入ったあとは、設定時間後にもう一度プログラムが再起動されます。起動から接続、データ送信完了まで大体数秒でしょうか。ですので、10秒とか20秒間隔でデータを送信したい場合はdeepsleepモードは有効ではありません。（もっともそんな使い方する人はいないと思いますが。。）

## 最後に
簡単にですが、ESP8266を用いてIFTTTにセンサ情報を投げる方法を解説しました。
私の使い方としてはwebhookを受け取った後にgoogle spreadsheetに書き込んでいます。

実はこのあとが本当にやりたいことで、google homeと連携して「今の温度は？」と聞いたら答えてくれるようにできたらと思っています。また進展しましたら記事にしたいと思います。