JR6PUE HOME PAGE

raspberyy piで室温を測定


秋月電子で販売しているraspberyy piで使える温度センサーを使って無線室の温度を測定することにしました。
ただ、測定するだけでは面白くないのでグラフで見れるようにします。
ネット上には、多くの情報があふれているので簡単にできると思ったのが苦労の始まりでした。

初めてなので、ADT7410温度センサーモジュールで挑戦することにしました。

先ずは、準備です。このあたりを見てモジュールに端子を付けて、raspberry piと接続して動作を
確認します。i2c接続設定は、本体で行います。



1.動作確認

pi@rastemp1:~ $ sudo i2cdetect -y 1
    0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

sudo i2cget -y 1 0x48 0x00 w
このコマンドで 0x200b などと表示すればOKです。

2.raspberry pi側に関連ソフトをインストール

(1)関連するソフトのバージョンを記載しておきます。
  下記コマンドで確認できます。

  pi@rasthemo:~ $ javac -version
  javac 1.8.0_65
  pi@rasthemo:~ $ python --version
  Python 2.7.9
  pi@rasthemo:~ $ python3 --version
  Python 3.4.2
  pi@rasthemo:~ $ perl --version  (あとでインストールします。でなくても大丈夫です)
  This is perl 5, version 20, subversion 2 (v5.20.2) built for arm-linux-gnueabihf
  pi@rasthemo:~ $ bash --version
  GNU bash, バージョン 4.3.30(1)-release (arm-unknown-linux-gnueabihf)
  pi@rasthemo:~ $ awk -W version
  mawk 1.3.3 Nov 1996, Copyright (C) Michael D. Brennan
  pi@rasthemo:~ $ uname -a
  Linux rasthemo 4.4.38-v7+ #938 SMP Thu Dec 15 15:22:21 GMT 2016 armv7l GNU/Linux
  pi@rasthemo:~ $ cat /etc/issue
  Raspbian GNU/Linux 8 \n \l
 
(2)apache2をインストール
  sudo apt-get update
  sudo apt-get upgrade
  sudo apt-get install apache2
  インストールが終わったら、ラズベリーパイから以下にアクセスします。
  http://localhost
   アパッチを紹介する表示が出ればOKです
  
  なお、温度を表示したり、グラフを作成するのには、CGIを使いますので
  設定が必要です。
  CGIファイルはデフォルトでは、以下のディレクトリに置くことになっています。
  /usr/lib/cgi-bin/

  @ /etc/apache2/apache2.confで設定
    pi@rasthemo:~ $ sudo vim  /etc/apache2/apache2.conf
    
    ・Global configuratiion内、Server rootのコメントアウトをはずします。
    ServerRoot "/etc/apache2"

    ・cgi, ssiを使用できるようにし、 index.shtml index.cgi index.plをインデックスとして使用できるよう
    最下行に下記を追加します。
    # vim: syntax=apache ts=4 sw=4 sts=4 sr noet
    AddType text/html .shtml
    AddHandler server-parsed .shtml
    AddHandler cgi-script .cgi .pl
    DirectoryIndex index.html index.shtml index.cgi index.pl

   A専用のコマンドを使って Include(SSIの実行)とcgid(CGIの実行)を有効にします。
    $ sudo a2enmod include
    $ sudo a2enmod cgid

   Bcgi ファイルを CGI スクリプトとして実行する
    $ sudo vi /etc/apache2/mods-available/mime.conf
        219行目のコメントアウトをはずす。
        AddHandler cgi-script .cgi

     注:私が迷うだけかもしれませんが、apache2は、/var/www/html/がデフォルトの場所に
     なっています。
     /var/www/html/index.htmlをアドレス表記すると下記のとおりです。
     http://localhost/index.html

     開かないとか、ファイルが無いとか怒られる時は、パーミッションが許可されていなくて
     問題が出る場合もあります。
     その時は、書き込み可能とか所有権を確認してください。

