HOME → 1 Raspberry Pi → 03 作品集 → 

Raspberry Pi 計測した温度をデータベースに格納し、Webブラウザにグラフで表示する

Raspberry Pi 作品集
Python Flask + MySQL + Google Chart
温度を記録し、Webサーバーでグラフ化する
 
Raspberry Pi に接続した温度センサーで温度を定期的に計測し、その結果を「MySQL」のデータベースに記録。
「MySQL」データベースに記録された温度データを読み込んで、「Python Flask Webサーバー」で、ブラウザに「Google Chart」を使ってグラフで表示する。
 
Raspberry Pi - Python 測定した温度をグラフで表示
Raspberry Pi - Python 測定した温度をグラフで表示。
 
以下、ラズベリーパイで温度を記録し、Webサーバーでグラフ化した記録。
 
 

 

スポンサー リンク

 

 
 
 
 
 
1. 全体イメージ
 
センサの記録をグラフ化する、全体イメージ。
 
①.Raspberry Pi に温度センサーを接続し、室内の温度を定期的に計測し、結果を「MySQL」のデータベースに記録する。
②.「Python Flask」によるWebサーバーで、「MySQL」データベースに記録された温度データを読み込んで、HTMLテンプレートに「render」する。
③.HTMLテンプレートでは、「Google Chart」を使ってブラウザにグラフを表示する。
 
プログラム構成。
Raspberry Pi のセンサーで測定した温度を Python で グラフ化
 
ディレクトリーとファイル構成。
/ondo-fdb        (ホーム直下に作成)
├── temperature.py   (温度の測定とデータベースへの書込み)
├── app_05.py     (データの読込と html への render)
└── templates
  └── template.html (Google Chartを使ってグラフを表示)
 
 
参考:
 
 
 
2. データベースの作成
 
データベースには「MySQL」の修正版である「MariaDB」を使用した。
 
①.MariaDB のインストール
 
MariaDB のインストール。
sudo apt update
sudo apt install mariadb-server -y
 
MariaDB のバージョンを確認する。
mariadbd --version
 
MariaDB がインストールされていなければ、「-bash: mariadbd: コマンドが見つかりません」と表示される。
 
セキュリティ設定を行う。
sudo mysql_secure_installation
 

・Enter current password for root (enter for none):
カレントパスワードは空なので、何も押さずにエンターキーを押す。

・Switch to unix_socket authentication [Y/n]
「unix_socket authentication」は無効化したいので、「n」を入力し、エンターキーを押す。

・You already have your root account protected, so you can safely answer 'n'.
rootパスワードを変更したいので、「Y」を入力し、エンターキーを押す。
設定したいrootパスワードを入力し、エンターキーを押す。
入力確認で、設定したいrootパスワードを再度入力し、エンターキーを押す。

・Remove anonymous users? [Y/n]
アノニマスユーザーを削除したいので、「Y」を入力し、エンターキーを押す。

・Disallow root login remotely? [Y/n]
ルートのリモートログインは許可したくないので、「Y」を入力し、エンターキーを押す。

・Remove test database and access to it? [Y/n]
テストデータベースは削除したいので、「Y」を入力し、エンターキーを押す。

・Reload privilege tables now? [Y/n]
権限テーブルをすぐに反映させたいので、「Y」を入力し、エンターキーを押す。

サービスの状態を確認。
systemctl status mariadb
 
 
②.新しいデータベースの作成
 
ルート権限で実行。
mysql -u root -p
 
データベースの作成。(データベース名:ondodb)
MariaDB [(none)]> create database ondodb;
 
作成したデータベースに、ユーザー名( flaskpy)とパスワード(xxxxxxx)を設定。
MariaDB [mysql]> grant all on ondodb.* to flaskpy@localhost identified by'xxxxxxx';
 
作成されたデータベースの確認。
MariaDB [mysql]> show databases;
 
作成されたデータベースの確認
 
データベースの選択。
MariaDB [(none)]> use ondodb;
 
テーブルの作成。(テーブル名:meas_value)
MariaDB [ondodb]> CREATE TABLE meas_value (
nitiji DATETIME NOT NULL,
temp1 DECIMAL(10,2) NOT NULL,
temp2 DECIMAL(10,2) NOT NULL,
temp3 DECIMAL(10,2) NOT NULL,
temp4 DECIMAL(10,2) NOT NULL,
PRIMARY KEY(nitiji)
);
 
