HOME → 1 Raspberry Pi → 03 作品集 → 

Rasp Pi から Rasp Pi に温度データを Wi-Fiで送受信し データベースに保存

Raspberry Pi 作品集
Python + socket + MariaDB
温度データを Wi-Fiで送受信し データベースに保存
 
クライアントとなる Raspberry Pi(送信側)とサーバーとなる Raspberry Pi(受信側)の「2台」を用意し、「Wi-Fi(socket)」を使ってデータを送受信し、サーバー側では、受信したデータをデータベース(MariaDB)に蓄積する。
 
サーバーとなる Raspberry Pi(受信側)のメッセージ
サーバーとなる Raspberry Pi(受信側)のメッセージ。
 
以下、 Raspberry Piで 温度データを Wi-Fiで送受信し データベースに保存する「Python 」を作成した記録。
 
 

 

スポンサー リンク

 

 
 
 
 
 
1. 全体イメージと稼働環境
 
Raspberry Pi を2台用意し、クライアントとなる Raspberry Pi(送信側)から
サーバーとなる Raspberry Pi(受信側)に、「Wi-Fi(socket)」を使ってデータを送信し、サーバー側の Raspberry Pi で受信したデータをデータベース(MariaDB)に蓄積する。
Rasp Pi から Rasp Pi に温度データをネットワーク経由で送受信しデータベースに保存
 
送信側のRaspberry Piと使用した温度センサー 。
Raspberry Pi 2 Model B Rev 1.1
DHT22 温度湿度センサモジュール:AM2302チップ付き x 4個
 
受信側のRaspberry Piと使用したデータベース。
Raspberry Pi 3 Model B Rev 1.2
MariaDB Ver 10.5.21
 
Raspberry Pi OS と Pythonのバージョン。
cat /etc/os-releasese
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に変換して送信。
# 送信するデータ
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
 
「ConnectionRefusedError: [Errno 111] Connection refused」
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"}
my_dict:『json.loads』で元に戻す変換をした結果
{'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
 
 
データベースへの書き込み結果を確認。( SELECT * FROM meas_value;)
データベースへの書き込み結果を確認
 
 
 
5. まとめ
 
①.「データの型」について
複数の項目を送信するので、データは「辞書型(dict)」にする。
しかし、データの送信は「文字列型(str)」でしか行えない。
そこで、送信側では『json.dumps』を使って、dictからstrに変換して送信する。
 
受信側では、『json.loads』を使って、strからdictに戻す変換を行い、[キー'x']を指定し「値」を抽出する。
 
 
②.Pythonをバックグラウンドで実行する
受信側の「Pythonプログラム」は、常時稼働している必要がある。
 
SSH で アプリを起動した後、セッション終了後も起動し続ける方法。
nohup python3 xxxxx.py &
 
 
③.データベースに蓄積された温度データを参照する
x 4個の温度データを、測定時刻別にプロットしたグラフ。
x 4個の温度データを測定時刻別にグラフプロットした結果
 
 
 
④.Pythonプログラムを2つ同時に実行する
 1⃣.データを受信し、データベースに蓄積する「Pythonプログラム」と、
 2⃣.データベースを読込んで、グラフ表示する「Pythonプログラム」は、
データベースに保存しながらデータベースの内容を参照するため、それぞれが同時に稼働している必要がある。
 
一番簡単な方法は、ターミナルセッションを2つ(SSH接続を2つ)開いて、それぞれでPythonスクリプトを実行すれば、2つ同時に稼働させることができる。
ターミナルセッションを2つ開いて、それぞれでPythonスクリプトを実行すれば、2つ同時に稼働させることができる
 
但し、データを受信するPythonと、グラフを表示するPythonの「ポート番号」が被らないようにする必要がある。
 
データを受信するPythonの「ポート番号」は、【5000】に設定。
データを受信するPythonの「ポート番号」は、【5000】に設定
 
グラフを表示するPythonの「ポート番号」は、【5001】に設定。
グラフを表示するPythonの「ポート番号」は、【5001】に設定
 
参考:
 
 
以上。
(2024.01.25)
 

 

スポンサー リンク

 

             

 

 

 

コメントを残す

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

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