ESP8266とRaspberryPiで温度監視botを作る

この記事は[Raspberry Pi Advent Calendar 2017](https://adventar.org/calendars/2075) 20日目の記事です。

## はじめに
この記事では僕が去年の夏休みぐらいから始めた、お家の温度監視botをちゃんと作り直したことについて、まとめ的なことを書こうと思います。
目標としては定期的に部屋の温度や湿度をつぶやいたり、集計してグラフをつぶやいたりできたらいいなと思っています。
最初はESP8266だけで[StewGate U](http://stewgate-u.appspot.com/)というサービスを使ってbotを作っていました。
しかしESP8266だけじゃグラフ出せないし、データを常に保存するならSDカード必要だしな…ラズパイ使うか！という感じでラズパイをサーバーにbotを作りました。

## 用意するもの
- どこのご家庭にも転がっている**ラズパイ**
 - Python、PHP、Apach導入済みで、IPアドレスが固定されていたほうがいいかも
- 安価なWiFIモジュールでArduinoとして使える**ESP8266**
- 秋月電子で販売している**[温湿度センサーモジュールSHT31](http://akizukidenshi.com/catalog/g/gK-12125/)**
 - 以前はHDC1000を使っていましたが経年劣化（？）で湿度が高めに表示されていたので変更

## 全体の構成
![raspitoexp.png](https://qiita-image-store.s3.amazonaws.com/0/147601/05d83281-eae5-c4de-00db-0a80f089f56e.png)
ESP8266は温湿度センサーから値を取得してラズパイへ送信
ラズパイはESP8266から受け取った値を成型してcsvファイルへ保存し、定期的にTwitterへつぶやく
という役割になっています。

## ESP8266とラズパイの通信
ESP8266はWiFiに接続することができ、HTTP通信のライブラリもあります。
そこでラズパイにPHPで入力フォームを作り、ESP8266でGETリクエストを送信することで値を受け渡しています。
![form.png](https://qiita-image-store.s3.amazonaws.com/0/147601/137197ab-6509-0d4e-7801-aeee912c8576.png)

こんな感じのよく見る入力フォームをラズパイ上で立ち上げます。
そして作った入力フォームに合わせてESP8266からGETリクエストを送ってやります。
送られてきたデータは20121225.csvというふうに日付ごとのファイルに保存しています。

SHT31の温度取得には[Adafruitのライブラリ](https://github.com/adafruit/Adafruit_SHT31)を使用しました。
ESP8266でのHTTP GETの使い方は以下を参考にしました。
[ESP8266でHTTP GETするならWiFiClientじゃなくてHTTPClientのほうが良い](http://relativelayout.hatenablog.com/entry/2016/12/21/234344)

```arduino
String url = "http://myipadress/php/gettest.php";
void loop() {
  //SHT31
  float temp = sht31.readTemperature();
  float hum = sht31.readHumidity();
  //クエリストリングの追加
  url += "&temp=";
  url += String(temp);
  url += "&hum=";
  url += String(hum);
  char buf[100];
  int len = url.length();
  url.toCharArray(buf,len);
  getESP(buf);
}
String getESP(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;
}
```
全部書くと長くなるので重要なところだけ
GETリクエストはHTTPClientがやってくれるので、我々はセンサの値をクエリストリングにしてしまえば簡単にGETリクエストで値を送信することができます。

## データを処理してつぶやく
ラズパイは受け取った値をcsvファイルに一度保存し、保存されたデータをもとにPythonでTwitterにつぶやいています。
なぜそのようになっているかというと、ESP8266はタイマーで5分おきにデータを送信してくるのに対し、Twitterにつぶやくのは20分毎にしたかったからです。また、グラフを作成するのにPythonを使いたかったというのも理由の一つです。

TwitterAPIを使うためにtwitterモジュールを、csvファイルの読み込みにはpandasを使いました。

```Python
# -*- coding: utf-8 -*-

import numpy as np
import pandas as pd
from datetime import datetime
from twitter import *
 
CONSUMER_KEY        = 'YOUR_CONSUMER_KEY'
CONSUMER_SECRET_KEY = 'YOUR_CONSUMER_SECRET_KEY'
ACCESS_TOKEN        = 'YOUR_ACCESS_TOKEN'
ACCESS_TOKEN_SECRET = 'YOUR_ACCESS_TOKEN_SECRET'

PATH = 'hogehoge'

t = Twitter(auth = OAuth(ACCESS_TOKEN, ACCESS_TOKEN_SECRET, CONSUMER_KEY,CONSUMER_SECRET_KEY))

now = datetime.now()
filename = '{0}{1}{2}'.format(now.year, now.month, now.day)

data = pd.read_csv(PATH + filename + '.csv')
sum = len(data) # 行数を読む

latest_temp = data.loc[sum-1, 'Temp']
latest_hum = data.loc[sum-1, 'Hum']
mes = 'Temperature : {0}℃\nHumidity : {1}%'.format(latest_temp, latest_hum)

t.statuses.update(status = mes)

```
csvファイルが日付ごとに保存されているためdatetimeを使ってファイル名を生成し、pandasで読み込んでいます。csvファイルの一番下の行が最新の値になるのでlocを使って読み込んでいます。

## 完成！
Pythonでデータを読み込みTwitterへつぶやく部分が書けたらcronで決まった時間に自動的にPythonスクリプトを実行するように設定すれば、botの完成です。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="und" dir="ltr">Temperature : 15.35℃<br>Humidity : 52.0%</p>&mdash; Miθra (@mithraism_bot) <a href="https://twitter.com/mithraism_bot/status/944593504340078595?ref_src=twsrc%5Etfw">2017年12月23日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


## 終わりに
PHPとかPythonとかあんまり触ったことなくてやってみたいけど、ただ勉強するのもモチベーション上がらないな～ということでbotを作ってみましたが思ったより大変でした。
始めたの去年の夏休みなのに投稿が今年の冬でしかも、期限に間に合わせられなくて申し訳ない。
まだ必要最低限の部分しかできてなくて、ESP8266止まったらどうするの？とか、csvじゃなくてデータベース使えばいいじゃん、とかグラフはまだ？？とかありますが今後の課題にしていきたいと思います。