nitiji」をデータベースのキー項目に指定。
※:DECIMAL(10,2) を指定しないと、デフォルトでは DECIMAL(10,0) になる。
 
テーブルが作成できているか確認。
MariaDB [ondodb]> show tables;
 
テーブルが作成できているか確認
 
作成したテーブルの中身を確認。
MariaDB [ondodb]> describe meas_value;
 
作成したテーブルの中身を確認
 
 
 
3. temperature.py:温度測定とDB書込みプログラム
 
温度センサーで室温を計測し、その結果を「MySQL」のデータベースに記録するプログラム。(センサー:DHT22 温度湿度センサモジュール x 4個)
#!/usr/bin/python
# -*- coding: utf-8 -*

from time import sleep
import datetime #日付ライブラリ読み込み
import Adafruit_DHT #温度センサーライブラリ読み込み
import MySQLdb #DBライブラリの読み込み

# DHT22センサーから温度と湿度を読み取る関数
def read_dht22(pin):
    sensor = Adafruit_DHT.DHT22 # センサーの種類
    humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
    return humidity, temperature

# GPIOピン番号
pin1 = 17 # GPIOポート番号 = 接続するピン番号 11
pin2 = 27 # GPIOポート番号 = 接続するピン番号 13
pin3 = 4 # GPIOポート番号 = 接続するピン番号 7
pin4 = 26 # GPIOポート番号 = 接続するピン番号 37

##---------------------------------------------------------------------------------------

#●日付時刻情報の取得--------------------------------------------------------------------

dtime = datetime.datetime.now() #日付、日時の取得
date = dtime.strftime('%Y-%m-%d') #日付の整形 yyyy-mm-dd
jikok = dtime.strftime('%H:%M') #時間の整形 hh:mm
dayjikoku = dtime.strftime('%Y-%m-%d %H:%M:%S')

#●2つのセンサーから温度と湿度を読み取る--------------------------------------------------------------

humidity1, temperature1 = read_dht22(pin1)
humidity2, temperature2 = read_dht22(pin2)
humidity3, temperature3 = read_dht22(pin3) #センサー No-3 外側
humidity4, temperature4 = read_dht22(pin4) #センサー No-4 室内

#humidityに湿度を代入
humidity1 = "{:.2f}" . format(humidity1) #湿度(小数点第2位まで)
humidity2 = "{:.2f}" . format(humidity2) #湿度(小数点第2位まで)
humidity3 = "{:.2f}" . format(humidity3) #湿度(小数点第2位まで)
humidity4 = "{:.2f}" . format(humidity4) #湿度(小数点第2位まで)

#temperatureに気温を代入
temperature1 = "{:.2f}" . format(temperature1) #気温(小数点第2位まで)
temperature2 = "{:.2f}" . format(temperature2) #気温(小数点第2位まで)
temperature3 = "{:.2f}" . format(temperature3) #気温(小数点第2位まで)
temperature4 = "{:.2f}" . format(temperature4) #気温(小数点第2位まで)

#●DBに書き込む-------------------------------------------------------------------------
# MySQL接続
connector = MySQLdb.connect(
	host = "localhost",
	db = "ondodb",
	user = "flaskpy",
	passwd = "dht22x4",
# テーブル内部で日本語を扱うために追加
	charset = "utf8"
)

# カーソル取得
cursor = connector.cursor()

# SQLクエリ実行(データ追加)
sql = "insert into meas_value (nitiji, temp1, temp2, temp3, temp4) VALUES (%s, %s, %s, %s, %s)"
val = (dayjikoku, temperature4, temperature1,temperature2,temperature3)
cursor.execute(sql, val)

connector.commit()

# カーソル終了
cursor.close()
# MySQL切断
connector.close()

#●DB書込み内容の表示--------------------------------------------------------------------------

print (
	dayjikoku,
	temperature4,
	temperature1,
	temperature2,
	temperature3
)

##---------------------------------------------------------------------------------------
 
