Raspberry Pi 作品集
Python Flask + MySQL + Google Chart
温度を記録し、Webサーバーでグラフ化する
Python Flask + MySQL + Google Chart
温度を記録し、Webサーバーでグラフ化する
Raspberry Pi に接続した温度センサーで温度を定期的に計測し、その結果を「MySQL」のデータベースに記録。
「MySQL」データベースに記録された温度データを読み込んで、「Python Flask Webサーバー」で、ブラウザに「Google Chart」を使ってグラフで表示する。
「MySQL」データベースに記録された温度データを読み込んで、「Python Flask Webサーバー」で、ブラウザに「Google Chart」を使ってグラフで表示する。
Raspberry Pi - Python 測定した温度をグラフで表示。
以下、ラズベリーパイで温度を記録し、Webサーバーでグラフ化した記録。
スポンサー リンク
目 次
1. 全体イメージ
センサの記録をグラフ化する、全体イメージ。
①.Raspberry Pi に温度センサーを接続し、室内の温度を定期的に計測し、結果を「MySQL」のデータベースに記録する。
②.「Python Flask」によるWebサーバーで、「MySQL」データベースに記録された温度データを読み込んで、HTMLテンプレートに「render」する。
③.HTMLテンプレートでは、「Google Chart」を使ってブラウザにグラフを表示する。
②.「Python Flask」によるWebサーバーで、「MySQL」データベースに記録された温度データを読み込んで、HTMLテンプレートに「render」する。
③.HTMLテンプレートでは、「Google Chart」を使ってブラウザにグラフを表示する。
ディレクトリーとファイル構成。
/ondo-fdb (ホーム直下に作成)
├── temperature.py (温度の測定とデータベースへの書込み)
├── app_05.py (データの読込と html への render)
└── templates
└── template.html (Google Chartを使ってグラフを表示)
/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
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;
MariaDB [(none)]> create database ondodb;
作成したデータベースに、ユーザー名( flaskpy)とパスワード(xxxxxxx)を設定。
MariaDB [mysql]> grant all on ondodb.* to flaskpy@localhost identified by'xxxxxxx';
MariaDB [mysql]> grant all on ondodb.* to flaskpy@localhost identified by'xxxxxxx';
作成されたデータベースの確認。
MariaDB [mysql]> show databases;
MariaDB [mysql]> show databases;
データベースの選択。
MariaDB [(none)]> use ondodb;
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)
);
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) になる。
※:DECIMAL(10,2) を指定しないと、デフォルトでは DECIMAL(10,0) になる。
テーブルが作成できているか確認。
MariaDB [ondodb]> show tables;
MariaDB [ondodb]> show tables;
作成したテーブルの中身を確認。
MariaDB [ondodb]> describe meas_value;
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,・・・)を指定。
②.valで書き込むデータ(dayjikoku, temperature4,・・・)を指定。
①.'sql' コードの中で、「 VALUES」に値のプレースホルダーとして '%s' を使用している。
Python の MySQL Connector では (文字列、整数、日付などの) すべてのデータ型に '%s' を使用する。
②.データベースに書き込む値は、【val】で指定した。
Python の MySQL Connector では (文字列、整数、日付などの) すべてのデータ型に '%s' を使用する。
②.データベースに書き込む値は、【val】で指定した。
定期的に計測するために「cron」で、温度の計測とDBへの書込みを「10分間隔」で実行するように設定。
crontab -e
*/10 * * * * python3 /home/yaopi/ondo-fdb/temperature.py
*/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
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;
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時間を加算し、現在時刻より大きい値のレコードを抽出。
「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】のカラム名に合わせる。
{{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
python3 app_05.py
Web サーバーが起動すると、
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
と、表示される。
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
と、表示される。
パソコンから、Raspberry Pi のIPアドレス(固定アドレスにしておけば便利)
「http://192.168.11.113:5000/」にアクセスする。
「http://192.168.11.113:5000/」にアクセスする。
ターミナルなどから SSH 接続で Python を実行している場合,SSH 接続を切断するとプログラムも止まってしまう。
SSH で Flask アプリを起動した後、セッション終了後も起動し続ける方法。
nohup python3 app_05.py &
nohupをつけてコマンドを実行した際、カレントディレクトリに nohup.out というファイルが出力される。
nohup.out の内容を見る。
sudo nano ondo-fdb/nohup.out
nohupで起動したバックグラウンドのプロセスを止めるには、
psコマンドでプロセスIDを調べる。
psコマンドでプロセスIDを調べる。
ps -x
killコマンドを用いて調べたプロセスIDを中断。
kill 16161
以上。
(2024.01.20)
(2024.01.20)
スポンサー リンク