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

出品: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

推廣

ad.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子百新,更是在濱河造成了極大的恐慌檬贰,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遵湖,死亡現(xiàn)場離奇詭異悔政,居然都是意外死亡,警方通過查閱死者的電腦和手機延旧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門谋国,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迁沫,你說我怎么就攤上這事芦瘾“莆茫” “怎么了?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵近弟,是天一觀的道長缅糟。 經常有香客問我,道長祷愉,這世上最難降的妖魔是什么窗宦? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮二鳄,結果婚禮上赴涵,老公的妹妹穿的比我還像新娘。我一直安慰自己泥从,他們只是感情好句占,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著躯嫉,像睡著了一般纱烘。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祈餐,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天擂啥,我揣著相機與錄音,去河邊找鬼帆阳。 笑死哺壶,一個胖子當著我的面吹牛,可吹牛的內容都是我干的蜒谤。 我是一名探鬼主播山宾,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼鳍徽!你這毒婦竟也來了资锰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤阶祭,失蹤者是張志新(化名)和其女友劉穎绷杜,沒想到半個月后,有當地人在樹林里發(fā)現(xiàn)了一具尸體濒募,經...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡鞭盟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瑰剃。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片齿诉。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出鹃两,到底是詐尸還是另有隱情遗座,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布俊扳,位于F島的核電站途蒋,受9級特大地震影響,放射性物質發(fā)生泄漏馋记。R本人自食惡果不足惜号坡,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望梯醒。 院中可真熱鬧宽堆,春花似錦、人聲如沸茸习。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽号胚。三九已至籽慢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間猫胁,已是汗流浹背箱亿。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留弃秆,地道東北人届惋。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像菠赚,于是被迫代替她去往敵國和親脑豹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348