前からちょろちょろ作っていた 「電力測定するやつ」 が一通り完成した。正確には、電力ではなく、電流を測定するやつだが。
Pythonとか、JSONとか、Chart.jsなどという、C言語ばっかり書いている私にとっては、最近ぽい(そうでもない?)ものをグニグニくみあわせてみた。お勉強をかねて。
電流測定とデータの蓄積
この電流測定するやつは、電流を測定するモジュール(AVR+Xbee)と、測定結果を蓄積する部分(Raspberry Pi+Xbee)に分かれる。
- 電流を測定する部分
- AVR (ATMega8) が、30秒に一回Wakeupし、電流センサの値(電圧出力)を1秒間の間128回 AD変換する。128回の測定値の合計(正確には基準点との絶対値の合計)を、その時刻の消費電流量とする
- AVRは、12回分の測定結果が溜まるごと、つまり30秒 * 12回 = 5分ごとに、その5分間の平均消費電流値を求める。
- AVRは、1時間ごとに、XBeeをWakeupし、その1時間の間の5分ごとの平均消費電流データをXbeeを使って、Raspberry Piに送る。
- これにより、電子レンジの利用など1分ぐらいの消費電流変化も捉えられるようにするとともに、乾電池で電力測定部分を計算上1年以上動作可能にした。
- 測定したデータがいつ採取したしたものか分かるよう、RTCモジュールを搭載。RTCの値は、Raspberry Piとの通信時に、適宜、Raspberry Pi側の時刻に構成されるようにした。
- 一応、本当に1年以上動くか評価するために、電池電圧のデータも、電流量のデータとともに、Raspberry Piに送信するようにしてある
- 測定結果を蓄積する部分
- Raspberry PiにXbeeを取り付けたものを利用。
- 測定部分から送られてきたデータは、Raspberry Pi上で動かしているデーモンが、SQLite3のデータベースにガシガシつっこむ。
データの表示
データの表示部分が、自分にとって、新しい試み。
まず、測定データは、SQLite3のデータベースの次のテーブルにがしがし、記録される。
CREATE TABLE samples ( sample_time TEXT, sample_type INTEGER, value INTEGER, PRIMARY KEY(sample_time, sample_type) );
ここで、sample_type は、測定値のタイプ(0 : 電流測定値、1 : 電池電圧測定値)を示す。
このデータベースに対して「過去48時間の1時間後との電流値平均」「過去1ヶ月の1日ごとの電流値平均」「過去1年間の1Weekごとの電流値平均」を求めるSQLを発行し、その情報をJSONデータとして吐き出すCGIをPythonを用いて作成。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sqlite3
import json
def get_json_labels_data_pair(cursor):
label = []
value = []
for r in c:
label.append(r[0])
value.append(r[1])
return {"labels" : label, "data": value}
db = sqlite3.connect("//home/pi/XbeeDaemon/samples.db")
# 過去48時間の1時間後との電流値平均
sql = (
"select strftime('%m-%d %H', sample_time) as time,avg(value)"
" from samples"
" where sample_type = 0"
" and julianday(sample_time) "
" >= julianday(datetime('now', 'localtime', '-48 hour'))"
" group by time order by time;"
)
c = db.execute(sql)
hour_data = get_json_labels_data_pair(c)
# 過去1ヶ月の1日ごとの電流値平均
sql = (
"select strftime('%Y-%m-%d', sample_time) as time,avg(value)"
" from samples"
" where sample_type = 0"
" and julianday(sample_time) "
" >= julianday(datetime('now', 'localtime', '-1 month'))"
" group by time order by time;"
)
c = db.execute(sql)
day_data = get_json_labels_data_pair(c)
# 過去1年間の1Weekごとの電流値平均
sql = (
"select strftime('%Y-%m (%W)', sample_time) as time, avg(value)"
" from samples"
" where sample_type = 0"
" and julianday(sample_time) "
" >= julianday(datetime('now', 'localtime', '-1 year'))"
" group by time order by time;"
)
c = db.execute(sql)
week_data = get_json_labels_data_pair(c)
send_data = {"hour" : hour_data, "day" : day_data, "week" : week_data}
print "Content-type: application/json"
print
print json.dumps(send_data)
で、最後に、このCGIプログラムを呼び出して、JSONデータを取得し、その情報を Chart.js によって表示するHTMLファイルを作成。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script src="./Chart.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
<script type="text/javascript">
function drawChart(labelData, targetCanvas)
{
var chartData = {
datasets : [
{
fillColor : "rgba(151,187,205,0.5)",
strokeColor : "rgba(151,187,205,1)",
pointColor : "rgba(151,187,205,1)",
pointStrokeColor : "#fff",
}
]
};
chartData.labels = labelData.labels;
chartData.datasets[0].data = labelData.data;
new Chart(targetCanvas.getContext("2d")).Line(chartData);
}
function updateChart ()
{
$.getJSON("http://pi/cgi-bin/Power.py", function(json) {
drawChart(json.hour, document.getElementById("hourChart"));
drawChart(json.day, document.getElementById("dayChart"));
drawChart(json.week, document.getElementById("weekChart"));
});
}
$(function(){
var currentChart = 0;
var chart = $("#chartArea").children('div');
$(chart).hide();
updateChart();
setInterval(updateChart, 60 * 60 * 1000); // 一時間ごとに更新
$(chart[currentChart]).show();
setInterval(function()
{
var nextChart = currentChart + 1;
if (nextChart >= chart.length) {
nextChart = 0;
}
$(chart[currentChart]).fadeOut(1000);
$(chart[nextChart]).fadeIn(1000);
currentChart = nextChart;
},
30 * 1000 // 30秒置きに切り替え
);
});
</script>
<style type="text/css">
#chartArea {
height: 600px;
width: 850px;
overflow:hidden;
position:relative;
}
.chart {
position:absolute;
}
</style>
</head>
<body>
<H1>消費電流量表示するやつ</h1>
<div id="chartArea">
<div id="divhour" class="chart">
<h2>過去48時間のデータ(1時間単位)</h2>
<canvas id="hourChart" height="500" width="800"></canvas>
</div>
<div id="divday" class="chart">
<h2>過去1ヶ月のデータ(1日単位)</h2>
<canvas id="dayChart" height="500" width="800"></canvas>
</div>
<div id="divweek" class="chart">
<h2>過去1年のデータ(1週間単位)</h2>
<canvas id="weekChart" height="500" width="800"></canvas>
</div>
</div>
</body>
</html>
んで、このHTMLにブラウザからアクセスすると、次のような画面が30秒、お気に切り替わって表示される、と。(まだ測定を始めて1週間ぐらいなので、過去1ヶ月と1年の表示はしょんぼりな感じ)
あとは、Raspberry Piを常時テレビにつないでおいて、Raspberry Pi起動とともに、Raspberry Piの標準Webブラウザ Midori を全画面で起動して、上記のHTMLを表示するようにする。加えて、現在は、センサの生データを表示しているので、電気メータの実測値から係数を求めて、W(KWh)単位でグラフ表示するようにすれば、おしまいかな。
思ったこと
- センサの値とかは、とりあえず、データベースに放り込んでおけば、SQL 1つでグニグニできるので、良い感じ。
- ちょっと勉強でも、それっぽく使える。JQueryとかChart.jsとか、すごいね。。。
最近のコメント