Raspberry Pi 作品集
Python + socket + MariaDB
温度データを Wi-Fiで送受信し データベースに保存
Python + socket + MariaDB
温度データを Wi-Fiで送受信し データベースに保存
クライアントとなる Raspberry Pi(送信側)とサーバーとなる Raspberry Pi(受信側)の「2台」を用意し、「Wi-Fi(socket)」を使ってデータを送受信し、サーバー側では、受信したデータをデータベース(MariaDB)に蓄積する。
サーバーとなる Raspberry Pi(受信側)のメッセージ。
以下、 Raspberry Piで 温度データを Wi-Fiで送受信し データベースに保存する「Python 」を作成した記録。
スポンサー リンク
目 次
1. 全体イメージと稼働環境
Raspberry Pi を2台用意し、クライアントとなる Raspberry Pi(送信側)から
サーバーとなる Raspberry Pi(受信側)に、「Wi-Fi(socket)」を使ってデータを送信し、サーバー側の Raspberry Pi で受信したデータをデータベース(MariaDB)に蓄積する。
サーバーとなる Raspberry Pi(受信側)に、「Wi-Fi(socket)」を使ってデータを送信し、サーバー側の Raspberry Pi で受信したデータをデータベース(MariaDB)に蓄積する。
送信側のRaspberry Piと使用した温度センサー 。
Raspberry Pi 2 Model B Rev 1.1
DHT22 温度湿度センサモジュール:AM2302チップ付き x 4個
DHT22 温度湿度センサモジュール:AM2302チップ付き x 4個
受信側のRaspberry Piと使用したデータベース。
Raspberry Pi 3 Model B Rev 1.2
MariaDB Ver 10.5.21
MariaDB Ver 10.5.21
Raspberry Pi OS と Pythonのバージョン。
cat /etc/os-releasese
NAME="Raspbian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
NAME="Raspbian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
Python 3.9.2
2. Pythonでの TCP/IP通信のベースプログラム
ChatGPT で検索すると下記のコードが表示され、このままコピペで問題なく動作した。
※:修正必要箇所:サーバーのIPアドレスとポート番号。
クライアントスクリプト
import socket
# サーバーのIPアドレスとポート
server_ip = "サーバーのIPアドレス"
server_port = 12345
# ソケットを作成
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# サーバーに接続
client_socket.connect((server_ip, server_port))
print(f"サーバー {server_ip}:{server_port} に接続しました。")
# 送信するデータ
data_to_send = "Hello, server!"
# データをサーバーに送信
client_socket.send(data_to_send.encode('utf-8'))
# ソケットを閉じる
client_socket.close()
サーバースクリプト
import socket
# サーバーのIPアドレスとポート
server_ip = "0.0.0.0" # 0.0.0.0はすべてのネットワークインターフェースを指します
server_port = 12345
# ソケットを作成
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# ソケットを指定のIPアドレスとポートにバインド
server_socket.bind((server_ip, server_port))
# 接続待機
server_socket.listen(1)
print(f"サーバーが {server_ip}:{server_port} で待機中...")
# クライアントからの接続を待機
client_socket, client_address = server_socket.accept()
print(f"クライアント {client_address} が接続しました。")
# データの受信と表示
while True:
data = client_socket.recv(1024)
if not data:
break
print(f"受信したデータ: {data.decode('utf-8')}")
# ソケットを閉じる
client_socket.close()
server_socket.close()
3. 複数のセンサーでデータを計測し送信するPythonプログラム
DHT22センサー x4個から、温度と湿度を読み取り、計測日時と4か所の測定温度を送信する Python プログラム。
#!/usr/bin/python
# -*- coding: utf-8 -*
import datetime #日付ライブラリ読み込み
import Adafruit_DHT #温度センサーライブラリ読み込み
import socket
import json
##--------------------------------------------------------------------------
# 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位まで)
##--------------------------------------------------------------------------
# サーバーのIPアドレスとポート
server_ip = "192.168.11.112"
server_port = 5000
# ソケットを作成
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# サーバーに接続
client_socket.connect((server_ip, server_port))
print(f"サーバー {server_ip}:{server_port} に接続しました。")
##--------------------------------------------------------------------------
# 送信するデータ
data = {'1':dayjikoku, '2':temperature4, '3':temperature1, '4':temperature2, '5':temperature3}
data_to_send = json.dumps(data)
# データをサーバーに送信
client_socket.send(data_to_send.encode('utf-8'))
# ソケットを閉じる
client_socket.close()
# 送信したデータの表示----------------------------------------------------------
print (
data_to_send
)
##--------------------------------------------------------------------------
このプログラムでのポイント。
複数の項目を送信するので、データ『data』を「辞書型(dict)」にする。
しかし、データの送信は「文字列型(str)」でしか行えない。
そこで、送信側では『json.dumps』を使って、dictからstrに変換して送信。
しかし、データの送信は「文字列型(str)」でしか行えない。
そこで、送信側では『json.dumps』を使って、dictからstrに変換して送信。
# 送信するデータ
data = {'1':dayjikoku, '2':temperature4, '3':temperature1, '4':temperature2, '5':temperature3}
data_to_send = json.dumps(data)
送信したデータ。
{"1": "2024-01-24 13:27:56", "2": "22.50", "3": "19.90", "4": "14.40", "5": "11.30"}
「ConnectionRefusedError: [Errno 111] Connection refused」
connectメソッドで、相手のIPアドレスを指定した所で例外が発生してアプリケーションが落ちる。
connectメソッドで、相手のIPアドレスを指定した所で例外が発生してアプリケーションが落ちる。
※:定期的に計測するために「cron」で、温度の計測とサーバーへの送信を「10分間隔」で実行するように設定。
4. 複数のデータを受信しデータベースに記録するPythonプログラム
複数のデータを受信し、データベース(MariaDB)に記録するサーバー側の Pythonプログラム。
#!/usr/bin/python
# -*- coding: utf-8 -*
import socket
import datetime #日付ライブラリ読み込み
import json
import MySQLdb #DBライブラリの読み込み
def start_server():
# サーバーのIPアドレスとポート
server_ip = "192.168.11.112"
server_port = 5000
# ソケットを作成
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# ソケットを指定のIPアドレスとポートにバインド
server_socket.bind((server_ip, server_port))
# 接続待機
server_socket.listen(1) # 同時に接続できるクライアントの数
print(f"サーバーが {server_ip}:{server_port} で待機中...")
my_dict = {}
# データの受信と表示
while True:
# クライアントからの接続を待機
client_socket, client_address = server_socket.accept()
print(f"クライアント {client_address} が接続しました。")
data = client_socket.recv(1024) # 最大1024バイトを受け入れる
if not data:
break
print(f"受信したデータ: {data.decode('utf-8')}")
my_dict = json.loads(data.decode('utf-8'))
print(my_dict)
# 各要素を取り出す
value_1 = my_dict['1']
value_2 = my_dict["2"]
value_3 = my_dict["3"]
value_4 = my_dict["4"]
value_5 = my_dict["5"]
client_socket.close()
# 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 = (value_1, value_2, value_3, value_4, value_5)
cursor.execute(sql, val)
connector.commit()
# カーソル終了
cursor.close()
# MySQL切断
connector.close()
# DB書込み終了---------------------------------------------
if __name__ == "__main__":
start_server()
このプログラムでのポイント。
受信したデータ『data』から要素を抽出するために、『json.loads』を使って、strからdictに戻す変換を行い、[キー'x']を指定し「値」を取り出した。
print(f"受信したデータ: {data.decode('utf-8')}")
my_dict = json.loads(data.decode('utf-8'))
print(my_dict)
# 各要素を取り出す
value_1 = my_dict['1']
value_2 = my_dict["2"]
value_3 = my_dict["3"]
value_4 = my_dict["4"]
value_5 = my_dict["5"]
受信したデータ:
{"1": "2024-01-24 13:27:56", "2": "22.50", "3": "19.90", "4": "14.40", "5": "11.30"}
{"1": "2024-01-24 13:27:56", "2": "22.50", "3": "19.90", "4": "14.40", "5": "11.30"}
my_dict:『json.loads』で元に戻す変換をした結果
{'1': '2024-01-24 13:27:56', '2': '22.50', '3': '19.90', '4': '14.40', '5': '11.30'}
{'1': '2024-01-24 13:27:56', '2': '22.50', '3': '19.90', '4': '14.40', '5': '11.30'}
value:各要素の取出し結果
2024-01-24 13:27:56
22.50
19.90
14.40
11.30
2024-01-24 13:27:56
22.50
19.90
14.40
11.30
5. まとめ
①.「データの型」について
複数の項目を送信するので、データは「辞書型(dict)」にする。
しかし、データの送信は「文字列型(str)」でしか行えない。
そこで、送信側では『json.dumps』を使って、dictからstrに変換して送信する。
複数の項目を送信するので、データは「辞書型(dict)」にする。
しかし、データの送信は「文字列型(str)」でしか行えない。
そこで、送信側では『json.dumps』を使って、dictからstrに変換して送信する。
受信側では、『json.loads』を使って、strからdictに戻す変換を行い、[キー'x']を指定し「値」を抽出する。
②.Pythonをバックグラウンドで実行する
受信側の「Pythonプログラム」は、常時稼働している必要がある。
受信側の「Pythonプログラム」は、常時稼働している必要がある。
SSH で アプリを起動した後、セッション終了後も起動し続ける方法。
nohup python3 xxxxx.py &
③.データベースに蓄積された温度データを参照する
④.Pythonプログラムを2つ同時に実行する
1⃣.データを受信し、データベースに蓄積する「Pythonプログラム」と、
1⃣.データを受信し、データベースに蓄積する「Pythonプログラム」と、
2⃣.データベースを読込んで、グラフ表示する「Pythonプログラム」は、
データベースに保存しながらデータベースの内容を参照するため、それぞれが同時に稼働している必要がある。
データベースに保存しながらデータベースの内容を参照するため、それぞれが同時に稼働している必要がある。
但し、データを受信するPythonと、グラフを表示するPythonの「ポート番号」が被らないようにする必要がある。
参考:
以上。
(2024.01.25)
(2024.01.25)
スポンサー リンク