ラズパイ+BME280でIoT環境センサー構築(その3)

##概要
Raspberry PiでスイッチサイエンスのBME280モジュールを使用して、温湿度と気圧を測定し、WEBブラウザで確認できるようにする。どうせならグラフ化して表示したい。今回は、PHPのページ作成について記載します。なお、内容については私自身がよく分かっておりません。ヘルプとにらめっこしてとりあえず動いたという程度の内容です。

試行錯誤したけど全部忘れたので、結論だけ書きます。
サンプルコードは、スクリプトを実行して結果を返すだけですが、PHPで表示するために関数化した(のかな？)
そのまま返すのではなく変数に格納して、別スクリプトから読みだしている。
(用語がよくわからない^^;)

##WEBページの構造
/var/www/html/ にphpを配置。ここからスクリプトを実行する。
スクリプトは/home/pi/bme280/に配置、内容は以下。

|ファイル名|内容|
|:--|:--|
|bme280.py|CSVファイルを作成|
|bme280_custom.py|温度、湿度、気圧を返す|
|bme280_temp.py|温度を返す|
|bme280_humid.py|湿度を返す|
|bme280_pres.py|気圧を返す|

一覧表とグラフの両方を見るためにこのようにしました。もっとうまいやり方があるとは思いますが。

/home/pi/bme280/data/ に観測値をcsvファイルとして保存する。csvファイルは日付単位で作成する。

##スクリプトの作成
###1.サンプルコードを修正する
bme280_sample.pyをbme280_custom.py にリネームして以下のように修正しました。
先頭部分は

```bme280_custom.py
先頭部分
(元)
from smbus2 import SMBus
import time

bus_number  = 1
i2c_address = 0x76

bus = SMBus(bus_number)

(修正後)
import smbus
import time
 
bus_number  = 1
i2c_address = 0x76
 
bus = smbus.SMBus(bus_number)

～～中略～～

def readData():
    data = []
    for i in range (0xF7, 0xF7+8):
        data.append(bus.read_byte_data(i2c_address,i))
    pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
    temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
    hum_raw  = (data[6] << 8)  |  data[7]
     
    #compensate_T(temp_raw)
    #compensate_P(pres_raw)
    #compensate_H(hum_raw)
    t = compensate_T(temp_raw)
    p = compensate_P(pres_raw)
    h = compensate_H(hum_raw)
    return p + "," + t + "," + h

def compensate_P(adc_P):
     :
    #print "pressure : %7.2f hPa" % (pressure/100)
    return "%7.2f" % (pressure/100)

def compensate_T(adc_T):
     :
    #print "temp : %-6.2f ℃" % (temperature) 
    return "%.2f" % (temperature) 

def compensate_H(adc_H):
     :
    #print "hum : %6.2f ％" % (var_h)
    return "%.2f" % (var_h)
```
###2.温度のみ返すスクリプトを作成
基本的にはcustomファイルから温度の部分のみを取り出したものです。
ちゃんと作るべきなんだろうけど、tだけ返せばいいわけで、bme280_custom.pyをコピー＆リネームして、下記1行のみ変更。

```bme280_temp.py
(元)
def readData():
     :
    return p + "," + t + "," + h
(修正)
def readData():
     :
    return t
```
###3.湿度のみ返すスクリプトを作成
温度と同じです。
bme280_custom.pyをコピー＆リネームして、下記1行のみ変更。

```bme280_humid.py
(元)
def readData():
     :
    return p + "," + t + "," + h
(修正)
def readData():
     :
    return h
```
###4.気圧のみ返すスクリプトを作成
温度と同じです。
bme280_custom.pyをコピー＆リネームして、下記1行のみ変更。

```bme280_pres.py
(元)
def readData():
     :
    return p + "," + t + "," + h
(修正)
def readData():
     :
    return p
```
###5.CSVファイルに保存するスクリプトを作成
読みだした値をCSVファイルとして保存します。WEBに表示する際に、日付ごとに分けたいので、手っ取り早く日付単位でファイルを作成します。

```bme280.py
#coding: utf-8
 
import bme280_custom
import bme280_temp
import bme280_pres
import bme280_humid
import datetime
import os
 
dir_path = '/home/pi/bme280/data'
 
now = datetime.datetime.now()
filename = now.strftime('%Y%m%d')
label = now.strftime('%H:%M')
date = now.strftime('%Y/%m/%d %H:%M')
csv = bme280_custom.readData()
csv_t = bme280_temp.readData()
csv_p = bme280_pres.readData()
csv_h = bme280_humid.readData()

if not os.path.exists('/home/pi/bme280/data'):
    os.makedirs('/home/pi/bme280/data')
f = open('/home/pi/bme280/data/'+filename+'.csv','a')
f.write("'"+date+"',"+csv+"\n")
f.close()
f = open('/home/pi/bme280/data/'+filename+'_t.csv','a')
f.write("'"+date+"',"+csv_t+"\n")
f.close()
f = open('/home/pi/bme280/data/'+filename+'_p.csv','a')
f.write("'"+date+"',"+csv_p+"\n")
f.close()
f = open('/home/pi/bme280/data/'+filename+'_h.csv','a')
f.write("'"+date+"',"+csv_h+"\n")
f.close()

```
##WEBページの作成
###1.表形式で表示する
記録した温度、湿度、気圧を表形式でまとめて表示する。表の作成はGoogleChartを使用する。

