目次
今回は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;
}
})
}