Raspberry Pi編 第5回 事務所の温度をブラウザにグラフ表示してみる

今回はRaspberyPIに接続した温度センサーの結果をグラフ表示してみます。
マイコン学習の最終形はたぶんIOTなので、センサーの結果をサーバー側で処理する技術を検証します。
なお、PHP及びグラフ表示部分については、「センサーでできるおもしろまじめ電子工作」を参考にさせていただきました。

センサーサーバー連携図

今回作成したシステムの概念図が以下のとおりです。PHPやChart.jsは初めてだったので、試行錯誤でした。
データの付け込みやデータからの取り出しもPHPでやればよかったのかもしれませんが、よくわからなかった
ので、完成させることを優先して、慣れ親しんだRAILSの力を借りました

GrovePi+の準備

温度センサーは今回、GrovePi+という拡張ボードを使用しました。ブレッドボードで線をつなぐのと違って
がっちりはまっているので、安心感があります。RaspberyPIにGrovePi+を上からかぶせて、GrovePi+の端子
に温度センサーをつなぎました(写真の右上の線でつながれているのが温度センサー)

ページトップ

RaspberyPI側の準備

(1)RaspberyPI側のプログラムをpythonで作成します。取得した温度をRailsで作成したデータ保存APIを呼びます。

 sensor.py

import urllib
import requests
import sys
from grovepi import *
dht_sensor_port = 2
dht_sensor_type = 1# データの取得
[ temp, hum] = dht(dht_sensor_port, dht_sensor_type)

API_URL="(サーバのURL)"
args = sys.argv
kbn = "0"
if len(args) == 2:
  kbn = args[1]

# データの送信
response = requests.get(API_URL,params="data=" + kbn + "," + str(temp), verify=False)

(2)cronの設定を行い、時間起動でpythonプログラムを実行します。(今回は1時間置きに実行)

 cronの設定内容

00 00 * * * python /home/pi/Desktop/sensor.py 0
00 01 * * * python /home/pi/Desktop/sensor.py 1
00 02 * * * python /home/pi/Desktop/sensor.py 2
00 03 * * * python /home/pi/Desktop/sensor.py 3
00 04 * * * python /home/pi/Desktop/sensor.py 4
00 05 * * * python /home/pi/Desktop/sensor.py 5
00 06 * * * python /home/pi/Desktop/sensor.py 6
00 07 * * * python /home/pi/Desktop/sensor.py 7
00 08 * * * python /home/pi/Desktop/sensor.py 8
00 09 * * * python /home/pi/Desktop/sensor.py 9
00 10 * * * python /home/pi/Desktop/sensor.py 10
00 11 * * * python /home/pi/Desktop/sensor.py 11
00 12 * * * python /home/pi/Desktop/sensor.py 12

Rails側の準備

(1)Rails側のプログラムを作成します。Rails5ではAPIを作成する処理が標準で提供されたので、もっとスマートに
作成できるかもしれませんが、今回はとりあえずセンサーの結果をブラウザにグラフ表示するのが目的なので、
細かいことは目をつぶることにします。

 data_controller.rb

class DataController < ApplicationController
  # 呼び出し方 http://xxxxx/data/set?data="1,25.0"
  # パラメタ 1,25.0 時刻区分,温度
  # テストでの呼び出し方 curl xxxxx/data/set?data="1,25.0"
  def set
    begin
      data = params["data"].split(',')
      sensor = Sensor.where(measure_date: Date.today, div: data[0]).first
      if sensor.blank?
        sensor = Sensor.new
        sensor.measure_date = Date.today
        sensor.div = data[0]
      end
      sensor.temperature = data[1].to_f
      sensor.save!
      render text: "OK"
      rescue => e
        logger.error e
        logger.error e.backtrace.join("\n")
        render text: "NG"
      end
    end
end

(2)データの取り出しはRails標準の機能を使います。
※.json.jbuilderファイルを用意することで、(サーバURL)/sensors.jsonでjsonデータを取得できます。

 sensors_controller

class SensorsController < ApplicationController
  def index
    @sensors = Sensor.where(measure_date: Date.today)
  end
end

 index.json.jpbuilder

json.array! @sensors, partial: 'sensors/sensor', as: :sensor

 _sensor.json.jbuilder

json.extract! sensor, :measure_date, :div, :temperature

PHPの準備

