📖

ESP32でUDP通信する方法を誰よりもわかりやすく解説 実践編

2023/01/08に公開

前回は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