MicroPython-ESP32之更合理的建立wifi連接-1Z實驗室

出品:1Z實驗室 1zlab.com
1ZLAB: Make Things Easy

導(dǎo)引

作為一款支持wifi的物聯(lián)網(wǎng)芯片,ESP32的聯(lián)網(wǎng)方式自然是要重點(diǎn)掌握的.在MicroPython下,聯(lián)網(wǎng)更是一件輕松Easy的事情, 在MicroPython tutorial for ESP8266中,官方給出了MicroPython的WiFi連接示例代碼.但是在實際的應(yīng)用場景中,很多基于物聯(lián)網(wǎng)的工程應(yīng)用,第一要義就是建立網(wǎng)絡(luò)連接.按照這份示例代碼,WIFI確實可以幾步就連接妥當(dāng).但WIFI連接有哪些坑需要注意,如何編寫更合理的WIFI連接代碼呢?

注: 如果你想直接獲取最終解決方案的代碼,請直接跳轉(zhuǎn)至文章尾部.

初試網(wǎng)絡(luò)連接

我們先來看看官方給的示例代碼(部分變量名筆者有所改動):

def do_connect():
    import network #WIFI連接需要引入network包
    wifi = network.WLAN(network.STA_IF)  #創(chuàng)建連接對象 如果讓ESP32接入WIFI的話使用STA_IF模式,若以ESP32為熱點(diǎn),則使用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沒有連接上的話做點(diǎn)什么,這里默認(rèn)pass啥也不做
    print('network config:', wifi.ifconfig())

我們對其稍作改動,將WIFI名字和密碼改為do_connect的參數(shù)

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進(jìn)去:

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())
>>> 

調(diào)用do_connect函數(shù):

>>> 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.

聽說你想開機(jī)自動連接WIFI?

大部分讀者的內(nèi)心獨(dú)白:
大佬: 這還用你教,我寫在main.py里不就好了嗎.
小白: 那每次都要開機(jī)自動輸入一遍WIFI名字和密碼,豈不是很麻煩?
大佬: 寫個配置文件,專門放置WIFI密碼和名字不就好了嗎?

現(xiàn)在我們按照大佬的思路來安排一波:
首先我們創(chuàng)建 main.py,并寫入do_connect函數(shù)的代碼,我們將以讀取配置文件的方式來讀取WIFI的名稱和密碼,因此代碼做如下改動:

def do_connect():
    import json
    import network
    # 嘗試讀取配置文件wifi_confi.json,這里我們以json的方式來存儲WIFI配置
    # wifi_config.json在根目錄下
    
    # 若不是初次運(yùn)行,則將文件中的內(nèi)容讀取并加載到字典變量 config
    try:
        with open('wifi_config.json','r') as f:
            config = json.loads(f.read())
    # 若初次運(yùn)行,則將進(jìn)入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()

然后就可以愉快的重啟了,試試咱們的開機(jī)自動連接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已經(jīng)被刷屏了
>>> 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:當(dāng)你陷入這種repl的輸出死循環(huán)的時候,不要慌張,解決方案還是有的,請先冷靜以下,默默的一字一句輸入import os回車os.remove('main.py')回車,在此過程中請無視repl的輸出,只需保證自己的輸入無誤就OK, 以此刪除你的main.py文件,當(dāng)然你也可以去對癥下藥,但是刪掉main.py重啟是最簡單的方式...

問題已經(jīng)暴露的一覽無余了,更合理的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,什么也沒干.因此我們在此做點(diǎn)文章應(yīng)該就OK了.
可能大部分人和我一開始的思路一樣,刪掉wifi_config.json,重新調(diào)用do_connect函數(shù)進(jìn)行wifi的初始化配置.但這樣的話,可能你永遠(yuǎn)也無法走出這個循環(huán),因為經(jīng)過我多次踩坑之后發(fā)現(xiàn):

connect()函數(shù)執(zhí)行完畢之后并不會等待WIFI連接成功之后才繼續(xù)執(zhí)行,而是直接繼續(xù)往下執(zhí)行.而且connect()本身不會返回任何數(shù)據(jù).

所以接下來的探討分為兩種情況:

  • 1 essid 和 password 正確
    在WIFI沒有真正的建立起連接的時候,wifi.is_connected()一直都返回False,while循環(huán)中的代碼會被循環(huán)執(zhí)行.當(dāng)wifi連接成功建立之后,wifi.is_connected()返回True,跳出while循環(huán),WIFI連接宣告完畢

  • 2 essid 和 password 不正確
    wifi.is_connected()一直都返回False,while循環(huán)中的代碼會被循環(huán)執(zhí)行.并且伴隨著repl的一頓刷屏輸出.

為了解決WIFI連接過程需要耗費(fèi)一定的時間的這個問題,我們需要加上一段延時,在一定延時之后我們再進(jìn)行is_connected()判斷,此時若is_connected()==False,則視為連接失敗,便接著執(zhí)行我們應(yīng)對WIFI環(huán)境改變或其他原因?qū)е碌膃ssid與password認(rèn)證失敗的代碼.
為了阻止repl由于wifi連接失敗產(chǎn)生的刷屏,我們需要將wifi關(guān)閉,調(diào)用wifi.active(False),然后我們刪除wifi_config.json,再遞歸調(diào)用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在根目錄下
    
    # 若不是初次運(yùn)行,則將文件中的內(nèi)容讀取并加載到字典變量 config
    try:
        with open('wifi_config.json','r') as f:
            config = json.loads(f.read())
    # 若初次運(yùn)行,則將進(jìn)入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熱點(diǎn)'.format(i))
            if wifi.isconnected():
                break
            utime.sleep_ms(100) #一般睡個5-10秒,應(yīng)該綽綽有余
        
        if not wifi.isconnected():
            wifi.active(False) #關(guān)掉連接,免得repl死循環(huán)輸出
            print('wifi connection error, please reconnect')
            import os
            # 連續(xù)輸錯essid和password會導(dǎo)致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.
>>> 

總結(jié)

  • MicroPython ESP32 wifi連接connect()函數(shù)不是同步執(zhí)行的,為了正確的判斷wifi的連接狀態(tài),需要一定的延時
  • 當(dāng)connect()函數(shù)從錯誤的essid和password連接時,會在repl中進(jìn)行輸出死循環(huán),需要將連接自行斷開以解決此問題.
  • 1ZLAB為你貼出了更加合理的wifi連接代碼,請拿去開心.

交流

如果你對我寫的文章中的內(nèi)容感到困惑,歡迎評論區(qū)參與討論或指教
沒有賬號的話可以郵箱聯(lián)系:Fuermohao@outlook.com

推廣

ad.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容