ESP8266とMilkcocoaを使ってビニールハウスの監視制御をやってみる

こちら[milkcocoaアドベントカレンダー](http://qiita.com/advent-calendar/2016/milkcocoa)の16日の記事です。
###導入
　IoTが完全にバズワードになってまいりました。で、手っ取り早くIoTのプロトタイプを製作する場合は、ESP8266が便利だよね。あと、サーバーはMilkcocoaを使うと手っ取り早くサーバーにデータを上げたり、リアルタイムの通知が出来たりしてほんとに便利。
　というわけで、この2つを組み合わせてわりとガチ仕様でどこまでのものができるのかやってみました。今回作成したのはビニールハウスの遠隔監視制御システムです。

###Milkcocoaについて
　MilkcocoaはMQTTプロトコルを使ったクライアントサービスです。
publisher,describer,subscriberなどのMQTTの概念を上手く隠ぺいして使いやすくしている印象ですね。MQTTを意識しなくてもプログラムは組めます。特にJavaScripからだと数行の追加で実装可能だし、クライアント側のArduino/ESP8266、AndroidのSDKも用意されているので、導入が非常に簡単です。
　同じようにmyThings+IDCFでもデータ送信とイベント処理が簡単にできるけど、こちらは少しMQTTを意識したプログラムが必要で、ちょっとばかりだけど敷居が高くなるかな。
　いずれにせよ、自前でMQTTのDescriberサーバーを立てるのはめんどくさいので、手っ取り早くプロトタイプを作ってデモのプレゼンをやる場合には重宝してます。
###構想（作りたいもの）
　最近の流れだとRaspberry-piを使って、カメラを繋いで動画とかも送ったりする場合が多いけど、個人的にはイマイチRaspberry-piを監視装置で使うのは不安だし、SDカードはすぐ壊れそうだし、Linuxで起動とシャットダウンに時間がかかるし...。
　ということで、今回製作するシステムでは、映像に関してはネットワークカメラで撮るということで割り切ります。
今回使用したのは、PLANEXのCS-QR10。
　そしてメインのデータのモニタと遠隔制御の部分を、ESP8266＋３GWiFi無線ルータで行うことにしました。（ネットワークカメラもこの３G無線ルータ経由でクラウドに上げます）
　温湿度を送る実装例はよくWebに上がっているので、今回は遠隔で換気扇とか、ビニール天窓の巻き上げ制御とか、潅水機の制御をすることを意識してみたいと思います。
###準備したもの
ESP8266ボード(スイッチサイエンス　ESP-WROOM-02)
温湿度センサ (HDC1000)

リレー制御BOX（モータ制御）DFRobot社製
Arduino UNO（互換機)
3G無線WiFiルータ(WM340+Freetel SIM)
![IMG_1128.JPG](https://qiita-image-store.s3.amazonaws.com/0/33661/33e770c3-e194-cec3-b9da-257e6bd583e3.jpeg)

###ブロック図


![fig1.png](https://qiita-image-store.s3.amazonaws.com/0/33661/d03bb856-3f07-2680-0e44-f3b6633db1fe.png)
###Milkcocoaの設定
　milkcocoaには、2つのデータストアを定義します。
　・esp8266-->温湿度データ（userid,temp,humi）
　・remote-->遠隔操作トリガ (mode,status)
###ESP8266のプログラム
　ESP8266のプログラムはMilkcocoaのSDKをベースに必要な分を追加しました。
　ESP8266で温湿度センサ（HDC1000）から10分おきに取得した、温度と湿度をデータストア"esp8266"にpush()で送信します。
 

    #define MILKCOCOA_DATASTORE2  "remote"
    DataElement elem = DataElement();
    elem.setValue("userid", USER_ID);
    elem.setValue("temp", temp);
    elem.setValue("humi", humi);
  
    milkcocoa->push(MILKCOCOA_DATASTORE, &elem);
![web3.png](https://qiita-image-store.s3.amazonaws.com/0/33661/ac0eca91-3b25-d22e-2b05-0828adc1a0bb.png)

###遠隔制御
　Webアプリ側で遠隔制御ボタンをクリックしたら、milkcocoaのデータストア"remote"にデータをsend()で送ります（書き込み内容　リレー番号(mode)、制御内容(status)）。ESP8266はこれをonpush()コールバック関数で受け取ります。
onpush()が呼ばれれば、IDが自分のIDの場合はリレーBOXに制御コマンド"r(リレー番号),(制御内容)\r"を送ります。

コールバック定義（setup()内）

```C++:milkcocoa_temp_humi_control.ino
 #define MILKCOCOA_DATASTORE2  "remote"
 Serial.println( milkcocoa->on(MILKCOCOA_DATASTORE2, "push", onpush) );
```
onpush()関数

```C++:milkcocoa_temp_humi_control.ino
void onpush(DataElement *elem) {
  //データ更新通知
  char* id = elem->getString("id");
  Serial.println("onpush");
  Serial.print(id);
  Serial.print(",");
  Serial.print(elem->getString("mode"));
  Serial.print(",");
  Serial.println(elem->getString("status"));
  if(atoi(id) == USER_ID){
    Serial.println("sendRelayBox");
    mySerial.print("r");
    mySerial.print(elem->getString("mode"));
    mySerial.print(",");
    mySerial.println(elem->getString("status"));
  }
};
```
![web2.png](https://qiita-image-store.s3.amazonaws.com/0/33661/f4b8bbf6-6e43-20d5-0be5-1809ccda7107.png)
　ビニールハウスでは、電動モーターを三相200V交流とか（100Vもあり）で動かしていて、スイッチを入切するのはパワーリレーです。今回はこのパワーリレーの制御信号（単相200V）をArduinoに接続したリレーで接続することを想定しています。
![IMG_1113.JPG](https://qiita-image-store.s3.amazonaws.com/0/33661/1442afaa-8867-d7e2-117d-8b25b1d01a4b.jpeg)

####はまったところ
最初、ESP8266のプログラムでデータストア"remote"へのsendでon()イベントが思ったタイミングで来ないので悩みました。なぜか、温湿度のデータをデータストア"esp8266"に書き込んだ時に、一緒にonpush()のコールバックが発生しました。
原因はサンプルプログラムでは温湿度を定期的に上げるためにloop()の最後にdelay()でタイミングを調整していたので、milkcocoa->loop();がこのタイミングでしか呼ばれていなかった事でした。
on()のコールバックはmilkcocoa->loop()を呼ばないと発生しないようになっているみたいです。（中身のソースを見ていなかったので気づかなかったorz)

```C++:milkcocoa_temp_humi_control.ino
void loop() {
  milkcocoa->loop();

  if(LPcount++ > 60*10){　// 10分ごとに送信
    LPcount = 0;
    //温度＆湿度の取得
    //milkcocoaへの送信
  }
  delay(1000);
};
```
このように、milkcocoa->loop()を頻繁に呼べば、すぐにonpush()が呼ばれます。ヨカッタ、ヨカッタ。
###Webアプリ
　データの表示と遠隔制御の命令は今回は、別サーバーを立ててPHP+JavaScriptで組みました。
　Milikcocoaのデータストアのデータは、JavaScriptでMilkcocoaraライブラリのstream()で取得できます。これをグラフライブラリに流し込めば、グラフはOK。今回はChat.jsを使いました。

　遠隔制御はボタンをクリックした時に、Milkcocoaraライブラリのsend()で書き込みます。

	$(":button[name='milkcocoa']").click(function(){

		var milkcocoa = MilkCocoa.connectWithApiKey('uniiud3hdn1.mlkcca.com', 'NLCHDEIJOPFEFOMI', 'TEVPPWRmVmfPkgMNjUkMKEMVfCWKZRYMJaGKiiHU');
		var ds = milkcocoa.dataStore('remote');
		ds.push({id: '1',mode: '1',status:'1'}); //リレー1　ON
	});

###できたもの
ビニールハウス（模型）の換気扇に見立てたファンを遠隔で動かしてます。
![web1.png](https://qiita-image-store.s3.amazonaws.com/0/33661/559b7bc0-0c4a-0e45-6a00-a0a9e7dd1f4e.png)

![IMG_1127.JPG](https://qiita-image-store.s3.amazonaws.com/0/33661/abc709bc-0a38-a788-ad9b-e8009cca449d.jpeg)

カメラで遠隔からの動作チェックもバッチリOK。
あとは日照センサー とかCO2センサーも付ければ、本格的になるよね。まあ実際に運用するためには、コードのエラー処理とか、セキュリティ対策とか、ケース（結露対策）とか、Web画面のUIグレードアップとか必要なので、まだまだ先は長い...。