日常生活の物理|身近で体験できる科学のブログ

日常に関すること、何でもつぶやきます。物理的な視点を加えることが多いかも。

温湿度計作り(6):Raspberry Pi センサデータのグラフ表示

Webサーバーにデータを送信できるようになったので、あとはGUIをどう作るかですが、前回と同じく、インデペンデンスシステムズ横浜のページを参考にさせて頂きました。
http://independence-sys.net/main/?p=3973

こちらのページで紹介されているCanvasJSが実装も簡単で使いやすく、見た目も折れ線グラフで複数パラメータを同時に表示でき、日・週・月毎の表示も簡単に切り替えられるため、そのまま参考にしました。

まず、データベースにアクセスするためのホスト名やパスワードをまとめたファイルを、以下のように用意します。XXXXXXXやYYYYYYYに入れる文字列は、前回記事と同様です。

【Database.php

<?php
function GetDb(){
// mysql:host=ホスト名;dbname=データベース名;charset=文字エンコード
    $dsn = 'mysql:host=XXXXXX.php.xdomain.ne.jp;dbname=YYYYYYYY;charset=utf8';
// データベースのユーザー名
    $usr = 'ZZZZZZZZZ';
// データベースのパスワード
    $passwd = 'AAAAAAAAAA';
    $db = new PDO($dsn, $usr, $passwd);
    $db-> exec('SET NAMES utf8');
    return $db;
}
?>


続いて、MySQLのデータを取得するプログラムを以下のように記述します。

MySQL.php

<?php
require_once 'Database.php';
$target  = isset($_GET['target']) ? $_GET['target'] : 'temp';
$range  = isset($_GET['range']) ? $_GET['range'] : 'Day';
switch ($range){
case 'Average':
case 'Month':
     $dayRange = 30;
     break;
case 'Week':
     $dayRange = 7;
     break;
case 'Day':
     $dayRange = 1;
     break;
default:
     break;
}
$day = date("Y-m-d H:i:s",strtotime("-$dayRange day"));
$qryDate = strtotime("-{$dayRange} day");
$db = GetDb();
switch ($range){
case 'Average':
for ($day=0; $day <$dayRange ; $day++) {
$days = date("Y-m-d", $qryDate);
$sth = $db->prepare("SELECT datetime,avg($target) FROM raspi_sensorvalues where datetime like '$days%' ORDER BY id ASC");
$sth->execute();
        $row = $sth->fetch(PDO::FETCH_ASSOC);
                $jsonData[] = [
               'label'=>substr($row['datetime'],5,5),
               'y'=>(float)round($row['avg('.$target.')'],2)
               ];
        $qryDate = strtotime("+1 day", $qryDate);
     }   
     break;
case 'Month':
case 'Week':
case 'Day':
$sth = $db->prepare("SELECT datetime,$target FROM raspi_sensorvalues where datetime >= '$day' ORDER BY id ASC");
$sth->execute();
        while($row = $sth->fetch(PDO::FETCH_ASSOC)){
                $jsonData[]=[
                'label'=>substr($row['datetime'],5,11),  
                'y'=>(float)$row[$target]
                ];
        }
     break;
}
        header('Content-type: application/json');
        echo json_encode($jsonData); 
?>


最後に表示部分を以下のように記述します。
【Graph01.php

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>センサーデータ</title>
    <script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script type="text/javascript">
    function drawChart(selectspan) {
    var temp_data;
    $.ajax({
    url: "MySQL.php", //データ取得のURL
    type: "GET", //GETメソッドで取得
    dataType: 'json', //処理結果はjson形式で受信
    async: false, //非同期通信
    data: {
           target: 'temp',
           range: selectspan
          },
    success: function(json1) { temp_data = json1;} 
    });
    var hum_data;
    $.ajax({
    url: "MySQL.php",
    dataType: 'json',
    async: false,
    data: {
           target: 'hum',
           range: selectspan
          },
    success: function(json1) { hum_data = json1;}
    });
    var lux_data;
    $.ajax({
    url: "MySQL.php",
    dataType: 'json',
    async: false,
    data: {
           target: 'lux',
           range: selectspan
          },
    success: function(json1) { lux_data = json1;}
    });
    
                var chart = new CanvasJS.Chart(chartContainer01, {
                    title: {text: "温度・湿度・照度データ"},
                    axisX: { labelAngle: -90, labelFontSize: 14, labelFontColor: '#222'},
                    axisY:[{
                            title: "Tempreture",
                            lineColor: "#C24642",
                            tickColor: "#C24642",
                            labelFontColor: "#C24642",
                            titleFontColor: "#C24642",
                            //includeZero: false,
                            suffix: "℃"
                        },
                        {
                            title: "Humidity",
                            lineColor: "#369EAD",
                            tickColor: "#369EAD",
                            labelFontColor: "#369EAD",
                            titleFontColor: "#369EAD",
                            includeZero: false,
                            suffix: "%"
                        }],
                    axisY2: {
                            title: "Illuminance",
                            lineColor: "#FF8C00",
                            tickColor: "#FF8C00",
                            labelFontColor: "#FF8C00",
                            titleFontColor: "#FF8C00",
                            includeZero: false,
                            suffix: "lx"
                        },
               toolTip: {shared: true},
               legend: {cursor: "pointer",itemclick: toggleDataSeries},
               
                    //axisY: { title: "temperature", suffix: '℃',axisYIndex: 0, labelFontSize: 14, labelFontColor: '#222' },
                    theme: "light1",  //デフォルトテーマに設定
                    data: [{
                        type: 'line',  //温度グラフの種類
                        name: "temperature",
                        color: "#C24642",
                        showInLegend: true,
                        axisYIndex: 0,
                        dataPoints: temp_data //表示するデータ
                    },
                    {
                        type: 'line',  //湿度グラフの種類
                        name: "humidity",
                        color: "#369EAD",
                        axisYIndex: 1,
                        showInLegend: true,
                        dataPoints: hum_data //表示するデータ
                    },
                    {
                        type: 'line',  //照度グラフの種類
                        name: "illuminance",
                        color: "#FF8C00",
                        axisYType: "secondary",
                        showInLegend: true,
                        dataPoints: lux_data //表示するデータ
                    }]
                });
    chart.render();
    //マウスカーソル一つに3つの値を表示する設定
    function toggleDataSeries(e) {
    if (typeof (e.dataSeries.visible) === "undefined" || e.dataSeries.visible) {
        e.dataSeries.visible = false;
    } else {
        e.dataSeries.visible = true;
    }
    e.chart.render();
    }
    }
    </script>
  </head>
  <body onload= drawChart('Day')>
      <form>
      <select name="selectspan" onchange="drawChart(this.value)">
        <option value="Day" selected="">1日</option>
        <option value="Week">1週間</option>
        <option value="Month">1ヵ月</option>
        <option value="Average">1ヵ月平均</option>
      </select>
    </form>
    <div id="chartContainer01" style="height: 450px; width: 100%;"></div><br>
  </body>
</html>

この3つのファイルをWebサーバーにアップロードします。
そして、Graph01.phpのページを開くと、以下のようなページがされました!

f:id:dailyphysics:20210117173002p:plain

見た目も綺麗ですし、カーソルを画面に触れるだけで、上図のように各時間帯の数値も確認できます。
これならスマホのブラウザからアクセスするだけで、いつでも家のセンサ情報を確認できますね。スマホのブラウザから開くと、若干見た目が崩れるので、私はPC版サイトから開くようにして、PCと同じビジュアルになるように設定しています。