PHPを作成します。PHPの機能としては以下のとおりです。
①RAILS APIの呼び出し(curlを使用)
②取得したjsonを分解して、csvデータを作成(カンマ区切りで、1データの終わり毎に改行)

 sensorGet.php

<?php
$base_url = '(サーバURL)/sensors.json';
$tag = 'PHP';$curl = curl_init();curl_setopt($curl, CURLOPT_URL, $base_url);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);

$response = curl_exec($curl);
$result = json_decode($response, true);

if (curl_errno($curl) != 0) {
  print('curl error:[' . curl_errno($curl) .'] '. curl_error($curl));
}

curl_close($curl);

$return = "";

for($i = 0; $i < count($result); ++$i) { 
  $return = $return . $result[$i]["div"] . "," . $result[$i]["temperature"] . "\n"; 
} 
$filename = 'sensorLog.txt'; 
file_put_contents($filename, $return); 
echo file_get_contents("sensorLog.txt"); 
?>

HTML/JSの準備

(1)グラフ表示用のHTMLを作成します。

 index.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="robots" content="noindex">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>事務所現在温度</title>
  <link rel="stylesheet" href="css/normalize.css" />
  <link rel="stylesheet" href="css/index.css" />
  <script src="js/jquery-1.11.3.min.js"></script>
  <script src="js/Chart.min.js"></script>
  <script defer src="js/index.js"></script>
</head>
<body>
  <!-- グラフ表示領域 -->
  <canvas id="chart"></canvas>
</body>
</html>

(2)グラフ表示用のJavaScript

 index.js

// PHPのURL
var PHP_URL = "sensorGet.php";
// センサーの値
var sensorValue = 0;
// センサーの時間
var sensorTime = 99;

// サーバーにアクセス中かどうか
var isAjax = false;

// canvas要素の設定
var canvas = document.getElementById("chart");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
var context = canvas.getContext("2d");

// 線の情報
var data = {
  // ラベル
  labels: [],
  datasets: [
  {
  data : [],
  // 塗りの色
  fillColor: "rgba(0,0,220,0)",
  // 線の色
  strokeColor: "rgba(0,0,220,1)"
  }
]
};

// グラフの描画設定
var options = {
  // アニメーションの速さ
  animationSteps: 1,
  // 線をベジェ曲線で滑らかにするかどうか
  bezierCurve: false,
  // 目盛を自分で設定する
  scaleOverride: true,
  // Y軸の目盛の数
  scaleSteps: 7,
  // Y軸の1目盛の大きさ
  scaleStepWidth: 5,
  // Y軸の最小値
  scaleStartValue: -5,
  // 目盛の色
  scaleLineColor: "#fff",
  // 目盛の線の幅
  scaleLineWidth: 1,
  // グリッドを表示するかどうか
  scaleShowGridLines: true,
  // グリッドラインの色
  scaleGridLineColor: "#222",
  // グリッドラインの幅
  scaleGridLineWidth: 1,
  // Y軸方向のグリッドを表示するかどうか
  scaleShowVerticalLines: false
};

var labels = ["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"];

// 折れ線グラフをインスタンス化
var chart = new Chart(context).Line(data, options);

// サーバーへアクセス中でなければ
if(!isAjax) getSensorValue(chart);

// PHPからセンサーの値を取得し、描画します
function getSensorValue() {
  // フラグをtrue
  isAjax = true;

  $.ajax({
    url: PHP_URL + "?p=" + new Date().getTime(),
    type: "post",
    dataType: "text",
    success: function(value) {
    var tempArray = value.split("\n");

    for(var i = 0; i < tempArray.length; i++){
      if (tempArray[i] != ""){
        var dataArray = new Array();
        dataArray = tempArray[i].split(",");
        sensorTime = dataArray[0];
        sensorValue = dataArray[1];
        chart.addData([sensorValue], labels[i]);
      }
    }
    // フラグをfalse
    isAjax = false;
    },
    error: function(){
      console.log("センサーの値を取得できませんでした。");
      isAjax = false;
    }
  })
}

動作確認

ブラウザで確認します

13時で温度が下がったのでは、部屋が暑くなってきたので、窓を開けたせいですね。今回このシステム?
を作って感じたのは、自分の基礎知識のなさですね。JQUERYやPHPやWEB API呼び出しなどなど、、
IOTのできる人って、センサーからサーバーの知識からサーバ系言語まで、多種多様な知識をお持ち
なのでしょうか、、、


ページトップ