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

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

導引

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

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

初試網絡連接

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

def do_connect():
    import network #WIFI連接需要引入network包
    wifi = network.WLAN(network.STA_IF)  #創建連接對象 如果讓ESP32接入WIFI的話使用STA_IF模式,若以ESP32為熱點,則使用AP模式
    if not wifi.isconnected(): #判斷WIFI連接狀態
        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密碼和名字不就好了嗎?

現在我們按照大佬的思路來安排一波:
首先我們創建 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,執行配置文件的創建        
    except:
        essid = input('wifi name:') # 輸入essid
        password = input('wifi passwrod:') # 輸入password
        config = dict(essid=essid, password=password) # 創建字典
        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是否已創建完畢:

>>> 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環境發生改變后,WIFI連接陷入了死循環

小白: 大佬真棒,上面的代碼沒毛病,但是如果WIFI環境一變,好像就陷入了死循環,比如接下來的這波操作:
我們把 wifi_config.json文件刪掉,然后重啟,輸入錯誤的wifi名稱和密碼,以此來模擬WIFI環境的改變:

>>> 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的輸出死循環的時候,不要慌張,解決方案還是有的,請先冷靜以下,默默的一字一句輸入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循環中,,執行循環的條件是wifi沒有連接成功.我們看到目前的做法是pass,什么也沒干.因此我們在此做點文章應該就OK了.
可能大部分人和我一開始的思路一樣,刪掉wifi_config.json,重新調用do_connect函數進行wifi的初始化配置.但這樣的話,可能你永遠也無法走出這個循環,因為經過我多次踩坑之后發現:

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

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

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

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

為了解決WIFI連接過程需要耗費一定的時間的這個問題,我們需要加上一段延時,在一定延時之后我們再進行is_connected()判斷,此時若is_connected()==False,則視為連接失敗,便接著執行我們應對WIFI環境改變或其他原因導致的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,執行配置文件的創建        
    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) # 創建字典
                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死循環輸出
            print('wifi connection error, please reconnect')
            import os
            # 連續輸錯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()函數不是同步執行的,為了正確的判斷wifi的連接狀態,需要一定的延時
  • connect()函數從錯誤的essid和password連接時,會在repl中進行輸出死循環,需要將連接自行斷開以解決此問題.
  • 1ZLAB為你貼出了更加合理的wifi連接代碼,請拿去開心.

交流

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

推廣

ad.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371