(3)FTPをインストールします。
  ホームページを作成して、apache2にファイルを転送するのにFTPを使用しますので
  定番のvsftpdをインストールします。

    $ sudo apt-get upgrade && sudo apt-get update

    $ sudo apt-get install vsftpd

   設定します。
    $ sudo vi /etc/vsftpd.conf

     (変更箇所のみ記載)
  # ユーザ権限設定
   local_enable=YES #ローカルユーザを有効に(デフォルトはコメントアウト)
   write_enable=YES #書き込み可能に(デフォルトではコメントアウト)
   local_umask=022   #書き込んだ際のパーミッションのマスク(デフォルトではコメントアウト)

   # ASCIIモードの設定
   ascii_upload_enable=YES #アスキーでアップロードを有効(デフォルトではコメントアウト)
   ascii_download_enable=YES #アスキーでダウンロードの有効(デフォルトではコメントアウト)

   # ユーザ権限
   chroot_local_user=YES #ローカルユーザの制限(デフォルトではコメントアウト)
   chroot_list_enable=YES  #リストにより制限を行う(デフォルトではコメントアウト)
   chroot_list_file=/etc/vsftpd.chroot_list #リストのパス

  FTPユーザでファイルをアップロードできるように所有者を変更してください。
  i@rastemp1:/var/www $ ls -l
  drwxr-xr-x 2 root root 4096  1月  8 15:15 html
  i@rastemp1:/var/www $ sudo chown pi html
  @rastemp1:/var/www $ sudo chgrp pi html
  @rastemp1:/var/www $ ls -l
   drwxr-xr-x 2 pi pi 4096  1月  8 15:15 html
 
3.ADT7410で温度を測定します
  このページを参考にしました。細かいところは、この―ページをご覧ください。
  このページの通り、いけばすんなりだったのですがOSやソフトのバージョンが新しくなっているからだと思いますが
  すんなりいきませんでした。どうしても1か所は、原因がわからなかったので別の方法で回避しました。
  
 (1)温度を測定しデータを取得するスプリクト
  $vi /home/pi/tmpget.sh

  #!/bin/sh
  date +"%Y/%m/%d %k:%M" | awk '{printf("%s ",$1 " " $2)}'
  sudo /usr/sbin/i2cget -y 1 0x48 0x00 w | awk '{printf("%.2f\n", (t=("0x"substr($1,5,2)substr($1,3,2)))/128)}'

  @rastemp1:~ $ ls t* -l
   -rw-r--r-- 1 pi pi 178  1月  8 14:56 tmpget.sh
   
   $sudo chmod a+x tmpget.sh
   で実行権をつけます。
   @rastemp1:~ $ ls t* -l
    -rwxr-xr-x 1 pi pi 178  1月  8 14:56 tmpget.sh

   @rasthemo:~ $ /home/pi/tmpget.sh
   2017/01/07 22:29 22.60
   などと、年月日 時間 温度の表示が出ればOKです。

  (2)cronで10分毎に温度を取得します
   crontab -e でcrontabに次の一行を追加します。
   # m h  dom mon dow   command
   */10 * * * * /home/pi/tmpget.sh >> /home/pi/tmpget.log

   エディタがnanoで編集が立ち上がることがあります。
   その時は、ここの解説を見ながら対応してください。私は、nanoは苦手です。(^^;
   http://www.obenri.com/_nano/close_nano.html

  注:スプリクト内にある>>と>の違い
    ・>> 追加
    ・> 上書きです。1か所だけperl上で上手く動作しないコマンドをcron上で>を利用して解決しました。

(2)perlのグラフィックライブラリをインストール
  $ sudo apt-get install libgd-gd2-perl libgd-graph-perl bc

(3)CGIを作ってページに埋め込む
参考にさせていただいたホームページに下記の様に記載されていました。
CGIを利用するのは、初めてなので良くわかりません。とりあえず、日ごろ使っているホームページ作成ソフトで勉強。
...
<FORM method="GET" action="./cgi-bin/adt7410.cgi">
      <p><input type="submit" name="ctmp" value="現在の室温"></p>
      <p><input type="submit" name="draw" value="○○ 時間推移"></p>
</FORM>
...
ホームページ作成ソフトとかあればHTMLタグが分らなくても使えますが、無い場合は、私が作成した
ページをお使いください。
HTML.tar.gzとして関連ファイルを17個置いておきます。HTML.tar.gz
tar zxvf HTML.tar.gzで解凍して/var/www/html/に置いてください。
なお、JR6PUEの表示が出ますので、index.html内で自分のコールサインに変更してください。

(4)温度・グラフ表示用のシェルスプリクトadt7410.cgiを作成

$ sudo vi /usr/lib/cgi-bin/adt7410.cgi

#!/usr/bin/perl
use GD::Graph::lines;
($arg1,$arg2) = split( /&/ ,$ENV{'QUERY_STRING'} );
($name,$value) = split( /=/ , $arg1 );
sub hthead {
   print "Content-Type:text/html\n";
   print "\n";
   print "JR6PUE Archives.\n";
}
if ($name eq "ctmp")
   &hthead;
   open(FILE,"/tmp/tmp.log");
   ($date, $time, $temp) = split /\s+/, <FILE>;
   close (FILE);
print <<"HTML";
<BR>
<H2>
<p>Date = $date</p>
<p>Time = $time</p>
<p>Temp = $temp C</p>
<BR><BR><BR>
HTML
} elsif ($name eq "draw") {
   system("tail -n 288 /home/pi/tmpget.log > /tmp/draw.log");
   open(FILE, "/tmp/draw.log");
   while($line = <FILE>) {
       chomp($line);
       ($d1, $d2, $d3) = split(/\s+/, $line);
       if ($dat1 ne ""){
           $dat1 = $dat1.",".$d1;
           $dat2 = $dat2.",".$d2;
           $dat3 = $dat3.",".$d3;
       } else {
           $dat1 = $d1;
           $dat2 = $d2;
           $dat3 = $d3;
       }
   }
   my @labels = split(/,/, $dat2);
   my @dsheet = split(/,/, $dat3);
   my @data = (\@labels, \@dsheet);
   print "Content-type: image/png;\n\n";
   my $graph = GD::Graph::lines->new(1200,600);
   binmode STDOUT;
   print $graph->plot(\@data)->png;
   close(FILE);
   exit;
}
print <<"RET";
<A href="../index.html"> Back to Top.</A>
RET
exit;


