ESP32をWiFiに接続する
はじめに
この記事ではESP32開発ボードをMicropythonを使用してWiFiに接続する方法について記述しています。
In English
This article describes how to connect ESP32 development board to WiFi network using Micropython in Japanese.
ESP32開発ボードとWiFi
原稿執筆時の段階では、ESP32開発ボードで使用できるWiFiは2.4GHz帯のみで、5GHz帯には対応していないので、注意が必要です。
ESP32のWiFiインターフェイスにはステーションモード と アクセスポイントモード のふたつのモードがあります。
ステーションモードは自身(ESP32)が無線LAN子機としてWiFiルータなどのアクセスポイントに接続するモードです。
アクセスポイントモードは自身がアクセスポイントとして振る舞い、PCやスマホなどの無線LAN子機からの接続を受け付けるモードです。
結線
結線は不要です。
サンプルプログラム1(WiFiスキャン)
次のプログラムはESP32のWiFiインターフェイスをステーションモードに設定し、1秒毎にWiFiをスキャン(周辺で、どのようなSSIDの電波が出ているか調べる)を5回行うプログラムです。
7行目:ESP32のWiFiインターフェイスをステーションモードとして使用するようインスタンスを作成しています。
10行目:WiFiインターフェイスを有効化しています。
14行目:scan()を実行し、その結果を表示しています。
wlan_scan1.py
コピペ用 wlan_scan1.py
# Scan WiFi network aroud ESP32
import network
import time
# Make wlan instance as station
wlan = network.WLAN(network.STA_IF)
# Activate WiFi interface
wlan.active(True)
# Scan 5 times every 1 second
for n in range(5):
print(wlan.scan())
time.sleep(1)
wlan.scan()の戻り値は次のようなタプルになっています。
(ssid, bssid, channel, RSSI, security, hidden)
ssid
Service Set Identifierの略で、無線LANアクセスポイントの識別名。
最大32文字。
bssid
Basic Service Set Identifierの略で、通常はMACアドレスとなっている。
channel
使用しているWiFiのチャンネル番号を表す。
RSSI
Received Signal Strength Indicatorの略で、受信しているWiFi電波の強度を表す。単位はdBm(でぃーびーえむ)。0に近づくほど電波が強い。
security
WiFiの認証方式を表し、open, WEP, WPA-PSK, WPA2-PSK, WPA/WPA2-PSKの値がそれぞれ、0から4で返される。
hidden
0はSSIDを表示し、1はSSIDを表示しない(SSIDステルス機能)モードとなっている。
サンプルプログラム2(スキャン結果の詳細表示)
wlan.scan()の戻り値を詳しく表示するようにサンプルプログラム1を変更したものです。
17行目:scandataというリストに格納されたデータを22行目以下で、一つずつ取り出して表示しています。
23行目:SSIDがbyte型となっているので、decode()でstring型に変換して表示います。
24行目:MACアドレスがbyte型で格納されているので、:(コロン)を区切り記号とした16進数表現に変換(binascii.hexlify())し、さらにbyte型をstring型に変換(decode())して表示しています。
25行目、26行目:チャネルやRSSIをstring型に変換して表示しています。
27行目:WiFiの認証方式を8行目のSECURITYリストから取り出して表示しています。
wlan_scan2.py
コピペ用 wlan_scan2.py
# Scan WiFi network aroud ESP32-Dev board
# Dec. 30 2022 iot101@zenn.dev
import network
import binascii # for MAC address
# WiFi Authentication Method
SECURITY = ["open", "WEP", "WPA-PSK", "WPA-PSK", "WPA/WPA2-PSK"]
# Make wlan instance as station
wlan = network.WLAN(network.STA_IF)
# Activate WiFi interface
wlan.active(True)
# Scan once
scandata = wlan.scan()
print(scandata)
print()
# Print details
for data in scandata:
print("SSID:", data[0].decode())
print("MACADR:", binascii.hexlify(data[1], ':').decode())
print("Channel:", str(data[2]))
print("RSSI:", str(data[3]))
print("Security:", SECURITY[data[4]])
print()
サンプルプログラム3(WiFiルータ接続)
ESP32開発ボードをステーションモードでWiFiルータに接続するサンプルプログラムです。
10行目、11行目のSSIDとPASSは使用する環境に合わせて設定する必要があります。
接続が完了すると、DHCPで得られたIPアドレス、ゲートウェイ、DNSサーバ、RSSIが表示されます。
接続できない場合は、延々と . (ドット)が表示され続けるので、CTRL-Cでプログラムを停止させて下さい。
17行目〜20行目:一旦WiFiインターフェイスを無効化した後に有効化しています。
24行目:WiFiが接続されていなかったら10行目と11行目でセットしたSSIDとPASSを用いて、26行目でWiFiに接続します。
28行目:接続されるまで「.」を表示して200ミリ秒待つことを繰り返します。
34行目:接続されたWiFiルータの電波強度(電界強度)を取得しています。
35行目:接続されたWiFiのIPアドレス、ネットマスク、デフォルトルート、ネームサーバの情報を取得しています。
コピペ用 wifi1.py
# Try to connect WiFi router
# Dec. 4th 2022
# (C) iot101@zenn.dev
import network
import time
# At home, you should change these 2 lines.
SSID = "SSID_at_home_nomap"
PASS = "PASS_at_home"
# Connect to Wifi
print()
print("WiFi initializing...")
wlan = network.WLAN(network.STA_IF)
wlan.active(False)
time.sleep(1)
wlan.active(True)
time.sleep(1)
print("Scanning WLAN...")
print(wlan.scan())
if not wlan.isconnected():
print("Connecting WiFi:",SSID, end="")
wlan.connect(SSID, PASS)
time.sleep_ms(100)
while not wlan.isconnected():
print(".", end='')
time.sleep_ms(200)
pass
print("\n\nConnected.")
rssi = wlan.status('rssi')
myip, mynetmask, myroute, mydns = wlan.ifconfig()
wifiinfo = (myip, myroute, mydns, rssi)
print("ip: %s\ngateway: %s\ndns: %s\nrssi: %.1f" % wifiinfo)
実行結果
WiFi initializing...
Scanning WLAN...
[(b'myoffice_nomap', b'xxx\xxx\xxx\xxx', 6, -47, 3, False), (b'Buffalo-G-Z123', b'\xxxx\xxx\xxx\xxx', 9, -76, 3, False), (b'MicroPython-xxxxxx', b'J?\xxxx\xxx', 1, -78, 4, False)]
Connecting WiFi: myoffice_nomap....
Connected.
ip: 192.168.134.123
gateway: 192.168.134.233
dns: 192.168.134.233
rssi: -47.0
サンプルプログラム4(複数拠点でのルータ接続)
自宅のWiFiと職場/学校のWiFiなど、複数箇所に移動してWiFi接続する場合のサンプルコードです。
mywifiというリストにそれぞれの場所のSSIDとパスワードをタプルでセットするようにしています。
24行目のMAXTRY変数で設定された回数接続を試みて、接続できなければ諦めて次へ行きます。
WiFiに接続すると、ESP32開発ボードのオンボードLEDが点灯したままになり、接続できないと消灯します。
SSID1,PASS1,SSID2,PASS2はそれぞれの環境に合わせて書き換えて下さい。
このファイルをboot.pyというファイル名に変更し、ESP32開発ボードに転送すると、起動時にWiFi接続するようにできます。
14、15行目、18、19行目:それぞれで場所のSSIDとPASSを設定します。環境に合わせて書き換える必要があります。
21行目:SSIDとPASSの組み合わせをタプルとして、それらからリストを作成しています。
24行目:試行する接続回数の上限をセットしています。
34行目〜40行目:オンボードLEDを0.2秒ごとに点滅する関数です。
44行目〜87行目:WiFiに接続する関数です。WiFiが接続されていなかったら(55行目)SSIDとPASSの組みを順に取り出して接続を試みます。MAXTRYの値を超えるとGive upします。接続されるとDHCPで割り振られたIPアドレス、デフォルトゲート、DNSサーバ、電波強度、MACアドレスを表示します。
コピペ用 wifi2.py
# Try to connect WiFi at multiple place
# Dec. 4th 2022
# Last modify: Apr. 13 2023
# (C) iot101@zenn.dev
#
# Rename this file to boot.py and put this into ESP board.
import network
import machine
import time
import binascii # for MAC address
# At home, you should change these 2 lines.
SSID1 = "SSID_at_home_nomap"
PASS1 = "PASS_at_home"
# At office/school, you should change these 2 lines.
SSID2 = "SSID_at_office/school"
PASS2 = "PASS_at_office/school"
mywifi = [(SSID1, PASS1), (SSID2, PASS2)]
# try to connect wifi MAXTRY times
MAXTRY = 10
wlan = ""
# on-board LED
LED = 2
led = machine.Pin(LED, machine.Pin.OUT)
# blink on-board led count times
def blink(count):
for n in range(count):
led.on()
time.sleep(0.2)
led.off()
time.sleep(0.2)
led.off()
# Connect to Wifi
def connectwifi():
print()
print("WiFi initializing...")
wlan = network.WLAN(network.STA_IF)
wlan.active(False)
time.sleep(1)
wlan.active(True)
time.sleep(1)
print("Scanning WLAN...")
print(wlan.scan())
for w in mywifi:
if not wlan.isconnected():
trycount = 0
ssid, passwd = w
print("Trying to connect WiFi: "+ssid, end='')
wlan.connect(ssid, passwd)
time.sleep_ms(100)
while not wlan.isconnected():
blink(1)
print(".", end='')
time.sleep_ms(200)
trycount += 1
# Give up if trycount exceeded
if trycount > MAXTRY:
wlan.disconnect()
print("Give up")
wifiinfo = (None, None, None, None, None)
break
if wlan.isconnected() is True:
rssi = wlan.status('rssi')
macaddr = binascii.hexlify(wlan.config('mac'), ':').decode()
print("\n\nConnected WiFi:", ssid)
myip, mynetmask, myroute, mydns = wlan.ifconfig()
wifiinfo = (myip, myroute, mydns, rssi, macaddr)
print("ip: %s\ngateway: %s\ndns: %s\nrssi: %.1f\nmacaddr: %s"
% wifiinfo)
led.on()
return wifiinfo
# ---
blink(5)
myip, myroute, mydns, rssi, macaddr = connectwifi()
if myip is None:
print("Can't connect WiFi.")
演習問題
- ESP32開発ボードと同一のWiFiに接続されているPCからpingを飛ばして疎通確認を行って下さい。スマフォに「Network Analyzer」など、pingができるアプリがインストールされていれば、スマートフォンからも試せます。ただし、ESP32開発ボードと同じWiFiに接続されている必要があります。
スマホ用Network Analyzerについては以下の画像のリンクをクリックして下さい。
アプリのインストールは自己責任でお願いします。
- ESP32開発ボードとPCをUSBケーブルで接続されている場合はThonnyのシェル画面でESP32開発ボードのIPアドレスを知ることができますが、モバイルバッテリなどから電源が供給されていて、PCが接続されていない場合、どうすればESP32開発ボードのIPアドレスを知ることができますか?
ヒント:次のようなキーワドで ChatGPTに聞いてみて下さい。
「ローカルネットに接続された機器のIPアドレスを知る方法は? ただし、MACアドレスは既知である。」
MACアドレスはサンプルプログラム4でもシェル画面の最後に表示されますが、下のプログラムを単独に動かしても表示させることができます。
# Display MAC address
# Apr. 7th 2023
# (C) iot101@zenn.dev
import network
import binascii
wlan = network.WLAN(network.STA_IF)
wlan.active()
macaddr = wlan.config('mac')
print("My MAC address is", binascii.hexlify(macaddr, ":").decode())
おまけ
ステーションモードで固定IPにするサンプルプログラム
サンプルプログラム3、4はDHCPによりWiFiルータからIPアドレスなどが付与されますが、固定IPとして設定することもできます。
14行目〜17行目:固定IPに必要な情報をセットします。
43行目:IPアドレス等の情報を保持したタプルを作成しています。
44行目:43行目の情報にしたがってWiFiインターフェースの設定を行っています。
コピペ用 wifi_fixedIP.py
# Try to connect WiFi router
# Apr. 6th 2023
# (C) iot101@zenn.dev
import network
import machine
import time
# At home, you should change these 2 lines.
SSID = "SSID_at_home_nomap"
PASS = "PASS_at_home"
# Fixed IP information
MYIP = '192.168.0.4'
MYNETMASK = '255.255.255.0'
MYGATEWAY = '192.168.0.1'
MYDNS = '1.1.1.1'
# Connect to Wifi
print()
print("WiFi initializing...")
wlan = network.WLAN(network.STA_IF)
wlan.active(False)
time.sleep(1)
wlan.active(True)
time.sleep(1)
print("Scanning WLAN...")
print(wlan.scan())
if not wlan.isconnected():
print("Connecting WiFi:",SSID, end="")
wlan.connect(SSID, PASS)
time.sleep_ms(100)
while not wlan.isconnected():
print(".", end='')
time.sleep_ms(200)
pass
print("\n\nConnected.")
rssi = wlan.status('rssi')
# set fixed IP
MYWIFI = (MYIP, MYNETMASK, MYGATEWAY, MYDNS)
wlan.ifconfig(MYWIFI)
myip, mynetmask, myroute, mydns = wlan.ifconfig()
wifiinfo = (myip, myroute, mydns, rssi)
print("ip: %s\ngateway: %s\ndns: %s\nrssi: %.1f" % wifiinfo)
アクセスポイントモードのサンプルプログラム
ESP32開発ボードをWiFiのアクセスポイントとして使用するサンプルプログラムです。
パスワードは8桁以上にする必要があります。さもないと、Wifi Invalid Password
のエラーが出ます。
このプログラムを動かした後、スマホやPCのWiFiをESP32開発ボードのSSID(ESP32_AccessPoint)に接続するとそれらのMACアドレスが表示されます。パスワードはHimitsudesu
と入力して下さい。
接続を切るとMACアドレスが表示されなくなります。DHCPで割り振られたIPアドレスはPCやスマホで確認できます。
コピペ用 wifi_accesspoint.py
# Become an access point
# Apr. 6th 2023
# (C) iot101@zenn.dev
import network
import binascii
import time
# Access point credensials
SSID = 'ESP32_AccessPoint'
# THe password must be more than 8 digits or
# you will meet 'Wifi Invalid Password' error.
PASS = 'Himitsudesu'
# Authentification mode. We use WPA/WPA2-Personal.
AUTH = network.AUTH_WPA_WPA2_PSK
# Access Point address information
MYIP = '172.16.3.254'
MYNETMASK = '255.255.255.0'
MYGATEWAY = '172.16.3.254'
MYDNS = '172.16.3.254'
MYNETINFO = (MYIP, MYNETMASK, MYGATEWAY, MYDNS)
# Connect to Wifi
print()
print("WiFi initializing...")
wlan = network.WLAN(network.AP_IF)
wlan.config(essid=SSID, password=PASS, authmode=AUTH)
wlan.active(False)
time.sleep(1)
wlan.active(True)
# Wait until WiFi interface is active
while wlan.active() is False:
pass
print('Access point has bee activated')
wlan.ifconfig(MYNETINFO)
print(wlan.ifconfig())
# Check who is connected via WiFi, show MAC address
while True:
clients = wlan.status('stations')
if len(clients) == 0:
print("Waiting for connection...")
else:
for client in clients:
mac = client
print(binascii.hexlify(mac[0], ":").decode(), " ", end='')
print()
time.sleep(1)
Discussion