📖
ESP32でUDP通信する方法を誰よりもわかりやすく解説 実践編
前回はUDP通信を使って、ESP32からmacbookにデータを送りました。
実践に近い形として、ESP32から号機、温度、湿度を送ります。
ESP32
二台用意し、それぞれ1号機、2号機とします。
データは以下のような形で渡します
data = {
id:1, #ESP32の号機
data:{
hum:30, #湿度
temp:10,#温度
}
}
main.py
import ujson
from network import WLAN, STA_IF
from utime import sleep
from usocket import socket, AF_INET, SOCK_DGRAM
SSID = "自宅wifiの2.4G"
PASSWORD = "自宅wifiのパスワード"
wlan:WLAN = WLAN(STA_IF)
wlan.active(True)
def wifi_connect():
if not wlan.isconnected():
print('connecting to network...')
wlan.connect(SSID, PASSWORD)
print('network config:', wlan.ifconfig())
while not wlan.isconnected():
pass
HOST = '100.64.1.50'
PORT = 8890
s = socket(AF_INET, SOCK_DGRAM)
# s.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
i:int=0
while 1:
i+=1
wifi_connect() # 工夫点1
tempValue = 10 + i%20
humidValue = i%80
data = {
'id':2, # 1号機なら1、2号機なら2
'data':{
'temp':tempValue,
'hum':humidValue
}
}
print(data)
json = ujson.dumps(data)
binData = json.encode()
s.sendto(binData,(HOST, PORT))
sleep(1) # 工夫点2
以下、工夫点です
1. wifi接続を都度確認
ずっとwifiに繋いでいると、たまに接続が途切れます。
whileのループの中でwifi接続を入れることで、wifi接続が切れても接続しなおすようにしています。
2. sleepで時間を空ける
sleepを設けないと、3回くらいループした後でエラーを起こします。
おそらくUDP通信には少し時間かかるため、データを送りきる前に次のデータを送ろうとすると、メモリ的にしんどくなるのでしょう。
MacBook
macbookはESP32からのデータを受け取ります。
server.py
from socket import socket, AF_INET, SOCK_DGRAM
import json
HOST_NAME = '100.64.1.50' # MacBookのIPアドレス
PORT = 8890
# IPv4でUDP通信
s = socket(AF_INET, SOCK_DGRAM)
# 自ホストで使用するIPアドレスとポート番号を指定
s.bind((HOST_NAME, PORT))
while True:
#データを待ち受け
rcv_data, addr = s.recvfrom(1024)
data_json = rcv_data.decode()
data_dict = json.loads(data_json)
print(data_dict)
実行すると、以下のように2台のESP32のデータを受け取ります
{'id': 2, 'data': {'hum': 21, 'temp': 11}}
{'id': 2, 'data': {'hum': 22, 'temp': 12}}
{'id': 2, 'data': {'hum': 23, 'temp': 13}}
{'id': 2, 'data': {'hum': 24, 'temp': 14}}
{'id': 2, 'data': {'hum': 25, 'temp': 15}}
{'id': 2, 'data': {'hum': 26, 'temp': 16}}
{'id': 2, 'data': {'hum': 27, 'temp': 17}}
{'id': 2, 'data': {'hum': 28, 'temp': 18}}
データの平滑化と書き込み
先ほどのやり方では、1秒おきに2台のESP32から温度と湿度のデータが送られてきます。
しかし現実はそんなに細かいデータなんて必要ありません(10分おきくらいで十分です)
そこで10分間に受け取ったデータを平均値をとって平滑化し、さらにデータをSQLiteに書き込みします。
(こういったデータの精製や平滑化作業は、サーバー側で行なったほうが良いです。)
こんな感じでデータを格納するクラスを作ってあげればどうでしょう。
server.py
class Data:
hums:list[int] = []
temps:list[int] = []
count = 0
def setData(self,data):
self.hums.append(data['hum'])
self.temps.append(data['temp'])
self.count = self.count+1
print(f'count:{self.count}')
if self.count>9:
self.setDb()
def setDb(self):
humAvg = sum(self.hums)/len(self.hums)
tempAvg = sum(self.temps)/len(self.temps)
timestamp = datetime.datetime.now()
print(f'timestamp:{timestamp},humAvg:{humAvg},tempAvg:{tempAvg}')
self.hums = []
self.temps = []
self.count = 0
esp1data = Data()
esp2data = Data()
10カウントすると、平均値を表示させます。
Discussion