Nature Remo API + Google Chartsでグラフを作ろう!

Nature Remo活用シリーズ

0.開封編 1.ダイキンのエアコン 2.ダイキンのエアコン、その2
3.アイリスオーヤマのサーキュレーター 4.温度計 5.温度計、その2
6.Google Chartsでグラフ作成    

こんな感じのグラフを作ります。

さて前回Nature Remo APIから部屋の気温と湿度を定期的に取得してブラウザで表示する温度計を作りました。今回はそのデータをグラフ化して部屋の温度と湿度を見える化してしまおうという計画です。

グラフ描写はGoogle Chartsを利用

データをグラフ化する手法は沢山ありますが、今回はGoogle Chartsを利用します。Google Chatsはグーグルが提供する無料のグラフ作成ツールで、JavaScriptによるライブラリの読み込みとデータの入力を行うだけで、円グラフや折れ線グラフなどいろいろなグラフを作成することができます。

グラフタイプはLine Chart

Chart Galleryから好みのグラフを選びます。今回は温度と湿度を時系列に並べるので折れ線グラフ(Line Chart)にします。

JavaScriptはサンプルコードをちょこっと改造

Google Chartsのページにグラフを描写するためのサンプルコード載っています。このままでも十分かっこいいグラフができますが、Configration Optionsを見ながら線の色やタイトル、凡例を設定することで更に見やすくカッコよくなります。

Nature Remo APIの温度グラフを描写するコード

コードはこのように書きました。

<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>remo chart</title>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {packages: ['corechart', 'line']});
google.charts.setOnLoadCallback(drawCrosshairs);

function drawCrosshairs() {
  var data = new google.visualization.DataTable();
  data.addColumn('string', '日時');
  data.addColumn('number', '室内の気温');
  data.addColumn('number', '室内の湿度');
  data.addRows([

  ]);

  var options = {
    height: '800',
    hAxis: {
      title: '1時間毎の気温と湿度'
    },
    series: {
      0: { color: '#000065' },
      1: { color: '#6565FF' },
      2: { color: '#CB3200' },
      3: { color: '#FFB299' }
    },
    curveType: 'function',
    crosshair: {
      trigger: 'both',
      focused: {
        color: 'green',
        orientation: 'vertical'
      },
      selected: {
        color: 'aqua',
        opacity: 0.3,
        orientation: 'horizontal'
      }
    },
    tooltip: {
      trigger: 'both'
    },
    focusTarget: 'category'
  };

  var chart = new google.visualization.LineChart(document.getElementById('chart_div'));

  chart.draw(data, options);
}
</script>
</head>
<body>
<div id="chart_div"></div>
</body>
</html>

data.addRows([

の後に温度と湿度の値を入れていくと勝手にグラフになってくれます。

ポイントは height: ‘800’, でグラフの縦を長くしているところです。湿度はわりと上下の変化があるのでいいのですが、室内の温度はそんなに変化がないと思います。デフォルトの縦幅だとあまり変化がないつまらないグラフになってしまうので縦を長くして変化を見えやすくしています。因みに800の単位はピクセルです。

このファイルをremo-chart.htmlとして保存します。

温度と湿度の値を自動で追記するプログラム

グラフのベースとなるHTMLとJavaScriptができましたので、Nature Remo APIから取得した温度と湿度の値を自動でどんどん追記していくプログラムを作ります。値は前回作った温度計プログラムの中間生成物である、tmp.jsonファイルから抽出します。実行環境は前回同様、さくらのレンタルサーバ、言語はPerlです。

#!/usr/bin/perl

$| = 1;

#モジュールを指定
use utf8;

#実行時刻の取得
($sec, $min, $hour, $mday, $mon, $year,$wday, $yday, $isdst) = localtime;
$yyyy = $year + 1900;
$month = $mon + 1;

#ファイル指定
$html = './remo-chart.html';
$tmphtml = './tmp.html';
$tmpjson = './tmp.json';

#コマンドと引数を指定
$jq = "/home/XXXX/bin/jq";

#センサー値の取り出し
$te = `$jq .[].newest_events.te.val $tmpjson`;
$hu = `$jq .[].newest_events.hu.val $tmpjson`;

chomp($te);
chomp($hu);

open(HTML, "<$html");
open(TMP, ">$tmphtml");
while ($line = <HTML>){
	chomp($line);
	if($line =~ /]\)\;/) {
		print(TMP "[\"$yyyy/$month/$mday $hour:$min:$sec\", $te, $hu,],\n");
		print(TMP "$line\n");
	} else {
		chomp($line);
		print(TMP "$line\n");
	}
}

close(TMP);
close(HTML);

rename "$tmphtml", "$html";

exit:

プログラム解説

要点を解説します。

#ファイル指定
$html = './remo-chart.html';
$tmphtml = './tmp.html';
$tmpjson = './tmp.json';

ファイルを変数に代入します。一つ目は上で作ったベースとなるHTML + JavaScriptファイル。二つ目は中間ファイル。三つ目はNature Remo APIから取得した値を保存してあるjsonファイルです。tmp.jsonファイルは前回の温度計プログラムの中間生成ファイルです。作り方は前回を参照してください。

#コマンドと引数を指定
$jq = "/home/XXXX/bin/jq";

#センサー値の取り出し
$te = `$jq .[].newest_events.te.val $tmpjson`;
$hu = `$jq .[].newest_events.hu.val $tmpjson`;

chomp($te);
chomp($hu);

jqコマンドを使ってjsonファイルから温度と湿度の値をそれぞれの変数に代入します。変数代入後、chompコマンドを使ってお尻の改行コードを叩き落とします。

open(HTML, "<$html");
open(TMP, ">$tmphtml");
while ($line = <HTML>){
	chomp($line);
	if($line =~ /]\)\;/) {
		print(TMP "[\"$yyyy/$month/$mday $hour:$min:$sec\", $te, $hu, $owtemp, $owhum],\n");
		print(TMP "$line\n");
	} else {
		chomp($line);
		print(TMP "$line\n");
	}
}

close(TMP);
close(HTML);

rename "$tmphtml", "$html";

exit:

open関数を使ってremo-chart.htmlを開きます。同時にtmp.htmlも開きます。続いてwhile関数を使ってremo-chart.htmlを一行づつ読み込みます。その際、 ” ]);  ” にマッチしたら、実行時間、温度、湿度をtmp.htmlに書き込みます。無ければ読み込んだ行をそのままtmp.htmlに書き込みます。

こうすることで

data.addRows([

以降にグラフデータとなる温度と湿度が実行されるたびに追記されていくという仕組みです。

最後に、tmp.htmlをremo-chart.htmlにリネームして終了です。

cronを使って一時間に一回実行

このプログラムをcronを使って1時間に1度実行します。

2 * * * * cd /home/XXXX/bin/remo-chart ; /usr/bin/perl /home/XXXX/bin/remo-chart/remo-chart.pl 1> /dev/null

crontabにこのように登録します。毎時2分に実行するように登録します。

さあ、アクセスしてみよう。remo-chart.html

cronからプログラムが実行されたらグラフが出来上がっているはず・・・。無事グラフが出来上がっています!サンプルはこちら!

remo-chart

1時間毎の温度と湿度が自動で追記されていっています。

これで部屋の温度と湿度の見える化ができるようになりました。

おわり

Nature Remoで温度計を作ろう!その2

Nature Remo活用シリーズ

0.開封編 1.ダイキンのエアコン 2.ダイキンのエアコン、その2
3.アイリスオーヤマのサーキュレーター 4.温度計 5.温度計、その2

さて前回からの続きです。今回はコードを書いて温度計を作ります。

Perlで書いてcronで定期実行

今回作りたいプログラムはNature RemoのAPIから取得した温度と湿度の値をブラウザで表示するという簡単なプログラムです。となると特定のURLにアクセスしたタイミングでAPIコールすればいいだけですが、折角プログラムを書いて情報を取得するのであれば、定期的に実行してデータを貯め、あとから見返せるようにしておくほうが面白いかなと思いました。もしかしたら温度と湿度の変化から何か発見があるかもしれません。また結果を予めファイルに落としておけば、温度計アプリの表示も早くなります。という訳でプログラムは定期実行、温度表示は結果を書き込まれたHTMLファイルを表示するという形にしました。

実行環境はさくらのレンタルサーバ

定期実行となるとサーバ的なマシンが必要になります。本サイトでもお世話になっているさくらのレンタルサーバ(スタンダード)はPerlも使えてcronも使えますので、この環境を使わない手はありません。言語は使い慣れているPerlで書きます。

Nature RemoのAPIから温度計を作るPerlプログラム

前置きが長くなりましたが、完成したコードは以下のとおりです。ここに大公開!

#!/usr/bin/perl

$| = 1;

#モジュールを指定
use lib '/home/XXXX/cpan/lib/perl5/site_perl/5.8';

#実行時刻の取得
($sec, $min, $hour, $mday, $mon, $year,$wday, $yday, $isdst) = localtime;
$yyyy = $year + 1900;
$month = $mon + 1;

#ファイル指定
$log = '/home/XXXX/remo-api/remo-api-result.csv';
$tmp = '/home/XXXX/remo-api/tmp.json';
$html = '/home/XXXX/remo-api/kion.html';

#アクセストークンを指定
$apikey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

#コマンドと引数を指定
$curl = "/usr/local/bin/curl";
$curlopt = "-X GET";
$url = "https://api.nature.global/1/devices";
$header1 = "-H \"accept: application/json\"";
$header2 = "-H \"Authorization: Bearer $apikey\"";
$jq = "/home/XXXX/bin/jq";

#APIアクセスを実行
$remoapi = `$curl $curlopt $url $header1 $header2`;

if ($remoapi != "") {
	exit:
	} else {
	open(TMP, ">$tmp");
	flock(TMP, 2);
	print(TMP "$remoapi");
	close(TMP);
	}

#センサー値の取り出し
$name = `$jq -r .[].name $tmp`;
$firm = `$jq -r .[].firmware_version $tmp`;
$te = `$jq .[].newest_events.te.val $tmp`;
$hu = `$jq .[].newest_events.hu.val $tmp`;
$il = `$jq .[].newest_events.il.val $tmp`;
$mo = `$jq .[].newest_events.mo.val $tmp`;

chomp($name);
chomp($firm);
chomp($te);
chomp($hu);
chomp($il);
chomp($mo);

#HTMLファイル生成
open(FILE, ">$html");
flock(FILE, 2);
print(FILE "<!doctype html>\n");
print(FILE "<html lang=\"ja\">\n");
print(FILE "<head>\n");
print(FILE "<meta charset=\"UTF-8\">\n");
print(FILE "<title>kion</title>\n");
print(FILE "<style>\n");
print(FILE "body { background:#000000; color:#ffffff}\n");
print(FILE "span.font1 {font-size: 100%; }\n");
print(FILE "span.font2 {font-size: 300%; }\n");
print(FILE "</style>\n");
print(FILE "</head>\n");
print(FILE "<body>\n");
print(FILE "<span class=\"font1\">ただいまの $name の気温と湿度は</span><br>\n");
print(FILE "<span class=\"font2\"> $te \℃ / $hu \%</span><br>\n");
print(FILE "</body>\n");
print(FILE "</html>\n");
close(FILE);

#ログを出力
open(LOG, ">>$log");
flock(LOG, 2);
print(LOG "$yyyy/$month/$mday $hour:$min:$sec,name,$name,firmware_version,$firm,te,$te,hu,$hu,il,$il,mo,$mo\n");
close(LOG);

exit:

プログラム解説

折角なので要点を解説します。

#モジュールを指定
use lib '/home/XXXX/cpan/lib/perl5/site_perl/5.8';

PerlでJSONを扱えるようにするモジュール、JSON.pmがあるパスを指定します。尚、さくらのレンタルサーバではインストールされていないので、自身でインストールし、パスを指定します。

#ファイル指定
$log = '/home/XXXX/remo-api/remo-api-result.csv';
$tmp = '/home/XXXX/remo-api/tmp.json';
$html = '/home/XXXX/remo-api/kion.html';

各種ファイルを指定します。$logは定期的に取得したデータをログとして保存するCSVファイル、$tmpはjsonデータを一時的に保存しておくファイル、$htmlは温度計として表示するためのHTMLファイルです。

#アクセストークンを指定
$apikey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";

前回取得したアクセストークンを指定します。

#コマンドと引数を指定
$curl = "/usr/local/bin/curl";
$curlopt = "-X GET";
$url = "https://api.nature.global/1/devices";
$header1 = "-H \"accept: application/json\"";
$header2 = "-H \"Authorization: Bearer $apikey\"";
$jq = "/home/XXXX/bin/jq";

今回の実装は前回試したcurlコマンドとjqコマンドの組み合わせをPerlで実行させるだけです。Perlはバッククォートでコマンドを囲うと実行できる機能があるのでこれを利用します。まずは各種コマンドのパスを変数に代入します。

尚、さくらのレンタルサーバはjqコマンドは入っていないので、自身でコンパイルしてインストールする必要があります。

#APIアクセスを実行
$remoapi = `$curl $curlopt $url $header1 $header2`;

if ($remoapi != "") {
	exit:
	} else {
	open(TMP, ">$tmp");
	flock(TMP, 2);
	print(TMP "$remoapi");
	close(TMP);
	}

$remoapiにcurlコマンドの標準出力を代入します。コマンドはバッククォートで囲って実行します。$remoapiが空でなければ$tmpに一時保存します。

#センサー値の取り出し
$name = `$jq -r .[].name $tmp`;
$firm = `$jq -r .[].firmware_version $tmp`;
$te = `$jq .[].newest_events.te.val $tmp`;
$hu = `$jq .[].newest_events.hu.val $tmp`;
$il = `$jq .[].newest_events.il.val $tmp`;
$mo = `$jq .[].newest_events.mo.val $tmp`;

chomp($name);
chomp($firm);
chomp($te);
chomp($hu);
chomp($il);
chomp($mo);

jqコマンドを使って必要な値を取り出します。jqコマンドを使うと必ずお尻に改行コードが付いてしまうのでchompコマンドで叩き落とします。

#HTMLファイル生成
open(FILE, ">$html");
flock(FILE, 2);
print(FILE "<!doctype html>\n");
print(FILE "<html lang=\"ja\">\n");
print(FILE "<head>\n");
print(FILE "<meta charset=\"UTF-8\">\n");
print(FILE "<title>kion</title>\n");
print(FILE "<style>\n");
print(FILE "body { background:#000000; color:#ffffff}\n");
print(FILE "span.font1 {font-size: 100%; }\n");
print(FILE "span.font2 {font-size: 300%; }\n");
print(FILE "</style>\n");
print(FILE "</head>\n");
print(FILE "<body>\n");
print(FILE "<span class=\"font1\">ただいまの $name の気温と湿度は</span><br>\n");
print(FILE "<span class=\"font2\"> $te \℃ / $hu \%</span><br>\n");
print(FILE "</body>\n");
print(FILE "</html>\n");
close(FILE);

温度計となるHTMLファイルを出力します。

#ログを出力
open(LOG, ">>$log");
flock(LOG, 2);
print(LOG "$yyyy/$month/$mday $hour:$min:$sec,name,$name,firmware_version,$firm,te,$te,hu,$hu,il,$il,mo,$mo\n");
close(LOG);

最後にログとして各種値をCSVファイルとして追記していきます。

cronの実行間隔は5分に一回

プログラムができましたのでcronに登録します。Nature RemoのAPIの更新間隔は分からなかったのでとりあえず5分間隔にしました。温度計なので5分に一回は更新してほしいなという希望的観測も含まれます。

*/5 * * * * cd /home/XXXX/bin/remo-api ; /usr/bin/perl /home/XXXX/bin/remo-api/remo-api.pl 1> /dev/null

crontabにはこのように記述します。

さあ、アクセスしてみよう!Nature Remo温度計

プログラムも書いてcronの登録も終わりましたのであとは自動で温度計HTMLファイルが出力されるのを待つだけです。

温度と湿度がHTMLファイルで出力されてブラウザで表示できるようになりました!成功です!!

ちなみにファイルは kion.html (ダミー)こんな感じに生成されます。

これで部屋の温度と湿度が知りたいときは、PCを起動してブラウザを立ち上げて特定のURLにアクセスすれば分かるようになりました。(面倒くさ!核爆

と言うのは冗談で、私はオリジナルのブラウザスタートページを作っていてiframeで埋め込んで使っています。

おまけ

一ヶ月ほど動かしてログを取っていたところ2点ほど発見がありました。

APIの更新間隔は5分でよい

2019/12/6 16:10:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,13,hu,34,il,58.2,mo,1
2019/12/6 16:15:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,13,hu,34,il,39,mo,1
2019/12/6 16:20:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,13,hu,34,il,28.79,mo,1
2019/12/6 16:25:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,13,hu,34,il,18.79,mo,1
2019/12/6 16:30:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,13,hu,34,il,8.6,mo,1

最小の更新間隔は分かりませんが、この通りilの値が変化していますので、5分間隔でもよいことが分かります。

温度が0.000001まで表示される

2019/12/5 20:45:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,14.790001,hu,35,il,236.19,mo,1
2019/12/5 20:50:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,14.790001,hu,35,il,236.19,mo,1
2019/12/5 20:55:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,14.790001,hu,35,il,236.19,mo,1
2019/12/5 21:0:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,14.790001,hu,35,il,236.19,mo,1
2019/12/5 21:5:0,name,ダイニングルーム,firmware_version,Remo/1.0.62-gabbf5bd,te,14.790001,hu,35,il,236.19,mo,1

この通り、温度のteが0.000001単位まで表示されることがあります。これは恐らく、本当の温度ではなく小数点を扱っているので表示上このようになっているものと思われます。四捨五入してもいいのですが別に困らないのでこのままにします。

おわり

Nature Remoで温度計を作ろう!

Nature Remo活用シリーズ

0.開封編 1.ダイキンのエアコン 2.ダイキンのエアコン、その2
3.アイリスオーヤマのサーキュレーター 4.温度計  

さて、めっきり寒くなってきました。空気も乾燥しています。そうなると気になるのが部屋の温度と湿度です。今、何度なのかなー、肌がカサつくけど湿度はどのくらいかなーと知りたくなりますが、生憎、私の部屋には温度計がありません。今更温度計を買うのもなんだなーと考えていたところ、ふと思い出しました。

そういえばNature Remoに温度計とかセンサーがついていたような・・・。

調べてみると、Nature Remoには温度、湿度、照度、人感センサーがついており、各センサーの値をAPI経由で取得できることがわかりました。

だったら定期的にAPIを叩いて温度と湿度をブラウザで表示できるようにしよう!

というわけで久しぶりにコードを書くことにしました。

まずはアクセストークンの取得

まずはじめにNature RemoのAPIを使えるようにするためのアクセストークンを発行します。アクセストークンを発行するためのURLはこちらです。

https://home.nature.global/

ログインをクリック

メールアドレスを入力

メールを送りましたとなるのでメールソフトを開きます。

メールに書いてあるリンクを開いて「許可する」をクリック

これでアクセストークンを発行できる状態になりました。すでにあるトークンは以前作ったIFTTT連携用ですね。

早速、アクセストークンを発行します。左下の「Generate access token」をクリックします。

新しいアクセストークンが発行されます。簡単ですね。ここで注意2点ほど。一つはアクセストークンの表示は一度きりなので必ずメモすること、2つめはアクセストークンは他人にバレないようにすることです。まあバレても部屋の温度と湿度が分かるのとエアコンとかが勝手に操作されるだけですけど・・・。

Nature RemoのAPIはcurlで叩いてJSONで取得

アクセストークンが取得できたので、プログラムを書く前に試しにAPIを叩いて情報の取得ができるか試してみましょう。Nature RemoのAPIはREST APIなのでcurlコマンドで簡単に試すことができます。

またNature RemoのAPIはマニュアルが公開されているので、必要な情報の取得や操作のためのURIはマニュアルから参照できます。

http://swagger.nature.global/

Nature Remoのセンサーの値を取得するためのコマンドは以下です。<<アクセストークン>>のところに先程取得したトークンを入れます。

curl -X GET "https://api.nature.global/1/devices" -H "accept: application/json" -H "Authorization: Bearer <<アクセストークン>>"

何やらズラズラっと出てきます。出力形式はJSONです。ちなみにこのコマンドはChromebookのLinux機能を使いました。Chromebook便利ですね!

話は逸れますが最近はREST + JSONが流行りですが、ぶっちゃけ私は苦手です。JSONって可読性は悪いし、データの抽出も一手間かかるし・・・。

まあ仕様ですので致し方ありません。jqコマンドを使って整形します。

curl -X GET "https://api.nature.global/1/devices" -H "accept: application/json" -H "Authorization: Bearer <<アクセストークン>>" | jq

可読性が良くなりました。”newest_events”以降がNature Remoの各種センターの値です。それぞれの意味はAPIマニュアルの「SensorValue」のdescriptionに以下のように書いてあります。


The reference key to SensorValue means “te” = temperature, “hu” = humidity, “il” = illumination, “mo” = movement

ということなので、

te 温度
hu 湿度
il 照度
mo 人感センサー

なのだと思います。照度の値がルクスなのかは分かりませんでした。

出力結果から私の部屋は現在、気温が18.2度で湿度が45%で明るさは10.39で人がいるということが分かります。

温度と湿度を抽出

今回の目的は温度計を作ることなので、必要な情報である温度と湿度をjqコマンドを使って更に絞り込みます。

温度だけを出す場合は以下のコマンドです。

curl -X GET "https://api.nature.global/1/devices" -H "accept: application/json" -H "Authorization: Bearer <<アクセストークン>>" | jq .[].newest_events.te.val

湿度だけを出すコマンドは以下

curl -X GET "https://api.nature.global/1/devices" -H "accept: application/json" -H "Authorization: Bearer <<アクセストークン>>" | jq .[].newest_events.hu.val

見事に目的の値を出すことに成功しました!!あとはこの値をブラウザで表示できるようHTMLを生成するだけです。

今回はここまで。次回はこれらの処理を自動で行うプログラムを作成して簡単な温度計Webアプリを作りたいと思います。