出品:1Z實驗室 1zlab.com
1ZLAB: Make Things Easy
導引
作為一款支持wifi的物聯(lián)網芯片,ESP32的聯(lián)網方式自然是要重點掌握的.在MicroPython下,聯(lián)網更是一件輕松Easy的事情, 在MicroPython tutorial for ESP8266中,官方給出了MicroPython的WiFi連接示例代碼.但是在實際的應用場景中,很多基于物聯(lián)網的工程應用,第一要義就是建立網絡連接.按照這份示例代碼,WIFI確實可以幾步就連接妥當.但WIFI連接有哪些坑需要注意,如何編寫更合理的WIFI連接代碼呢?
注: 如果你想直接獲取最終解決方案的代碼,請直接跳轉至文章尾部.
初試網絡連接
我們先來看看官方給的示例代碼(部分變量名筆者有所改動):
def do_connect():
import network #WIFI連接需要引入network包
wifi = network.WLAN(network.STA_IF) #創(chuàng)建連接對象 如果讓ESP32接入WIFI的話使用STA_IF模式,若以ESP32為熱點,則使用AP模式
if not wifi.isconnected(): #判斷WIFI連接狀態(tài)
print('connecting to network...')
wifi.active(True) #激活WIFI
wifi.connect('<essid>', '<password>') #essid為WIFI名稱,password為WIFI密碼
while not wifi.isconnected():
pass # WIFI沒有連接上的話做點什么,這里默認pass啥也不做
print('network config:', wifi.ifconfig())
我們對其稍作改動,將WIFI名字和密碼改為do_connect
的參數
def do_connect(essid, password):
import network
wifi = network.WLAN(network.STA_IF)
if not wifi.isconnected():
print('connecting to network...')
wifi.active(True)
wifi.connect(essid, password)
while not wifi.isconnected():
pass
print('network config:', wifi.ifconfig())
Ctrl+E開啟MicroPython ESP32的粘貼模式,將以上代碼copy進去:
paste mode; Ctrl-C to cancel, Ctrl-D to finish
=== def do_connect(essid, password):
=== import network
=== wifi = network.WLAN(network.STA_IF)
=== if not wifi.isconnected():
=== print('connecting to network...')
=== wifi.active(True)
=== wifi.connect(essid, password)
=== while not wifi.isconnected():
=== pass
=== print('network config:', wifi.ifconfig())
>>>
調用do_connect
函數:
>>> do_connect('ChinaNet-Q5uk','0921608677')
I (88874) wifi: wifi driver task: 3ffcb8b8, prio:23, stack:4096, core=0
I (88874) wifi: wifi firmware version: ac8d7b4
I (88874) wifi: config NVS flash: enabled
I (88874) wifi: config nano formating: disabled
I (88884) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (88894) system_api: Base MAC address is not set, read default base MAC address from BLK0 of EFUSE
I (88904) wifi: Init dynamic tx buffer num: 32
I (88904) wifi: Init data frame dynamic rx buffer num: 64
I (88914) wifi: Init management frame dynamic rx buffer num: 64
I (88914) wifi: Init static rx buffer size: 1600
I (88924) wifi: Init static rx buffer num: 10
I (88924) wifi: Init dynamic rx buffer num: 0
connecting to network...
I (88984) phy: phy_version: 3910, c0c45a3, May 21 2018, 18:07:06, 0, 0
I (88994) wifi: mode : sta (30:ae:a4:84:22:64)
I (88994) wifi: STA_START
I (89234) wifi: n:2 0, o:1 0, ap:255 255, sta:2 0, prof:1
I (89804) wifi: state: init -> auth (b0)
I (89814) wifi: state: auth -> assoc (0)
I (89824) wifi: state: assoc -> run (10)
I (90124) wifi: connected with ChinaNet-Q5uk, channel 2
I (90124) wifi: pm start, type: 1
I (90134) network: CONNECTED
I (91414) event: sta ip: 192.168.2.189, mask: 255.255.255.0, gw: 192.168.2.1
I (91414) network: GOT_IP
network config: ('192.168.2.189', '255.255.255.0', '192.168.2.1', '192.168.2.1')
>>>
打印一大堆日志,然后成功連接到WIFI.
聽說你想開機自動連接WIFI?
大部分讀者的內心獨白:
大佬: 這還用你教,我寫在main.py里不就好了嗎.
小白: 那每次都要開機自動輸入一遍WIFI名字和密碼,豈不是很麻煩?
大佬: 寫個配置文件,專門放置WIFI密碼和名字不就好了嗎?
現(xiàn)在我們按照大佬的思路來安排一波:
首先我們創(chuàng)建 main.py
,并寫入do_connect
函數的代碼,我們將以讀取配置文件的方式來讀取WIFI的名稱和密碼,因此代碼做如下改動:
def do_connect():
import json
import network
# 嘗試讀取配置文件wifi_confi.json,這里我們以json的方式來存儲WIFI配置
# wifi_config.json在根目錄下
# 若不是初次運行,則將文件中的內容讀取并加載到字典變量 config
try:
with open('wifi_config.json','r') as f:
config = json.loads(f.read())
# 若初次運行,則將進入excpet,執(zhí)行配置文件的創(chuàng)建
except:
essid = input('wifi name:') # 輸入essid
password = input('wifi passwrod:') # 輸入password
config = dict(essid=essid, password=password) # 創(chuàng)建字典
with open('wifi_config.json','w') as f:
f.write(json.dumps(config)) # 將字典序列化為json字符串,存入wifi_config.json
#以下為正常的WIFI連接流程
wifi = network.WLAN(network.STA_IF)
if not wifi.isconnected():
print('connecting to network...')
wifi.active(True)
wifi.connect(config['essid'], config['password'])
while not wifi.isconnected():
pass
print('network config:', wifi.ifconfig())
if __name__ == '__main__':
do_connect()
然后就可以愉快的重啟了,試試咱們的開機自動連接WIFI的代碼
wifi name:ChinaNet-Q5uk
wifi passwrod:0921608677
I (69669) wifi: wifi driver task: 3ffc6678, prio:23, stack:4096, core=0
I (69669) wifi: wifi firmware version: ac8d7b4
I (69669) wifi: config NVS flash: enabled
I (69669) wifi: config nano formating: disabled
...此處省略若干行日志
I (71139) network: CONNECTED
I (72089) event: sta ip: 192.168.2.189, mask: 255.255.255.0, gw: 192.168.2.1
I (72089) network: GOT_IP
network config: ('192.168.2.189', '255.255.255.0', '192.168.2.1', '192.168.2.1')
MicroPython v1.9.4-429-ge755bd493 on 2018-08-03; ESP32 module with ESP32
Type "help()" for more information.
>>>
再看看我們的wifi_config.json
是否已創(chuàng)建完畢:
>>> import os
>>> os.listdir()
['boot.py', 'main.py', 'wifi_config.json']
>>>
再重啟試試吧
ets Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
...此處省略若干行日志
I (1882) network: CONNECTED
I (4842) event: sta ip: 192.168.2.189, mask: 255.255.255.0, gw: 192.168.2.1
I (4842) network: GOT_IP
network config: ('192.168.2.189', '255.255.255.0', '192.168.2.1', '192.168.2.1')
MicroPython v1.9.4-429-ge755bd493 on 2018-08-03; ESP32 module with ESP32
Type "help()" for more information.
>>>
問題:WIFI環(huán)境發(fā)生改變后,WIFI連接陷入了死循環(huán)
小白: 大佬真棒,上面的代碼沒毛病,但是如果WIFI環(huán)境一變,好像就陷入了死循環(huán),比如接下來的這波操作:
我們把 wifi_config.json
文件刪掉,然后重啟,輸入錯誤的wifi名稱和密碼,以此來模擬WIFI環(huán)境的改變:
>>> import os
>>> os.remove('wifi_config.json')
然后重啟,并輸入錯誤的essid和password:
connecting to network...
I (26468) phy: phy_version: 3910, c0c45a3, May 21 2018, 18:07:06, 0, 0
I (26468) wifi: mode : sta (30:ae:a4:84:22:64)
I (26468) wifi: STA_START
I (28878) wifi: STA_DISCONNECTED, reason:201
no AP found
I (31288) wifi: STA_DISCONNECTED, reason:201
no AP found
I (33708) wifi: STA_DISCONNECTED, reason:201
no AP found
I (36118) wifi: STA_DISCONNECTED, reason:201
no AP found
I (38528) wifi: STA_DISCONNECTED, reason:201
no AP found
I (40938) wifi: STA_DISCONNECTED, reason:201
no AP found
I (43348) wifi: STA_DISCONNECTED, reason:201
no AP found
I (45758) wifi: STA_DISCONNECTED, reason:201
no AP found
I (48168) wifi: STA_DISCONNECTED, reason:201
no AP found
I (50578) wifi: STA_DISCONNECTED, reason:201
no AP found
I (52998) wifi: STA_DISCONNECTED, reason:201
no AP found
I (55408) wifi: STA_DISCONNECTED, reason:201
no AP found
Traceback (most recent call last):
File "main.py", line 31, in <module>
File "main.py", line 26, in do_connect
KeyboardInterrupt:
Ctrl+C也沒用
MicroPython v1.9.4-429-ge755bd493 on 2018-08-03; ESP32 module with ESP32
Type "help()" for more information.
>>> I (57818) wifi: STA_DISCONNECTED, reason:201
no AP found
I (60228) wifi: STA_DISCONNECTED, reason:201
no AP found
I (62638) wifi: STA_DISCONNECTED, reason:201
no AP found
I (65048) wifi: STA_DISCONNECTED, reason:201
no AP found
.....沒有盡頭的刷屏
>>> I (168678) wifi: STA_DISCONNECTED, reason:201
no AP found
repl已經被刷屏了
>>> I (171088) wifi: STA_DISCONNECTED, reason:201
no AP found
I (173498) wifi: STA_DISCONNECTED, reason:201
no AP found
I (175908) wifi: STA_DISCONNECTED, reason:201
no AP found
TIPS:當你陷入這種repl的輸出死循環(huán)的時候,不要慌張,解決方案還是有的,請先冷靜以下,默默的一字一句輸入
import os
回車os.remove('main.py')
回車,在此過程中請無視repl的輸出,只需保證自己的輸入無誤就OK, 以此刪除你的main.py文件,當然你也可以去對癥下藥,但是刪掉main.py重啟是最簡單的方式...
問題已經暴露的一覽無余了,更合理的WIFI連接姿勢我們立馬給出.
更合理的建立wifi連接
先讓我們回顧之前的代碼:
wifi = network.WLAN(network.STA_IF)
if not wifi.isconnected():
print('connecting to network...')
wifi.active(True)
wifi.connect(config['essid'], config['password'])
while not wifi.isconnected():
pass
print('network config:', wifi.ifconfig())
在 while循環(huán)中,,執(zhí)行循環(huán)的條件是wifi沒有連接成功.我們看到目前的做法是pass,什么也沒干.因此我們在此做點文章應該就OK了.
可能大部分人和我一開始的思路一樣,刪掉wifi_config.json,重新調用do_connect函數進行wifi的初始化配置.但這樣的話,可能你永遠也無法走出這個循環(huán),因為經過我多次踩坑之后發(fā)現(xiàn):
connect()
函數執(zhí)行完畢之后并不會等待WIFI連接成功之后才繼續(xù)執(zhí)行,而是直接繼續(xù)往下執(zhí)行.而且connect()
本身不會返回任何數據.
所以接下來的探討分為兩種情況:
1 essid 和 password 正確
在WIFI沒有真正的建立起連接的時候,wifi.is_connected()
一直都返回False
,while
循環(huán)中的代碼會被循環(huán)執(zhí)行.當wifi連接成功建立之后,wifi.is_connected()
返回True
,跳出while
循環(huán),WIFI連接宣告完畢2 essid 和 password 不正確
wifi.is_connected()
一直都返回False
,while
循環(huán)中的代碼會被循環(huán)執(zhí)行.并且伴隨著repl的一頓刷屏輸出.
為了解決WIFI連接過程需要耗費一定的時間的這個問題,我們需要加上一段延時,在一定延時之后我們再進行is_connected()
判斷,此時若is_connected()==False
,則視為連接失敗,便接著執(zhí)行我們應對WIFI環(huán)境改變或其他原因導致的essid與password認證失敗的代碼.
為了阻止repl由于wifi連接失敗產生的刷屏,我們需要將wifi關閉,調用wifi.active(False)
,然后我們刪除wifi_config.json,再遞歸調用do_connect()
更合理的wifi連接代碼如下:
import sys
# 添加路徑
sys.path.append('examples')
def is_legal_wifi(essid, password):
'''
判斷WIFI密碼是否合法
'''
if len(essid) == 0 or len(password) == 0:
return False
return True
def do_connect():
import json
import network
# 嘗試讀取配置文件wifi_confi.json,這里我們以json的方式來存儲WIFI配置
# wifi_config.json在根目錄下
# 若不是初次運行,則將文件中的內容讀取并加載到字典變量 config
try:
with open('wifi_config.json','r') as f:
config = json.loads(f.read())
# 若初次運行,則將進入excpet,執(zhí)行配置文件的創(chuàng)建
except:
essid = ''
password = ''
while True:
essid = input('wifi name:') # 輸入essid
password = input('wifi passwrod:') # 輸入password
if is_legal_wifi(essid, password):
config = dict(essid=essid, password=password) # 創(chuàng)建字典
with open('wifi_config.json','w') as f:
f.write(json.dumps(config)) # 將字典序列化為json字符串,存入wifi_config.json
break
else:
print('ERROR, Please Input Right WIFI')
#以下為正常的WIFI連接流程
wifi = network.WLAN(network.STA_IF)
if not wifi.isconnected():
print('connecting to network...')
wifi.active(True)
wifi.connect(config['essid'], config['password'])
import utime
for i in range(200):
print('第{}次嘗試連接WIFI熱點'.format(i))
if wifi.isconnected():
break
utime.sleep_ms(100) #一般睡個5-10秒,應該綽綽有余
if not wifi.isconnected():
wifi.active(False) #關掉連接,免得repl死循環(huán)輸出
print('wifi connection error, please reconnect')
import os
# 連續(xù)輸錯essid和password會導致wifi_config.json不存在
try:
os.remove('wifi_config.json') # 刪除配置文件
except:
pass
do_connect() # 重新連接
else:
print('network config:', wifi.ifconfig())
if __name__ == '__main__':
do_connect()
更改了main.py后我們重新啟動一下:
connecting to network...
...省略若干行日志...
wifi connection error, please reconnect
wifi name:ChinaNet-Q5uk
wifi passwrod:0921608677
connecting to network...
...省略若干行日志...
I (256217) network: CONNECTED
I (258397) event: sta ip: 192.168.2.189, mask: 255.255.255.0, gw: 192.168.2.1
I (258397) network: GOT_IP
network config: ('192.168.2.189', '255.255.255.0', '192.168.2.1', '192.168.2.1')
MicroPython v1.9.4-429-ge755bd493 on 2018-08-03; ESP32 module with ESP32
Type "help()" for more information.
>>>
總結
- MicroPython ESP32 wifi連接
connect()
函數不是同步執(zhí)行的,為了正確的判斷wifi的連接狀態(tài),需要一定的延時 - 當
connect()
函數從錯誤的essid和password連接時,會在repl中進行輸出死循環(huán),需要將連接自行斷開以解決此問題. - 1ZLAB為你貼出了更加合理的wifi連接代碼,請拿去開心.
交流
如果你對我寫的文章中的內容感到困惑,歡迎評論區(qū)參與討論或指教
沒有賬號的話可以郵箱聯(lián)系:Fuermohao@outlook.com