```bme280.php
<?php
$today  = date("Ymd");
$csv_dir  = '/home/pi/bme280/data/';
$csv_file = $today.'.csv';
$grapgh   = '';
if (($handle = fopen($csv_dir.$csv_file, "r")) !== false) {
    while (($line = fgets($handle)) !== false) {
    $grapgh .= '['.rtrim($line).'],'.PHP_EOL;
    }
    fclose($handle);
}else{
    echo 'no data';
}
?>
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
    google.load("visualization", "1", {packages:["table"]});
    google.setOnLoadCallback(drawTable);
 
    function drawTable() {
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'Time');
    data.addColumn('number', 'Pressure[hPa]');
    data.addColumn('number', 'Temperature[℃]');
    data.addColumn('number', 'Humidity[%]');
    data.addRows([
 
<?php echo $grapgh; ?>
 
    ]);
 
      var table = new google.visualization.Table(document.getElementById('table_div'));
      table.draw(data, {showRowNumber: true});
    }
</script>
</head>
<body>
 
<div id="table_div"></div>
 
</body>
</html>
```
###2.グラフで表示する
記録した温度、湿度、気圧をそれぞれをグラフにして表示する。Y軸を複数にして重ねることもできるが、温度と湿度と気圧だと2桁と4桁なので単純に重ねると気圧しか見えなくなり、難しいので3つに分けた。グラフの作成はGoogleChartを使用する。

```bme280-2.php
<?php
$today  = date("Ymd");
$csv_dir  = '/home/pi/bme280/data/';
$temp_file = $today.'_t.csv';
$grapgh_t   = '';
$pres_file = $today.'_p.csv';
$grapgh_p   = '';
$hum_file = $today.'_h.csv';
$grapgh_h   = '';
if (($handle = fopen($csv_dir.$temp_file, "r")) !== false) {
    while (($line = fgets($handle)) !== false) {
    $grapgh_t .= '['.rtrim($line).'],'.PHP_EOL;
    }
    fclose($handle);
}else{
    echo 'no data';
}
if (($handle = fopen($csv_dir.$pres_file, "r")) !== false) {
    while (($line = fgets($handle)) !== false) {
    $grapgh_p .= '['.rtrim($line).'],'.PHP_EOL;
    }
    fclose($handle);
}else{
    echo 'no data';
}
if (($handle = fopen($csv_dir.$hum_file, "r")) !== false) {
    while (($line = fgets($handle)) !== false) {
    $grapgh_h .= '['.rtrim($line).'],'.PHP_EOL;
    }
    fclose($handle);
}else{
    echo 'no data';
}
?>
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
    google.charts.load('current', {packages:['corechart', 'line']});
    google.charts.setOnLoadCallback(drawChart);
 
    function drawChart() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Time');
        data.addColumn('number', 'Temperature[℃]');
        data.addRows([
            <?php echo $grapgh_t; ?>
        ]);

	var options = {
	    title: 'Temprature by BME280(raspberry pi3)'
  	};

        var chart = new google.visualization.LineChart(document.getElementById('chart1'));
        chart.draw(data,options);
    }

    google.charts.load('current', {packages:['corechart', 'line']});
    google.charts.setOnLoadCallback(drawChart2);

    function drawChart2() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Time');
        data.addColumn('number', 'Pressure[hPa]');
        data.addRows([
            <?php echo $grapgh_p; ?>
        ]);

	var options = {
	    title: 'Pressure by BME280(raspberry pi3)'
  	};

        var chart = new google.visualization.LineChart(document.getElementById('chart2'));
        chart.draw(data,options);
    }

    google.charts.load('current', {packages:['corechart', 'line']});
    google.charts.setOnLoadCallback(drawChart3);

    function drawChart3() {
        var data = new google.visualization.DataTable();
        data.addColumn('string', 'Time');
        data.addColumn('number', 'Humid[%]');
        data.addRows([
            <?php echo $grapgh_h; ?>
        ]);

	var options = {
	    title: 'Humid by BME280(raspberry pi3)'
  	};

        var chart = new google.visualization.LineChart(document.getElementById('chart3'));
        chart.draw(data,options);
    }
</script>
</head>
<body>
 
<div id="chart1"></div>
<div id="chart2"></div>
<div id="chart3"></div>

</body>
</html>
```
##WEBの設定と自動実行
###1.ファイルの配置
作成したPHPファイルを/var/www/html/に置きます。
作成したスクリプトファイルを/home/pi/bme280/に置きます。
bme280.pyのパーミッションを755に変更する。

```
sudo chmod 755 bme280.py
```
###2.自動実行の設定
cronを起動する。

```
sudo /etc/init.d/cron start
[ ok ] Starting periodic command scheduler: cron.

sudo apt install -y chkconfig
sudo chkconfig cron
cron on
```
スクリプトを登録する。bme280.pyを実行すると、ほかの4つはこの中で呼ばれるのでbme280.pyのみ登録すればよい。10分ごとにスクリプトを実行する。
初めて登録する場合、エディタの選択肢が出るので好きなものを指定する。

```
crontab -e

最下行に以下を追加。
*/10 * * * * python /home/pi/bme280/bme280.py
```
###3.動作確認
ブラウザで、ラズパイのIPアドレスを表示。
(例)
http://192.168.0.36/bme280.php
![キャプチャ20.JPG](https://qiita-image-store.s3.amazonaws.com/0/276188/a2d010f3-1545-f8b5-c43b-31b30a991ca7.jpeg)
http://192.168.0.36/bme280-2.php
![クリップボード.jpg](https://qiita-image-store.s3.amazonaws.com/0/276188/89e18596-44db-1764-eca1-83c3123bb5b5.jpeg)
グラフはマウスをあてると吹き出しが出る。Google Chartは高性能だった。

##参考
- [第39回「ラズベリーパイで温度・湿度・気圧をまとめて取得！AE-BME280でIC2通信」](https://deviceplus.jp/hobby/raspberrypi_entry_039/)
- [Google Charts](https://developers.google.com/chart/interactive/docs/gallery/linechart)