このプログラムでのポイント。
sql = "insert into meas_value (nitiji, temp1, temp2, temp3, temp4) VALUES (%s, %s, %s, %s, %s)" 
val = (dayjikoku, temperature4, temperature1,temperature2,temperature3) 
cursor.execute(sql, val)
 
①.sqlでテーブル名【meas_value】とカラム名(nitiji, temp1,・・・)を指定して、VALUES でカラムのデータ型を指定。
②.valで書き込むデータ(dayjikoku, temperature4,・・・)を指定。
①.'sql' コードの中で、「 VALUES」に値のプレースホルダーとして '%s' を使用している。
 Python の MySQL Connector では (文字列、整数、日付などの) すべてのデータ型に '%s' を使用する。
②.データベースに書き込む値は、【val】で指定した。
 
 
定期的に計測するために「cron」で、温度の計測とDBへの書込みを「10分間隔」で実行するように設定。
crontab -e
*/10 * * * * python3 /home/yaopi/ondo-fdb/temperature.py
 
★Cronの起動、再起動、停止、ステータス確認コマンド。
Cronの起動
sudo /etc/init.d/cron start
Cronの再起動
sudo /etc/init.d/cron restart
Cronの停止
sudo /etc/init.d/cron stop
Cronのステータス確認
sudo /etc/init.d/cron status
 
データの挿入を確認する。
MariaDB [mydb]> SELECT * FROM meas_value;
 
データの挿入を確認する
 
 
 
4. app_05.py:FlaskによるWebアプリ
 
「Python Flask」によるWebサーバーで、「MySQL」データベースから気温データを読み込んで、HTMLテンプレートに「render」するプログラム。
# app.py
# -*- coding: utf-8 -*-

from flask import Flask, render_template
import MySQLdb
import datetime

# Flaskインスタンス作成
app = Flask(__name__)

@app.route('/')
def index():

	# 2次元リストを定義
	temp_list = []

	# MySQLに接続
	connector = MySQLdb.connect(
		host = "localhost",
		db = "ondodb",
		user = "flaskpy",
		passwd = "dht22x4",
	# テーブル内部で日本語を扱うために追加
		charset = "utf8"
	)

	# カーソル取得
	cursor = connector.cursor()

	# SQLクエリ実行(データの読込)
	sql = "select * from meas_value where DATE_ADD(nitiji, INTERVAL 24 HOUR) > NOW()"
	cursor.execute(sql)

	# 結果を取得し、2次元リストの形式に変換
	records = cursor.fetchall()
	for record in records:
		temp_list.append(
		{'nitiji':record[0].strftime("%Y-%m-%d %H:%M"),
		 'temp1':record[1],
		 'temp2':record[2],
		 'temp3':record[3],
		 'temp4':record[4]}
		)

	# データベースとの接続を閉じる
	cursor.close()
	connector.close()

	#テンプレートへ挿入するデータの作成
	title = "Raspberry Pi で測定した温度の推移(10min x 24H)グラフ"

	return render_template('template.html', title=title, temp_list=temp_list)

if __name__ == '__main__':
    app.run("0.0.0.0",debug=True)
 
グラフに表示する温度データの期間を、データベースのキーである「nitiji」で、「現在時刻より【24時間】以内」に限定した。
sql = "select * from meas_value where DATE_ADD(nitiji, INTERVAL 24 HOUR) > NOW()" 
SELECT構文でのWHERE句。
「nitiji」に対して24時間を加算し、現在時刻より大きい値のレコードを抽出。
 
読み込んだレコードの内容を、カラム名毎に2次元の【temp_list】に格納。
	for record in records:
		temp_list.append(
		{'nitiji':record[0].strftime("%Y-%m-%d %H:%M"),
		 'temp1':record[1],
		 'temp2':record[2],
		 'temp3':record[3],
		 'temp4':record[4]}
		)
 
HTMLテンプレートへの「render」は、【title】とレコードの2次元リストが入った【temp_list】。
return render_template('template.html', title=title, temp_list=temp_list)
 
 
 
5. template.html:温度をグラフで表示するHTML
 
