Grafanaの温度計パネルを作った
室温をデータベースに記録して可視化する(Grafana導入編)
前回の続きです。今回はRaspberry Pi 3にGrafanaをインストールし、グラフ化します。
GrafanaをRapsberry Pi 3にインストール
リポジトリを追加してGrafanaをインストールする
ARM版のパッケージは公式には配布されていないようですが、非公式で公開されている方がいるのでそれを利用します。
curl -sL https://bintray.com/user/downloadSubjectPublicKey?username=bintray | sudo apt-key add - echo "deb https://dl.bintray.com/fg2it/deb jessie main" | sudo tee -a /etc/apt/sources.list.d/grafana.list sudo apt-get update sudo apt-get install grafana
Grafanaを起動する
sudo service grafana-server start sudo update-rc.d grafana-server defaults
データソースの設定
ブラウザで http://[Raspberry PiのIPアドレス]:3000/ にアクセスします。
User/Passwordはadmin/adminです。
「Add data source」をクリック。
こんな感じで設定します。一番上のNameは任意の名前です。設定が正しく済んでデータベースへの接続に成功すると、画像のように緑の背景でメッセージが表示されます。
ダッシュボードの作成
データソースの設定ができたら、ダッシュボードを作成します。左上のアイコン→Dashbords→Newをクリックすると下記の画面に移動します。
とりあえず、グラフ化してみます。「Graph」をクリック。
空のグラフが表示されます。グラフの上部分、「Panel Title」と表示されているところをクリックすると画像のようなメニューが表示されるので「Edit」をクリック。
画面下部の「Metrics」タブで画像のように設定します。設定が正しく行われて値が取得できると、上部にグラフが表示されます。
- FROM
- temperatureテーブルのデータをすべて取得します。タグで絞り込みを行いたい場合はWHEREの横の+をクリックして条件を設定することができます。
- SELECT
- field(value)で値を取得、mean()で平均値にします。
- GROUP BY
- 10分間の値をlocationタグでグループ化します。fill(null)は値が記録されていない時間帯のデータをないものとして扱うということで、full(0)にすると0として扱い、fill(previous)だと前の値を使うという意味です。例えばtime(1s)なのに実際のデータが10秒ごとにしかない場合、残りの9秒間のデータをどう表示するかということに関わってきます。
設定が済んだら、右端の×で閉じて画面上部のフロッピーアイコンで保存します。
これで室温/外気温の変化を可視化するダッシュボードが作成できました!
今後は、部屋に誰かがいるかどうか・窓が空いているかどうかなど、室温に影響を与えそうな内容も追加して分析できると面白いかなと思います。
室温をデータベースに記録して可視化する(InfluxDB導入編)
エアコンから温度データを取得できるようになったので、このデータをデータベースに記録して後から参照できるようにしたいと思います。
室温の変化や外気温との関係を分析することで効率よくエアコン運用ができるようになる…かどうかはさておき、普段は室温の変化なんてそんなに気にしていませんが可視化するとどうなるのかなと興味があるので。
データベースはMySQLとSQL Server、PostgreSQLなどRDBしか使ったことがないのですが、今回は時系列データベースのInfluxDBを使ってみたいと思います。
エアコンのセンサー監視はRaspberry Pi 3で行なっているので、これにインストールして使用します。
また、可視化については最終的にはダッシュボードを自作したいですが、とりあえず仕事でも使ったことのあるGrafanaを使ってサクッと実現させたいと思います。
InfluxDBをRapsberry Pi 3にインストール
リポジトリを追加してInfluxDBをインストール
$ curl -sL https://repos.influxdata.com/influxdb.key | sudo apt-key add - $ echo "deb https://repos.influxdata.com/debian jessie stable" | sudo tee /etc/apt/sources.list.d/influxdb.list deb https://repos.influxdata.com/debian jessie stable $ sudo apt-get update $ sudo apt-get install influxdb
InfluxDBを起動
$ sudo systemctl start influxdb
動作確認。
$ curl -sl -I http://localhost:8086/ping $ ps aux | grep influx influxdb 2380 1.1 1.0 800020 9456 ? Ssl 12:10 0:00 /usr/bin/influxd -config /etc/influxdb/influxdb.conf pi 2396 0.0 0.1 5720 1856 pts/0 S+ 12:10 0:00 grep --color=auto influx pi@raspberrypi:~ $ ss -lntp | grep 808 LISTEN 0 128 127.0.0.1:8088 *:* LISTEN 0 128 :::8086 :::* pi@raspberrypi:~ $ curl -sl -I http://localhost:8086/ping HTTP/1.1 204 No Content Content-Type: application/json Request-Id: 8eef0538-a7e8-11e7-8001-000000000000 X-Influxdb-Version: 1.3.5 Date: Tue, 03 Oct 2017 03:11:33 GMT pi@raspberrypi:~ $ curl http://localhost:8086/query?pretty=true --data-urlencode "q=SHOW DATABASES" { "results": [ { "statement_id": 0, "series": [ { "name": "databases", "columns": [ "name" ], "values": [ [ "_internal" ] ] } ] } ] }
データベース作成
CLI経由でsensorという名前のデータベースを作成します。
$ influx Connected to http://localhost:8086 version 1.3.5 InfluxDB shell version: 1.3.5 > create database sensor > show databases name: databases name ---- _internal sensor > exit
データ投入
HTTP経由でデータを投入してみます。
$ curl -i -XPOST 'http://localhost:8086/write?db=sensor' --data-binary 'temperature,location=LDK value=27.0 1434055562000000000' $ curl -i -XPOST 'http://localhost:8086/write?db=sensor' --data-binary 'temperature,location=屋外 value=26.0 1434055562000000000'
データの確認
投入したデータを確認します。
$ curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=sensor" --data-urlencode "q=SELECT \"value\" FROM \"temperature\" WHERE \"location\"='LDK'" { "results": [ { "statement_id": 0, "series": [ { "name": "temperature", "columns": [ "time", "value" ], "values": [ [ "2015-06-11T20:46:02Z", 27 ] ] } ] } ] } $ curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=sensor" --data-urlencode "q=SELECT \"value\" FROM \"temperature\" WHERE \"location\"='屋外'" { "results": [ { "statement_id": 0, "series": [ { "name": "temperature", "columns": [ "time", "value" ], "values": [ [ "2015-06-11T20:46:02Z", 26 ] ] } ] } ] }
データの削除
$ curl -XPOST 'http://localhost:8086/query?pretty=true' --data-urlencode "db=sensor" --data-urlencode "q=DROP SERIES FROM \"temperature\"" $ curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=sensor" --data-urlencode "q=SELECT \"value\" FROM \"temperature\"" { "results": [ { "statement_id": 0 } ] }
JavaScriptでセンサーの値を取得してInfluxDBへ投入する
Node.jsでエアコンからセンサーの値を取得してデータを投入します。だいたいこんな感じ。
// エアコンのセンサーから値を取得する http.get(`http://192.168.11.2/aircon/get_sensor_info`, (response) => { let body = ''; response.setEncoding('utf8'); response.on('data', (chunk) => { body += chunk; }); response.on('end', () => { // 取得した文字列をオブジェクトに変換 const sensorValues = {}; const items = body.split(','); const length = items.length; for (let i = 0; i < length; i++) { const keyVal = items[i].split('='); sensorValues[keyVal[0]] = keyVal[1]; } // InfluxDBに室温と外気温をPOSTする const timestamp = +(new Date()) * 1000000; const postData = `temperature,location=LDK value=${sensorValues.htemp} ${timestamp} temperature,location=屋外 value=${sensorValues.otemp} ${timestamp}`; const options = { host: 'localhost', port: 8086, path: `/write?db=sensor`, method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }; const request = http.request(options, (dbResponse) => { dbResponse.setEncoding('utf8'); dbResponse.on('data', (dbResponseData) => { console.log(dbResponseData); }); }); request.on('error', (error) => { console.log(error.message); }); request.write(postData); request.end(); }); }).on('error', (error) => { console.log(error.message); });
実際には、前回作成した室温監視プログラムに機能追加しました。
次回は、記録したデータの可視化を行います。
ダイキンのルームエアコンでおうちハックする(センサー編)
以下の記事の続きです。
haneco.hatenablog.jp
haneco.hatenablog.jp
今回はセンサーから値を取得してみます。
取得できる値
室温と外気温を取得できます。外気温は室外機のセンサーで取得しているようです。室温センサーはAN80TRP-Wの場合は本体左側にあります。センサー周りがホコリで汚れている場合は正しく取得できないかもしれないので掃除しましょう。
パラメーター | 内容 |
---|---|
htemp | 室温 |
hhum | 室内の湿度 |
otemp | 外気温 |
このような値が取得できます。
室温がある範囲から外れたら冷暖房の運転を開始したり、外気温より低いのに冷房が動いていたらメールでアラートを送ったりといったことができそうですね。
センサーを利用したプログラム
うちではハムスターを飼っているのですが外出中の室温が心配です。そこで、室温が設定された範囲から外れたら冷暖房の運転を開始し、室温が安定したら運転を停止するプログラムを書いてみました。
適当なディレクトリに配置し、config/local.jsonに設定値を書き込んだあと
$ cd temperature-checker $ node index.js
で動作します。
/opt 以下に配置した場合、systemdで動かす場合は以下のようなUnit設定を記載すれば良いと思います。
[Unit] Description=Temperature checker After=syslog.target network.target [Service] Type=simple ExecStart=/usr/local/bin/node /opt/temperature-checker/index.js WorkingDirectory=/opt/temperature-checker KillMode=process Restart=always [Install] WantedBy=multi-user.target
ダイキンのルームエアコンでおうちハックする(操作編)
パラメーター解析編からの続きです。
今回は、解析したパラメーターを元に操作を行ってみます。
なお、この記事に書いてある内容を実行することで実際にエアコンの動作を変更することになるので、試してみる場合は自己責任でお願いします。何か問題が起きても一切保障はできません。
取得した情報を加工して設定する
1からパラメーターを組み立てるのは大変なので、取得した情報を加工して設定するのが楽そうです。
幸い、アダプタが知らないパラメーターは無視されるので、/aircon/get_control_info で取得した内容の必要な部分を書き換えて /aircon/set_control_info に投げるのが簡単です。
電源をオンにする
ret=OK,pow=0,mode=3,adv=,stemp=25.0,shum=0,dt1=M,dt2=M,dt3=25.0,dt4=21.0,dt5=21.0,dt7=M,dh1=AUTO,dh2=55,dh3=0,dh4=40,dh5=40,dh7=AUTO,dhh=40,b_mode=3,b_stemp=25.0,b_shum=0,alert=16,stemp_a=,dt1_a=-8.0,dt7_a=-8.0,b_stemp_a=
こんなレスポンスが返ってきた状態から電源をオンにするには、以下のURLにGETを投げるだけで大丈夫です。
http://[エアコンのIPアドレス]/ret=OK&pow=1&mode=3&adv=&stemp=25.0&shum=0&dt1=M&dt2=M&dt3=25.0&dt4=21.0&dt5=21.0&dt7=M&dh1=AUTO&dh2=55&dh3=0&dh4=40&dh5=40&dh7=AUTO&dhh=40&b_mode=3&b_stemp=25.0&b_shum=0&alert=16&stemp_a=&dt1_a=-8.0&dt7_a=-8.0&b_stemp_a=
pow=0をpow=1に書き換えて、,を&に置換しただけですね。軽く試してみるだけならブラウザでアクセスするだけで動作変更されます。LAN内とはいえ、認証も何もないのがちょっと怖いですね…。
ダイキンのルームエアコンでおうちハックする(パラメーター解析編)
我が家ではダイキン製ルームエアコンAN80TRP-Wに無線LAN接続アダプターBRP072A41を接続し、iPhoneにダイキンスマートAPPをインストールして操作できるようにしています。
これはこれでとても便利に使えているのですが、どうせならHomebridgeを使って「ホーム」アプリに対応させたり、気温などの条件によって動作を自動化させたいと思い、アプリと無線LANアダプターの通信内容を解析してハックしてみることにしました。
解析方法
大抵の場合はHTTPを使っているに違いない、ということで今回はmitmproxyを使って解析してみます。
mitmproxyのインストール方法は公式サイトを参考に。私はMacを使っているので
$ brew install mitmproxy
でインストールしました。
インストールしたら、
$ mitmproxy
で起動し、iPhoneの設定アプリからWi-Fi→使用中のSSID→プロキシを構成の順に進んでいき、mitmproxyをインストールしたマシンのIPアドレスとポート番号(通常は8080、ターミナル画面右下に表示されている)を入力します。
その後、ダイキンスマートAPPを起動してエアコンの情報を取得します。
バッチリ取れました。
その後は(電気代を気にしつつ)色々操作をしながら通信内容を解析していきます。
エンドポイント
APIのエンドポイントは以下の通り。と言ってもRESTfulではなくリクエストはすべてGETで行われているようで、レスポンスはキーと値を=で繋いだコンマ区切りのフォーマットです。
パス | 内容 |
---|---|
/aircon/get_sensor_info | センサの情報。気温とか湿度とか。 |
/aircon/get_control_info | 設定情報。運転モードとか。 |
/aircon/set_control_info | 設定情報の変更。「?」以降にクエリ文字列を付加してリクエストを送るとエアコンの動作を制御できる。 |
/common/basic_info | 基本的な情報。IDやパスワードまで返ってくる(!)ので取扱注意。 |
/common/get_datetime | 現在日時。 |
/aircon/get_scdltimer_body?target=c | ウィークリータイマーの設定情報。 |
基本的な操作だけなら上3つを使用するだけで良さそうです。
レスポンス解析
/aircon/get_control_info にアクセスすると以下のようなレスポンスを取得できます。
ret=OK,pow=0,mode=3,adv=,stemp=25.0,shum=0,dt1=M,dt2=M,dt3=25.0,dt4=20.0,dt5=20.0,dt7=M,dh1=AUTO,dh2=55,dh3=0,dh4=0,dh5=0,dh7=AUTO,dhh=40,b_mode=3,b_stemp=25.0,b_shum=0,alert=16,stemp_a=,dt1_a=0,dt7_a=0,b_stemp_a=
さっぱりワケが分かりませんが、エアコンの動作を変更しながら少しずつ解析を進めてみました。なお、アプリを使わなくても普通にブラウザからアクセスするだけで取得できます。
pow
電源状態です。0でオフ、1でオンです。
mode
動作モードです。
設定値 | 内容 |
---|---|
1 | 自動 |
2 | 除湿 |
3 | 冷房 |
4 | 暖房 |
5 | 不明 |
6 | 送風 |
7 | 自動 |
HUM | 加湿 |
どの動作モードにしても5になることがありませんでした。一部の機種で使われているのでしょうか?詳細は不明です。
1と7が自動ですが、7は自動モードで温度を上げたり下げたりする際に使われるモードのようです。
加湿だけ突然アルファベットになるところがなかなかアレですね。
dt*
それぞれのモードに対して設定されている温度です。
設定値 | 内容 | 自動(dt1) | 除湿(dt2) | 冷房(dt3) | 暖房(dt4) | 不明(dt5) | 自動(dt7) |
---|---|---|---|---|---|---|---|
M | 自動 | ○ | ○ | ○ | |||
14 | 14 | ○ | ○ | ||||
15 | 15 | ○ | ○ | ||||
16 | 16 | ○ | ○ | ||||
17 | 17 | ○ | ○ | ||||
18 | 18 | ○ | ○ | ○ | |||
19 | 19 | ○ | ○ | ○ | |||
20 | 20 | ○ | ○ | ○ | |||
21 | 21 | ○ | ○ | ○ | |||
22 | 22 | ○ | ○ | ○ | |||
23 | 23 | ○ | ○ | ○ | |||
24 | 24 | ○ | ○ | ○ | |||
25 | 25 | ○ | ○ | ○ | |||
26 | 26 | ○ | ○ | ○ | |||
27 | 27 | ○ | ○ | ○ | |||
28 | 28 | ○ | ○ | ○ | |||
29 | 29 | ○ | ○ | ○ | |||
30 | 30 | ○ | ○ | ○ | |||
31 | 31 | ○ | |||||
32 | 32 | ○ |
なぜか除湿モードも値が設定されています。今回解析した範囲ではM以外にはなることはありませんでした。また、dt5はdt4と同じ設定値が使われているようです。暖房の温度を変更するとdt5の値も変更されました。
dh*
それぞれのモードに対して設定されている湿度です。
設定値 | 内容 | 自動(dh1) | 除湿(dh2) | 冷房(dh3) | 暖房(dh4) | 不明(dh5) | 自動(dh7) | 加湿(dhh) |
---|---|---|---|---|---|---|---|---|
0 | OFF | ○ | ○ | ○ | ○ | ○ | ||
40 | 40% | ○ | ○ | ○ | ||||
45 | 45% | ○ | ○ | ○ | ||||
50 | 50% | ○ | ○ | ○ | ○ | ○ | ||
55 | 55% | ○ | ○ | |||||
60 | 60% | ○ | ○ | |||||
CONTINUE | 連続 | ○ | ○ | ○ | ○ | ○ | ||
AUTO_L | 低め | ○ | ○ | |||||
AUTO | 標準 | ○ | ○ | |||||
AUTO_H | 高め | ○ | ○ |
dt5と同じくdh5はdt4と同じ値が設定されるようです。
stemp
現在の動作モードで設定されている温度です。dt*の値と同一になります。
shum
現在の動作モードで設定されている湿度です。dh*の値と同一になります。
dt1_a, dt7a_, stemp_a
自動運転モードで「温度を下げる」「温度を上げる」の操作をした場合に値が設定されます。操作した回数に応じて、-8.0〜8.0の値が設定されました。
adv
不明。今回の解析では値が設定されることはありませんでした。
alert
不明。
b_mode=7, b_shum=AUTO, b_stemp=M, b_stemp_a
不明ですが、今回の解析ではb_なしのパラメータと同じ値が設定されているようでした。
次は操作編に続きます。