#はじめに
予告通りにnetatmoを購入(ヒャッハー)。
(参考:IFTTTのMakerを使ってRaspberry Piから定期的に部屋の温度をトリガする)
ってことで、RaspberryPi+noede.jsの強力タッグでnetatmoもIFTTTのMakerチャンネルで定期的な測定値情報の取得をできるようにしましょう。
目標はnetatmoで測定したデータを例のごとくIFTTTのMakerチャンネルに送り込み連携できるようにすること。
ただし、どのようなjsonをIFTTTに送るかは固まっておらず現時点ではネストしたjsonを送るという手段をとっている。
(参考:IFTTTのMakerチャンネルにネストされたjsonは送れるか?)
この場合には各valueのネストされたjsonは同じくMakerチャンネルに繋いで分解しないと取り出せない。
これが非常に微妙なので、現在試行錯誤中。
(測定値を全部送ることができても連携できないと意味が無いので)
まぁ、文字列で全部送ってしまえばいいですがね。なんか・・・ねー。
#準備
node.jsでnetatmoを使うならNetatmo ウェザーステーションを買ってみたので Node.js でいじってみたの記事から入るのがよろしいだろう。
順当にgithubのkarbassi/netatmoに移動しつつ構造を理解する。
#netatmoにアプリ登録する
Netatmo Developersから開発者サイトに入り、「CREATE AN APP]からアプリ登録を行い、Client IDとClient Secretを取得する。必須項目はNameとDescriptionのみなので、最低限の入力でOK。
登録が完了すると以下の様な画面が表示されるはず。
#netatmoの測定値を取得するjs
本当は晒したくない(ゴミコードなので)のだが、あえて晒します。
netatmoのモジュールIDを引数として渡して、部屋のステーションと、外のモジュールの測定値を取得できるようにしている。
モジュールIDはDEVICELISTで取得可能。
今回利用したjsのnetatmoならapi.getDevicelist()で取得できる。
IFTTTのMakerを使ってRaspberry Piから定期的に部屋の温度をトリガするで利用したtemperコマンドと互換な出力をするように調整してある。
これはこの後にシェルスクリプトから複数にcurlでコマンドを投げるられるようにするため。
投げ先が決まっていて、投げるjsonの形式を変える必要がなければ、curlでjsonファイルをそのまま投げられる形式にしておくのが良いと思う。
日付フォーマットの変換には日付フォーマットなど 日付系処理を有り難くそのまま利用させてもらいました。感謝。
if (process.argv.length < 3) {
console.log('missing argument.');
return;
}
var netatmo = require('netatmo');
var api = new netatmo({
'client_id' : '<CLIENT_ID>',
'client_secret' : '<CLIENT_SECRET>',
'username' : '<MAIL>',
'password' : '<PASS>'
});
var formatDate = function (date, format) {
if (!format) format = 'YYYY-MM-DD hh:mm:ss.SSS';
format = format.replace(/YYYY/g, date.getFullYear());
format = format.replace(/MM/g, ('0' + (date.getMonth() + 1)).slice(-2));
format = format.replace(/DD/g, ('0' + date.getDate()).slice(-2));
format = format.replace(/hh/g, ('0' + date.getHours()).slice(-2));
format = format.replace(/mm/g, ('0' + date.getMinutes()).slice(-2));
format = format.replace(/ss/g, ('0' + date.getSeconds()).slice(-2));
if (format.match(/S/g)) {
var milliSeconds = ('00' + date.getMilliseconds()).slice(-3);
var length = format.match(/S/g).length;
for (var i = 0; i < length; i++) format = format.replace(/S/, milliSeconds.substring(i, i + 1));
}
return format;
};
var options = {
device_id: '<DEVICE_ID>',
module_id: process.argv[2],
scale: '30min',
date_end: 'last',
limit: 1,
type: ['Temperature', 'CO2', 'Humidity', 'Pressure', 'Noise'],
};
api.getMeasure(options, function(err, measure) {
measure.forEach(function(result){
var date = formatDate(new Date( result.beg_time * 1000 ),'YYYY-MM-DD hh:mm:ss');
var val = result.value[0];
console.log("%s,%s,%s,%s,%s,%s", date, val[0],val[1],val[2],val[3],val[4]);
});
process.exit();
});
#IFTTTに投げるシェルスクリプト
こちらも微妙ですが公開。
IFTTTとfluentdに対して投げている例。
これをcronから定期的に実行すればよい。netatmoの更新間隔は比較的長い(はず)なので、30min以下で投げるのは現実的でない。30min~1h程度の間隔で投げるのが丁度良いと思う。
#!/bin/sh
room=$(/usr/local/bin/node /home/pi/netatmo/get_netatmo.js '<MODULE_ID>')
out=$(/usr/local/bin/node /home/pi/netatmo/get_netatmo.js '<MODULE_ID>')
#echo 'room: '$room
#echo 'out: '$out
room_date=`echo $room | cut -f1 -d','`
room_temp=`echo $room | cut -f2 -d','`
room_co2=`echo $room | cut -f3 -d','`
room_humi=`echo $room | cut -f4 -d','`
room_pres=`echo $room | cut -f5 -d','`
room_nois=`echo $room | cut -f6 -d','`
#echo 'room date: '$room_date
#echo 'room temp: '$room_temp'c'
#echo 'room co2: '$room_co2'ppm'
#echo 'room humi: '$room_humi'%'
#echo 'room pres: '$room_pres'mbar'
#echo 'room nois: '$room_nois'dB'
out_date=`echo $out | cut -f1 -d','`
out_temp=`echo $out | cut -f2 -d','`
out_humi=`echo $out | cut -f4 -d','`
#echo 'out date: '$out_date
#echo 'out temp: '$out_temp'c'
#echo 'out humi: '$out_humi'%'
# IFTTT用
ifttt_json="{\"value1\": \"$room_date\",\"value2\": {\"room_temperature\": $room_temp,\"room_co2\": $room_co2,\"room_humidity\": $room_humi,\"room_pressure\": $room_pres,\"room_noise\": $room_nois},\"value3\": {\"out_temperature\": $out_temp,\"out_humidity\": $out_humi}}"
curl -X POST -H "Content-Type: application/json" -d "$ifttt_json" https://maker.ifttt.com/trigger/netatmo/with/key/<KEY>
# fluentd用
fluentd_json="{\"date\": \"$room_date\",\"room_temperature\": $room_temp,\"room_co2\": $room_co2,\"room_humidity\": $room_humi,\"room_pressure\": $room_pres,\"room_noise\": $room_nois,\"out_temperature\": $out_temp,\"out_humidity\": $out_humi}"
curl -X POST -H "Content-Type: application/json" -d "$fluentd_json" http://<IP>:<PORT>/<TAG>
##素直にvalue1,value2,value3の数値を連携させたい例
この場合には、どのデータを渡すか厳選する必要あり。
個人的には「slackに投げる」「通知に出す」「twitterでつぶやく」などを想定すると、以下の3つかと。
測定時間を投げたい場合にはさらに1つ減る。
1.室温(room_temp)
2.外気温(out_temp)
3.外湿度(out_humi)
上記スクリプトのifttt_jsonの別例を示す。
ifttt_json="{\"value1\": $room_temp, \"value2\": $out_temp, \"value3\": $out_humi}"
現在はこちらで運用中。
#結果
##全データを投げた例
IFTTTのMakerチャンネルにネストされたjsonは送れるか?の成功例のようにMakerチャンネル経由で測定値がgoogleスプレッドシートに記録できる。
##投げるデータを厳選した例
試しにPushbulletに投げてみた例。
まぁ悪くないですな。
こちらはIFTTT通知に投げてみた例。
こちらの方がいいかも。
#さいごに
どこかに値を保存して、その値のURLを送るでもいいのですが、まずはMakerチャンネルを利用して簡単に別サービスを連携する土壌はできたかな。と。
色々工夫の余地があるので今後も定期的に更新する予定。
シェルスクリプトでデータの送り先を複数にすることが容易なので、今はIFTTTに投げると同時にfluentd→ElasticsearchでKibanaからセンサー類の一括監視も可能になった。こちらは次回予告ということで。