はじめに
今回,ESP32から画像ファイルをMongoDBに格納したかったのですが,初心者であるが故,実装に苦労したので備忘録というか知識の整理として記事を書きます.
こんなこと他に誰がやるんだって感じなので需要があるか分かりませんが...
やりたいこと
ESP32(送信側)からESP32(受信側)に画像バイナリデータを送信し,さらにESP32(受信側)はVM上にあるMongoDBにHTTPリクエストを使って画像データを送信したいわけです.MongoDBに画像をそのまま保存できるのか分からなかったので今回はバイナリ化してテキストとして保存します.
ESP32間でのやりとりはソケット通信です.
実装
ソケット作成等の部分は割愛します.ここでは画像データ送信の前処理とHTTPリクエストの部分のみを記述します.
ESP32(送信側)での処理
def sending():
global port
global socket_to_KH
global address
global message
global s
while True:
connection, client = s.accept()
with open('material.jpeg', 'rb') as image_file:
image_data = image_file.read()
try:
print(f'----Client {client} connected----')
image_size = len(image_data)
send_count = (image_size // buffer_size) + 1
connection.send(str(send_count).encode())
for i in range(send_count):
start = i * buffer_size
end = min((i + 1) * buffer_size, image_size)
chunk = image_data[start:end]
connection.sendall(chunk)
print('Number of chunks:', send_count)
utime.sleep(2)
finally:
connection.close()
print('connection is closed')
break
バッファサイズを超えてソケット通信で送信使用とするとうまくいかないので,送信ファイルサイズをバッファサイズで分割します.一度チャンクに分割してsendall()で送信することで送信に成功します.
ESP32(受信側)の処理
def receiving():
global host
global port
global socket_to_KM
global address
global message
host = wifi.ifconfig()[2]
try:
sendSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
red.on()
sendSocket.connect((host,port))
red.off()
sendSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
data = sendSocket.recv(buffer_size)
send_count = int(data.decode())
print('Number of chunks:', send_count)
image_data = b""
for i in range(send_count):
chunk = sendSocket.recv(buffer_size)
image_data += chunk
with open('received_image.jpg', 'wb') as image_file:
image_file.write(image_data)
print("Image received and saved as 'received_image.jpg'.")
print(f'received message: {message}')
sendSocket.close()
except Exception as e:
print(e)
pass
こちらは受け取ったチャンクを次々image_dataに突っ込んでいきます.これでESP32間での画像データのやり取りができました.
次にHTTPリクエストでMongoDBに格納します.
def mkb():
with open('received_image.jpg', 'rb') as image_file:
image_data = image_file.read()
return image_data
バイナリデータ化して文字列にします.
def toServer():
image_data = mkb()
url = 'http://192.168.***.***:5000/data'
files = {'image':('received_image.jpg',image_data)}
print(files)
response = urequests.post(url, json=files)
if response.status_code == 201:
print('Data saved successfully')
else:
print('Failed to save data.')
response.close()
バイナリ化したデータをimage_dataとします.
urlはmongoDBのデータコレクションを指定しています.
filesは送信する画像データのバイナリデータです.
micropythonなのでurequestsでpostします.レスポンスステータスコードを受け取って確認できるようにしています.
おわりに
これでHTTPリクエストでESP32からMongoDBにデータを格納できました.今回は画像データを送信するとしていますが,あまり大きなサイズになるとチャンクに分割していても送信できなくなるということがありました.