8行目 コールサインを自分用に変更してください。
オリジナルの12行目を削除 
13行目 system("/home/pi/tmpget.sh > /tmp/tmp.cur");
どうしても温度が計測されません。
2017/01/07 14:20となります。

ただし、
$/home/pi/tmpget.sh > /tmp/tmp.curをコマンドレベルと動作させると
2017/01/07 14:20 20.69と動作します。

このためcrontab -e 2行目参照でtmpget.shを使いtmp.logを作成して使用。

# m h  dom mon dow   command
*/10 * * * * /home/pi/tmpget.sh >> /home/pi/tmpget.log
*/01 * * * * /home/pi/tmpget.sh > /tmp/tmp.log

作成したら実行権を付けて下さい。
pi@rastemp1:/usr/lib/cgi-bin $ ls -l
合計 4
-rw-r--r-- 1 root root 1285  1月  8 15:25 adt7410.cgi
pi@rastemp1:/usr/lib/cgi-bin $ sudo chmod a+x adt7410.cgi
pi@rastemp1:/usr/lib/cgi-bin $ ls -l
合計 4
-rwxr-xr-x 1 root root 1285  1月  8 15:25 adt7410.cgi

他に、6時間用などのファイルを作ってください。
訂正箇所は、1か所だけです。
24行目の288(48時間用)を6時間なら36へ変更します。
10分に1回測定していますので1時間に6です。6×6=36となります。
あとは、24時間なら6×24=144ですね。

ファイル名の作成ルール
48時間用 adt7410.cgi
6時間用 adt741006.cgi
12時間用 adt741012.cgi
24時間用 adt741024.cgi

作成方法は、
pi@rastemp1:/usr/lib/cgi-bin $ sudo cp -p adt7410.cgi adt741006.cgi
24行目
   system("tail -n 36 /home/pi/tmpget.log > /tmp/draw.log");