「Google Chart」を使って、温度をグラフで表示するHTML。
<html>
  <head>
    <title>Temperature Chart</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8" />
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.load("visualization", "1", {packages:["corechart"]});
      google.setOnLoadCallback(drawChart);
      function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Date', '室内', 'カーテン', '内窓', '窓際'],
        {% for record in temp_list %}
          ['{{record.nitiji}}',  {{record.temp1}},  {{record.temp2}},  {{record.temp3}},  {{record.temp4}}],
        {% endfor %}
        ]);
        // グラフのオプションを設定
        var options = {
		title: '{{title}}',
			titleTextStyle: {
        	        color: '#444',    // タイトルの文字の色を設定
                	fontSize: 24      // タイトルの文字のサイズを設定
			},
		fontSize: 14,     // グラフ内の文字サイズを設定
		vAxis: {
                title: '温度',   // 縦軸のタイトルを設定
                maxValue: 35     // 縦軸の最大値を40に設定
                },
		colors: ['#FF0000', '#ffa500', '#008000', '#0000FF']
        };
        var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
        chart.draw(data, options);
      }
    </script>
  </head>
  <body>
 
  <div style="text-align:center;"> 
  <div id="chart_div" style="width: 100%; height: 500px;"></div>
  <br />
  <hr style="height: 6px; width: 900px; background-color: blue;">
  <input style="width:100px;height:50px; font-size: 200%;" type="button" value="更新" onclick="location.reload()">
  </div>

  </body>
</html>
 
「Google Chart」で表示する項目とその値の設定。
function drawChart() {
        var data = google.visualization.arrayToDataTable([
          ['Date', '室内', 'カーテン', '内窓', '窓際'],
        {% for record in temp_list %}
          ['{{record.nitiji}}',  {{record.temp1}},  {{record.temp2}},  {{record.temp3}},  {{record.temp4}}],
        {% endfor %}
        ]);
 
 ['Date', '室内', 'カーテン', '内窓', '窓際'],:グラフに表示する項目名を指定。
 
['{{record.nitiji}}', {{record.temp1}}, ・・・],:表示する値を設定。
{{record.nnnnn}}は、render」される【temp_list】のカラム名に合わせる。
 
グラフのカスタマイズは、「 var options = { , , , };」に「,」で区切って記述する。
// グラフのオプションを設定
        var options = {
		title: '{{title}}',
			titleTextStyle: {
        	        color: '#444',    // タイトルの文字の色を設定
                	fontSize: 24      // タイトルの文字のサイズを設定
			},
		fontSize: 14,     // グラフ内の文字サイズを設定
		vAxis: {
                title: '温度',   // 縦軸のタイトルを設定
                maxValue: 35     // 縦軸の最大値を40に設定
                },
		colors: ['#FF0000', '#ffa500', '#008000', '#0000FF']
        };
 
画面の下部に「更新」ボタンを設置した。
<input style="width:100px;height:50px; font-size: 200%;" type="button" value="更新" onclick="location.reload()">
 
 
 
6. 実行結果:温度のグラフ表示
 
メインルーチンの「main.py」を実行する。
cd ~/ondo
python3 app_05.py
 
Web サーバーが起動すると、
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
と、表示される。
 
パソコンから、Raspberry Pi のIPアドレス(固定アドレスにしておけば便利)
http://192.168.11.113:5000/」にアクセスする。
 
ブラウザに表示された温度の推移グラフ。
ブラウザに表示された温度の推移グラフ
 
ターミナルなどから SSH 接続で Python を実行している場合,SSH 接続を切断するとプログラムも止まってしまう。
 
SSH で Flask アプリを起動した後、セッション終了後も起動し続ける方法。
nohup python3 app_05.py &
 
SSH で Flask アプリを起動した後、セッション終了後も起動し続ける方法
 
nohupをつけてコマンドを実行した際、カレントディレクトリに nohup.out というファイルが出力される。
 
nohup.out の内容を見る。
sudo nano ondo-fdb/nohup.out
 
 
nohupで起動したバックグラウンドのプロセスを止めるには、
psコマンドでプロセスIDを調べる。
ps -x
 
psコマンドでプロセスIDを調べる
 
killコマンドを用いて調べたプロセスIDを中断。
kill 16161
 
 
以上。
(2024.01.20)
 

 

スポンサー リンク

 

             

 

 

 

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください