前回、Wioアプリを使って行おうとした、ベランダの温度と湿度をWebページに表示する記事のリベンジをします。
Wioアプリではバッテリーが持たないことがわかっているので、今回は素直にプログラミングで行きます。
温度・湿度センサーのDHT11はIFTTT経由でTwitterに送る記事で使ったので問題ないとして、残る問題はWebページに表示するための仲介となるサーバーをどうするかです。「なるべく手間をかけないで目的を達成する」をコンセプトにしているので、AWSとかではなくデータを中継してくれるようなサービスがないか調べてみました。
そして、今回利用することにしたのがMilkcocoaです。MQTTをベースにしているそうなんですが、Arduino SDKやJavaScript APIでラッピングされているせいかMQTTの知識は要求されません。また、個人で利用するには十分な無料プランが用意されています。
ベランダに設置したセンサー
底に空気穴を開けたおかず容器にWIO NODE、Grove温度・湿度センサー(DHT11)、リチウムポリマー電池を入れて、磁石を付けた蓋でピタッとエアコンの屋外機吊り下げ枠にくっつけました。
実際の温度と湿度の表示
上の表示はMilkcocoaのJavaScript APIを使って実際のデータを表示しています。PCでご覧の方はサイドバーに同じ表示を見ることができます。
Milkcocoaの準備
まずはMilkcocoaに登録します。登録に必要な情報はEmailアドレスとパスワードのみです。
登録が終わってログインするとダッシュボード画面になります。
「新しいアプリを作る」でアプリを作ります。アプリ名はダッシュボード上の識別名でしかないのであまり気にする必要はありません。
作ったアプリ名をクリックしてアプリを設定します。
セキュリティを無視すると設定に必要な個所はメニューの「設定」です。
許可Originに表示したいサイトのURLを登録します。図では「はてなブログの管理サイト」と「ぼくのブログサイト」を登録しています。
- Milkcocoa ESP8266 SDK (Milkcocoaのサイト)
- DHT11のライブラリ(ぼくの以前の記事)
- NTPのライブラリ(ぼくの以前の記事)
Milkcocoaのページでは「ESP8266に直接プログラムを書き込む場合」の手順を行ってください。GithubからSDKをZIPでダウンロードしてライブラリマネージャーに追加します。MacやLinuxRaspberry Pi場合は追加後にヘッダーファイルの修正が必要でした。
修正するファイル
修正内容 31行目
修正前:#include "include/aJson/aJson.h"
修正後:#include "include/aJson/aJSON.h"
DHT11とNTPのライブラリ追加はぼくの以前の記事を見てくださいね。
スケッチのポイント (スケッチのダウンロード)
Milkcocoaの設定
#define MILKCOCOA_APP_ID "作成したapp_idを記入"
#define MILKCOCOA_DATASTORE "esp8266/dht11"
DATASTOREはその名の通りデータを保存する場所です。事前に保存場所を作成しておく必要はなく、データを保存するときに作成されます。
Milkcocoaへのデータ保存
WiFiClient client; // WiFiを使う場合
Milkcocoa milkcocoa = Milkcocoa(&client, MQTT_SERVER, MILKCOCOA_SERVERPORT, MILKCOCOA_APP_ID, MQTT_CLIENTID);
milkcocoa.loop(); // Milkcocoaに接続
DataElement elem = DataElement(); // データ送信用のオブジェクト作成
elem.setValue("temperature", (int)round(t)); // 送信する温度データをセット
elem.setValue("humidity", (int)round(h)); // 送信する湿度データをセット
milkcocoa.push(MILKCOCOA_DATASTORE, &elem); // Milkcocoaにデータを保存
データの保存はこの一連の記述で行えます。データはデータ名とデータの値のセットで保存します。
保存したデータはダッシュボードのデータストアで確認することができます。
DHT11のデータ取得
delay(2000); // データ取得前に2秒待つ
float t = dht.readTemperature(); // 温度を取得
float h = dht.readHumidity(); // 湿度を取得
if (isnan(t) || isnan(h)) {
return; // データ取得に失敗したらloop()からやり直す
}
DHT11は独自のシングルバスで温度と湿度のデータを送るため、タイミングが結構シビアです。難しいタイミングを合わせる作業はライブラリ任せですが、データ取得に失敗するケースが多々あることから、データ取得に失敗した時のリトライを行う必要があります。
Deep Sleepの利用
センサーで値を取得してMilkcocoaに送るとき以外の殆どの時間は、バッテリー節約のために非常に消費電力の少ないDeep Sleep状態にしています。
ESP.deepSleep()の第1引数はマイクロ秒で指定しますが、ESP8266は時計を内蔵していなく実際にはカウンターを利用しているだけのため、60分ぐらいの時間を指定すると数分のずれが生じます。
そのため、loop()の終了だけでなく開始にもDeep Sleepに入る処理を加えて意図したタイミングに処理が実行されるようにしています。
loop()の開始
int min = SLEEP_INTERVAL - minute() % SLEEP_INTERVAL; // 実行タイミングでないときはスリープ
if (min != SLEEP_INTERVAL) {
ESP.deepSleep((min * 60 - second() + 10) * 1000 * 1000, WAKE_RF_DEFAULT); // マイクロ秒で指定
}
loop()の終了
min = SLEEP_INTERVAL - minute() % SLEEP_INTERVAL; // スリープする端数分数を計算
ESP.deepSleep((min * 60 - second() + 10) * 1000 * 1000, WAKE_RF_DEFAULT); // マイクロ秒で指定
Webページへの表示
Webページに表示するにはMilkcocoaのJavaScript APIを使用します。
<div>ベランダの温度と湿度</div>
<div id="datetime">時刻取得中...</div> <!-- 置き換え用の場所 -->
<div id="temperature">温度取得中...</div> <!-- 置き換え用の場所 -->
<div id="humidity">湿度取得中...</div> <!-- 置き換え用の場所 -->
<script src="https://cdn.mlkcca.com/v0.6.0/milkcocoa.js"></script>
<script type="text/javascript">// <![CDATA[
var milkcocoa = new MilkCocoa('app_idを記入.mlkcca.com'); // 「app_idを記入」を置き換えます
var ds = milkcocoa.dataStore('esp8266/dht11'); // データ取得先のデータストア
ds.stream().size(1).sort('desc').next(function(err, data){ // 1番新しいデータを1件取得
document.getElementById("datetime").innerHTML = "時刻:" + data[0].value.datetime + " ";
document.getElementById("temperature").innerHTML = "温度:" + data[0].value.temperature + "℃";
document.getElementById("humidity").innerHTML = "湿度:" + data[0].value.humidity + "%";
});
// ]]></script>
時刻、温度、湿度を表示する場所をHTMLに用意しておき、データ取得後に取得したデータで置き換えるようにしています。
リベンジ完了!
フルスケッチをダウンロードできるようにしました。よろしければ使ってください。
2017/5/11追記:
アップロードしていたファイルがBOM付きになっていたため、Windows環境のArduinoで不可解なエラーが出る状態だったのを修正しました。
また、Windows環境のArduinoではTime.hではなくTimeLib.hをインクルードしないとエラーになってしまうので修正しました。