288を36に変更
pi@rasthemo:/usr/lib/cgi-bin $ ls -l
-rwxr-xr-x 1 pi pi        273  1月  7 09:18 adt74.cgi
-rwxr-xr-x 1 pi pi       1285  1月  7 10:49 adt7410.cgi
-rwxr-xr-x 1 pi pi       1284  1月  8 12:22 adt741006.cgi
-rwxr-xr-x 1 pi pi       1284  1月  8 12:13 adt741012.cgi
-rwxr-xr-x 1 pi pi       1285  1月  8 12:23 adt741024.cgi




6時間推移グラフです


(5)Googleチャートでグラフ化します
このページを参考にしました。
ここまでで当初の目的は達成したのですが、もう少しグラフ化が出来ないかと思ってググっているとGoogleチャートを利用して
グラフ化することにしました。ここも参考ページに書かれている通りにうまくいかず、だいぶ苦労しました。
詳細は、参考にしたページをご覧ください。
オリジナルのスプリクトがうまく動作しなくて原因究明に多大な時間がかかりましたが
逆に色々と勉強になりました。

@温度取得スプリクトを作成
$ vi temperature.py

#!/usr/bin/env python

import os
import os.path

# Get temperature from the sensor
hex_temp = os.popen("/usr/sbin/i2cget -y 1 0x48 0x00 w").read()
hex_temp = hex_temp[4:6] + hex_temp[2:4]
dec_temp = int(hex_temp, 16) / 8 * 0.0625

# Print temperature
print round((dec_temp),1)

log_file = '/home/pi/temp_log.txt'
lines = []
if os.path.exists(log_file):
   with open(log_file) as f:
       lines = f.readlines()
       while len(lines) > 20000:
           lines.pop(0)

str = "          [new Date(" + os.popen("date +%Y,").read().rstrip() + os.popen("echo \"$(date +%m) - 1\" | bc").read().rstrip() + os.popen("date +,%d,%H,%M,%S").read().rstrip() + "),  " + str(dec_temp) + "],\n"

lines.append(str)
with open(log_file,'w') as f:
   f.writelines(lines)


2行目の#!/usr/bin/env pythonは、いらないので削除
13行目をround関数を使い四捨五入で表示するように変更。
オリジナルは、int関数で小数点以下を切り捨てています。

temperature.pyに実行権をつけます

$sudo chmod a+x temperature.py
$ ./temperature.py
22.6

温度取得が出来ていることが確認できます。

AHTML出力スクリプトwrite_html.pyを作成します

$ vi write_html.py

#!/usr/bin/env python

import os
import sys

argvs = sys.argv
argc  = len(argvs)
html_path = ''
if(argc == 2):
   html_path = argvs[1] + os.sep

lines = ['']

lines.append("<html>\n")
lines.append("  <head>\n")
#lines.append("    \n")
lines.append('    <script src="http://www.google.com/jsapi" type="text/javascript"></script>\n')
lines.append(" </head>\n")
lines.append(" <body>\n")
lines.append('    <script type="text/javascript">\n')
lines.append("      google.load('visualization', '1', {'packages':['annotatedtimeline']});\n")
lines.append("      google.setOnLoadCallback(drawChart);\n")
lines.append("      function drawChart() {\n")
lines.append("        var data = new google.visualization.DataTable();\n")
lines.append("        data.addColumn('date', 'Date');\n")
lines.append("        data.addColumn('number', 'Temp');\n")
lines.append("        data.addRows([\n")

log_file = '/home/pi/temp_log.txt'
if os.path.exists(log_file):
   with open(log_file) as f:
       lines.extend(f.readlines())

lines.append("        ]);\n")
lines.append("        var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));\n")
lines.append("        chart.draw(data, {displayAnnotations: true});\n")
lines.append("      }\n")
lines.append("    </script>\n")
lines.append("  </head>\n")
lines.append("  <body>\n")
lines.append('    <div id="chart_div" style="height: 240px; width: 700px;"></div>\n')
lines.append("  </body>\n")
lines.append("</html>\n")

with open(html_path + 'indexa.html','w') as f:
   f.writelines(lines)

