Make.

センサの記録をグラフ化

Pocket

Webブラウザでraspberrypi にアクセスすることで、気温のグラフを表示します。
決まった時間に気温を計り、そのデータをデータベースに格納する。
Webサーバにグラフ表示のページの取得要求があったときに、データベースから気温データを取り出し、グラフを表示します。


はじめに

ここでは、以下の2つのプログラムを作成して、センサが記録したログデータをグラフ化し、ブラウザで確認できるようにします。

①決まった時間に気温を計り、そのデータをデータベースに格納するプログラム。
②データベースから気温データを取り出し、グラフを表示するプログラム。

00125

このような仕組みは、Webフレームワークとしてパッケージ化されているものもあります。
今回は、Webフレームワークは使わずに、簡単な動的ページの作成で、グラフを表示します。


手順

ここでは、以下のステップで解説していきます。温度センサはADT7410を使用して、接続はI2C温度センサーに、接続されているものとします。

  1. データベースを準備する
  2. 気温を計り、データをデータベースに格納する。
  3. 決まった時間に気温を記録
  4. 気温を取り出しグラフを表示するhtmlを生成するPythonプログラムを作る
  5. pythonプログラムをcgiとして登録する

データベースを準備する

MySQLでデータベースを準備します。気温を計測した日付と、気温のテーブルを作成します。
データベースを使う(MySQL)MySQLの基本操作を参考にして、データベースを作成します。
作成したデータベースのSQLはこのようにしました。

00126

CREATE DATABASE logging CHARACTER SET utf8;
mysql> CREATE TABLE temperature (
  date datetime NOT NULL,
  value float(8, 4) NOT NULL
);

これで、loggingのデータベース内に、temperatureというテーブルが作成されました。
このテーブルに気温を追加するプログラムを記述していきます。


気温を計り、データをデータベースに格納する

Raspberrypiで気温を計るプログラムは、I2C温度センサー(ADT7410)を参考にします。

00127

また、データベースにデータを格納するプログラムは、PythonでMySQLを操作するを参考にします。
これらのプログラムを組み合わせるだけです。
プログラムは以下のようなものを用意しました。
今回は、一回だけ計測していますが、複数回計測してから平均をとった方がよいです。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import smbus
import datetime
import MySQLdb

if __name__ == "__main__":

    i2c = smbus.SMBus(1)
    address = 0x48

    block = i2c.read_i2c_block_data(address, 0x00, 12)
    temp = (block[0] << 8 | block[1]) >> 3
    if(temp >= 4096):
        temp -= 8192


    connector = MySQLdb.connect(host="localhost", db="logging", user=“user", passwd=“passed", charset="utf8")
    cursor = connector.cursor()

    str_tmp = "%6.2f" % (temp / 16.0)
    sql = u"insert into temperature values(now(), %s)" % str_tmp
    cursor.execute(sql)

    connector.commit()

    cursor.close()
    connector.close()

接続するデータベースへの設定(ユーザ名、パスワード、データベース名)は、自分の環境に合わせてください。
実際にプログラムを実行してみましょう。
現在の気温をデータベースに格納したことを確認します。


決まった時間に気温を記録

上記までで作ったプログラムを定期的には実行するにはcronを使用します。
cronは最小、1分の定期的実行ができますが、ここでは、5分毎に計測するものとします。

00128

Cronの設定ファイルは決まった時間に処理するを参考に以下のように記述します。
温度を測るためにGPIOを使用しますが、GPIOの操作はroot権限でしか行えません。
そのため、Pythonプログラムを自分の環境に合わせてcronを設定する必要があります。
場合によってはroot権限で、cronを設定する必要があります。

*/5 * * * * sudo python /home/hoge/python/temperature.py

グラフを表示するプログラム

データベースから気温を取り出す方法は、PythonでMySQLを操作するを参考にします。
html生成のためには、テンプレートからファイル生成を参考にし、テンプレートエンジンを使います。
あらかじめ、グラフ表示を行うためのhtmlテンプレートを用意して、そこに先ほど取得した気温データを流しこみます。
見た目だけ変えたい場合にも、テンプレートファイルだけを変えればよいので、楽です。

00129

ここでは気温グラフ表示に、Google Chart APIを使用します。Web上のAPIを使えば、グラフ表示は簡単に行うことができます。サンプルを元に、以下のようなグラフ表示用のhtmlテンプレートを使用します。

<html>
  <head>
    <title>Temperature Chart</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Date', 'Temp'],
        {% for record in temp_list %}
          ['{{record.date}}',  {{record.temp}}],
        {% endfor %}
        ]);
        // グラフのオプションを設定
        var options = {
          title: '{{title}}'
        };
        var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>


<div id="chart_div" style="width: 80%; height: 400px;"></div>


  </body>
</html>

テンプレートを用意したあとは、データを流し込みます。
気温データをテンプレートに反映するプログラムは以下のように作成します。

#!/usr/bin/pythonCGI
# -*- coding: utf-8 -*-

from jinja2 import Environment, FileSystemLoader
import MySQLdb
import datetime

def mychart(environ, start_response):

  env = Environment(loader=FileSystemLoader('./', encoding='utf8'))
  tpl = env.get_template('template.html')

  #テンプレートへ挿入するデータの作成
  title = u"Tmperature Chart"

  temp_list = []

  connector = MySQLdb.connect(host="localhost", db="logging", user="user", passwd="passwd", charset="utf8")
  cursor = connector.cursor()

  #sql = "select * from temperature"
  sql = "select * from logging.temperature where DATE_ADD(date, INTERVAL 24 HOUR) > NOW()"
  cursor.execute(sql)
  records = cursor.fetchall()
  for record in records:
    temp_list.append({'date':record[0].strftime("%Y-%m-%d %H:%M"), 'temp':record[1]})
  cursor.close()
  connector.close()

  #テンプレートへ挿入するデータの作成
  title = u"Tmperature Chart"

  #テンプレートへの挿入
  html = tpl.render({'title':title, 'temp_list':temp_list})

  start_response('200 OK', [('Content-Type', 'text/html')])
  return [html.encode('utf-8')]

if __name__ == '__main__':
  from flup.server.fcgi import WSGIServer
  WSGIServer(mychart).run()

接続するデータベースへの設定(ユーザ名、パスワード、データベース名)は、自分の環境に合わせてください。
上記までで、データベースから日時と気温を取り出し、Google Chart APIを使ってグラフを表示するHTMLが完成しました。
次は、上記のプログラムがCGIとして動作するように設定します。


pythonプログラムをcgiとして登録

最後に、上記で作成したプログラムをcgiとして登録します。
Webサーバには、lighttpdを使用し、以下のように登録します。
server.modulesに”mod_fastcgi”,を追加し、fastcgi.server にchart.pyの設定を追加します。

server.modules = (
    "mod_access",
    "mod_alias",
    "mod_compress",
    "mod_redirect",
    "mod_fastcgi",
#       "mod_rewrite",
)
 
server.document-root        = "/var/www"
server.upload-dirs          = ( "/var/cache/lighttpd/uploads" )
server.errorlog             = "/var/log/lighttpd/error.log"
server.pid-file             = "/var/run/lighttpd.pid"
server.username             = "www-data"
server.groupname            = "www-data"
server.port                 = 80
 
index-file.names            = ( "index.php", "index.html", "index.lighttpd.html" )
url.access-deny             = ( "~", ".inc" )
static-file.exclude-extensions = ( ".php", ".pl", ".fcgi" )
 
compress.cache-dir          = "/var/cache/lighttpd/compress/"
compress.filetype           = ( "application/javascript", "text/css", "text/html", "text/plain" )
 
# default listening port for IPv6 falls back to the IPv4 port
include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port
include_shell "/usr/share/lighttpd/create-mime.assign.pl"
include_shell "/usr/share/lighttpd/include-conf-enabled.pl"
 
fastcgi.server = (
    "chart.py" => (
        "python-fcgi" => (
        "socket" => "/tmp/test.python.socket",
        "bin-path" => "/var/www/chart.py",
        "check-local" => "disable",
        "max-procs" => 1)
    )
)

登録が完了したら動作確認を行います。
Raspberrypi にアクセスして、グラフが表示出来ることを確認します。

今回は、気温のみを扱いましたが、湿度や大気圧なども同様に記録して、身の回りの環境を知るのも面白いかと思います。


動作確認

ブラウザからローカルにあるRaspberry Piにアクセスして、グラフが表示できることを確認します。

http://[IPアドレス]/chart.py

このような感じで、Google Chart APIがいい感じのグラフを描いてくれます。
00130

Pocket