🐡

UDP通信を使って、ブラウザからESP32を操作する

2023/01/09に公開

ESP32を使っていると、スマホから操作できたらいいのにな〜と思うことはよくあります。

いくつか方法はありまして、

  1. ESP32をサーバーとして、ESP32からHTMLテンプレートをスマホ側に送信
  2. 出来合いのスマホアプリを使って、Bluetoothなどで操作
  3. LINE Messanger APIなどを使う

しかし、いずれの方法もUIを自分好みにはできません。

1の方法では、プログラミング初心者が作ったような、単純なボタンを配置する程度のUIが限界でしょう
そもそもArduinoエディタでHTMLを描くのは手間ですしナンセンスです

2でもできなくはないですが、UI面では一番制限されてしまいます。
アカウント作成など、余計な手間もあります。

3は地味にLINE Messanger APIの縛りが面倒ですし、素早い動作はできません
家のドアの開け閉めくらいが関の山です。

その他、Flutterなどでスマホアプリを作る方法もありますが、わざわざアプリをインストールするのも面倒ですし、銭ゲバApple社に高い登録料を払うのも癪です。

やはりUIは自分の好きに作りたいところ。
私はNuxt3を使えますので、Nuxtで自分好みのUIを作って、UDPで通信することにしました。

node.jsでUDP通信のテスト

まずはMacBookから信号を発信し、ESP32で受け取れるか確認します。

Nuxtを使うので、nodejsで実装します。
(ここではnodejsの実装方法は割愛します)

UDP通信をするにはdgramというライブラリを使います。
https://nodejs.org/api/dgram.html

package.json
{
  "dependencies": {
    "dgram": "^1.0.1",
    "ts-node": "^10.9.1"
  }
}
index.ts
import dgram from 'node:dgram';
import { Buffer } from 'node:buffer';

const HOST = '100.64.1.42' //ESP32のIPアドレスに合わせる
const PORT = 8086 // 何でも良い

const server = dgram.createSocket('udp4');

const message = Buffer.from('green'); // 'green'の文字列をバイナリ形式に変換

server.send(message, PORT, HOST, (err)=>{
      console.log(err)
      server.close()
})

何かしらのデータを送らなければならないので、'green'という文字列をバイナリに変換して送っています。

続いて、ESP32側です。

main.py
from usocket import socket, AF_INET, SOCK_DGRAM
from machine import Pin

SSID = "自宅wifiのssid"
PASSWORD = "自宅wifiのパスワード"

def do_connect():
    import network
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('connecting to network...')
        wlan.connect(SSID, PASSWORD)
        while not wlan.isconnected():
            pass
    print('network config:', wlan.ifconfig())

do_connect()

HOST='100.64.1.42'
PORT=8086

s = socket(AF_INET,SOCK_DGRAM)
s.bind((HOST,PORT))

while 1:
    print('waiting...')
    bytes_data,address = s.recvfrom(1024)
    data = bytes_data.decode()
    print(data)

esp32のIPアドレスは、

print('network config:', wlan.ifconfig())

で表示されるアドレスの一番最初の項目です。

network config: ('100.64.1.42', '255.255.255.0', '100.64.1.1', '8.8.8.8')

この場合は、100.64.1.42です。

これをserver側、client側に設定しましょう。

ESP32を起動させた状態で、nodejsのコードを実行すると、'green'という文字がESP32に送られるはずです。

※補足

ESP32で反応をわかりやすくするために、21ピンと23ピンにLEDをつけてやりました

main.py
# main.py
from usocket import socket, AF_INET, SOCK_DGRAM
from machine import Pin

##### wifi接続の部分は省略 #####

HOST='100.64.1.42'
PORT=8086

green_led = Pin(21,Pin.OUT)
red_led = Pin(23,Pin.OUT)

s = socket(AF_INET,SOCK_DGRAM)
s.bind((HOST,PORT))

while 1:
    print('waiting...')
    bytes_data,address = s.recvfrom(1024)
    data = bytes_data.decode()
    print(data)
    if data == 'red':
        red_led.on()
        green_led.off()
    elif data == 'green':
        red_led.off()
        green_led.on()
    else:
        red_led.off()
        green_led.off()

Nuxt3で実装

あとはNuxtで画面を作りましょう。

今回は最小の実装だけ載せています。

UI部分

app.vue
<script setup lang="ts">
type Color = 'red'|'green'

const blink = async(color:Color)=>{
  const {data} = await useFetch('api/esp32',{params:{color:color}})
  console.log(data.value)
}

</script>

<template>
  <div>
    <h1>テスト</h1>

    <button @click="blink('red')">赤を点灯</button>
    <button @click="blink('green')">緑を点灯</button>
  </div>
</template>

サーバー部分

server/api/esp32.ts
import dgram from 'node:dgram';
import { Buffer } from 'node:buffer';

const HOST = '100.64.1.42' //ESP32のIPアドレスに合わせる
const PORT = 8086

const server = dgram.createSocket('udp4');

type Color = 'red'|'green'

export default defineEventHandler(async(e)=>{
    const query = getQuery(e) as unknown as {color:Color}
    console.log(query)

    const message = Buffer.from(query.color);
    server.send(message,PORT,HOST)
})

Discussion