このスプリクトがうまく動かなくて解決するのに10時間以上はまっていました。(^^;

17行、20行、29行、41行、42行、43行で
オリジナルは、SyntaxError: invalid syntaがでます。

"マークが文章内にあるとエラーが出ることに気づくまで、解決まで数時間を費やしました。
41,42,43行は、1行にまとめています。
グーグルチャートのライブラリーのアドレス等が変更になっていますがオリジナル設定のままでつかえましたので
そのまま流用しています。詳しくは、https://google-developers.appspot.com/chart/interactive/docs/gallery/linechart

また、このスプリクトはホームページ上からを走らせる必要がありますので、オリジナルのままでは不具合が出ます。
オリジナルのindex.htmlを上書きしてしまいます。そこで、45行目の
with open(html_path + 'indexa.html','w') as f:
に記載されているindex.htmlをindexa.htmlに変更します。

$ home/pi/write_html.py
$ ls i*
indexa.html   index.html

indexa.htmlが出来ていればスプリクトは成功です。

B作成した2つのスプリクトを一つにまとめます
 最後は、atd7410.pyというファイルで1つのスプリクトにまとめます
 スプリクトファイルは、crontab -eで30分に一度動作するようにしました。

 $ crontab -e
 で、3行目に追加。

# m h  dom mon dow   command
*/10 * * * * /home/pi/tmpget.sh >> /home/pi/tmpget.log
*/01 * * * * /home/pi/tmpget.sh > /tmp/tmp.log
*/30 * * * * /home/pi/atd7410.py /var/www/html

$ vim atd7410.py
 
#!/usr/bin/env python

import os
import os.path

# Get temperature from the sensor
hex_temp = os.popen("/usr/sbin/i2cget -y 1 0x48 0x00 w").read()
hex_temp = hex_temp[4:6] + hex_temp[2:4]
dec_temp = int(hex_temp, 16) / 8 * 0.0625

# Print temperature
print round((dec_temp),1)

log_file = '/home/pi/temp_log.txt'
lines = []
if os.path.exists(log_file):
   with open(log_file) as f:
       lines = f.readlines()
       while len(lines) > 20000:
           lines.pop(0)

str = "          [new Date(" + os.popen("date +%Y,").read().rstrip() + os.popen("echo \"$(date +%m) - 1\" | bc").read().rstrip() + os.popen("date +,%d,%H,%M,%S").read().rstrip() + "),  " + str(dec_temp) + "],\n"

lines.append(str)
with open(log_file,'w') as f:
   f.writelines(lines)

import os
import sys

argvs = sys.argv
argc  = len(argvs)
html_path = ''
if(argc == 2):
   html_path = argvs[1] + os.sep

lines = ['']

lines.append("<html>\n")
lines.append("  <head>\n")
#lines.append("    \n")
lines.append('    <script src="http://www.google.com/jsapi" type="text/javascript"></script>\n')
lines.append(" </head>\n")
lines.append(" <body>\n")
lines.append('    <script type="text/javascript">\n')
lines.append("      google.load('visualization', '1', {'packages':['annotatedtimeline']});\n")
lines.append("      google.setOnLoadCallback(drawChart);\n")
lines.append("      function drawChart() {\n")
lines.append("        var data = new google.visualization.DataTable();\n")
lines.append("        data.addColumn('date', 'Date');\n")
lines.append("        data.addColumn('number', 'Temp');\n")
lines.append("        data.addRows([\n")

log_file = '/home/pi/temp_log.txt'
if os.path.exists(log_file):
   with open(log_file) as f:
       lines.extend(f.readlines())

lines.append("        ]);\n")
lines.append("        var chart = new google.visualization.AnnotatedTimeLine(document.getElementById('chart_div'));\n")
lines.append("        chart.draw(data, {displayAnnotations: true});\n")
lines.append("      }\n")
lines.append("    </script>\n")
lines.append("  </head>\n")
lines.append("  <body>\n")
lines.append('    <div id="chart_div" style="height: 240px; width: 700px;"></div>\n')
lines.append("  </body>\n")
lines.append("</html>\n")

with open(html_path + 'indexa.html','w') as f:
   f.writelines(lines)

pi@rasthemo:~ $sudo chmod a+x atd7410.py
実行権を付与します。

-rwxr-xr-x 1 pi   pi    2292  1月  7 18:06 atd7410.py

実行すると下記の画面が出てきます。