2019年7月21日 星期日

MicroPython on ESP32 學習筆記 (八) : 用 WebREPL 介面無頭存取

學習或測試 ESP8266/ESP32 開發板時最直接的方式就是插入電腦的 USB 槽, 利用 Putty 進入 REPL 介面下指令, 或者用 ampy 或 mpfshell 等檔案管理工具將程式上傳到開發板. 但是對一些 Ultrabook 來說就不太方便了, 因為 USB 槽只有一個, 但充電或滑鼠要用, 甚至沒有 USB 槽. 即使有可用的 USB 槽, 每次都要插拔 USB 也很麻煩. WebREPL 就是為了解決這問題而存在, 只要在開機程式 boot.py 中開啟並設定好本身 AP 介面之後即可用 WebREPL 進行無頭存取, 以後都不用再插 USB 槽了.

有時 ampy 因為不明原因無法連線時, WebREPL 就可以救急. 例如我之前在 main.py 中使用雙重無窮迴圈實作 Web 伺服器以便設定要連線之 AP 帳密, 但程式錯誤想要用 ampy 竟無法連線, 但使用 WebREPL 就可以. 而且即使 Putty 連線還存在情況下, WebREPL 也可以連線成功 (而且兩者連動, 在 Putty 下指令時, WebREPL 也同步顯示, 反之亦然), ampy 就不行, 下 ampy 指令時 Putty 一定要關掉, 否則 ampy 連線會失敗.

總之, WebREPL 可以擺脫 USB 傳輸線, 實現無線存取 ESP32 的目的. 參考下面這幾篇篇不錯的教學 :

通过WiFi连接到REPL
How to setup WebREPL to connect to Python prompt (REPL) of ESP8266 over WIFI network?


1. 開啟 WebREPL 功能 : 

要用 WebREPL 介面管理檔案與操作 ESP32 首先須在 REPL 介面下達 import webrepl_setup 指令開啟 WebREPL 功能並設定連線密碼 :

>>> import webrepl_setup     
WebREPL daemon auto-start status: disabled

Would you like to (E)nable or (D)isable it running on boot?
(Empty line to quit)
> E                        #輸入大寫 E 開啟 WebREPL 功能
To enable WebREPL, you must set password for it
New password (4-9 chars): 123456        #自訂 WebREPL 連線密碼
Confirm password: 123456 
Changes will be activated after reboot
Would you like to reboot now? (y/n)y     #重開機才生效

重開機後檢查 boot.py 會發現原先在 import webrepl 與 webrepl.start() 指令前面的註解都被拿掉了, 亦即每次開機都會開啟 WebREPL 功能 :

import webrepl
webrepl.start()

參考下面這兩篇中關於 WebREPL 的說明 :

MicroPython on ESP32 學習筆記 (一) : 燒錄韌體
MicroPython on ESP8266 (五) : WiFi 連線與 WebREPL 測試


2. 啟動 WiFi 介面 : 

因為 WebREPL 是透過無線網路操控 ESP32, 因此其 WiFi 介面必須開啟, 最好是開啟 STA+AP 雙重模式, 這樣既可以透過連線 ESP32 本身 AP 來使用 WebREPL, 也可以透過筆電與 ESP32 共同連線的外部 AP 來使用 WebREPL. 關於 WiFi 介面參考 :

MicroPython on ESP32 學習筆記 (三) : WiFi 連線

我綜合前面關於 RTC 與 WiFi 測試的結果, 將網路與時間的操作寫成如下的 boot.py 程式, 讓 ESP32 一開機就自動開啟 AP + STA 兩個 WiFi 介面, 並提供 scan(), connect(), disconnect(), ip(), now() 等函數方便進行連網與時間查詢操作 :

#program:boot.py
#import esp
#esp.osdebug(None)
import webrepl  
webrepl.start() 

import network
import ubinascii
import time

def connect(ssid, pwd):
    sta.connect(ssid, pwd)
    print('Connecting to WiFi AP=', ssid, ' ...')
    time.sleep(8)
    if sta.isconnected():
        print('Connected: ', sta.ifconfig()[0])
    else:
        print('Can not connect to AP=' + ssid)

def disconnect():
    sta.disconnect()
    return True

def scan():
    aps=sta.scan()
    for ap in aps:
        ssid=ap[0].decode()
        mac=ubinascii.hexlify(ap[1], ':').decode()
        rssi=str(ap[3]) + 'dBm'
        print('{:>20} {:>20} {:>10}'.format(ssid, mac, rssi))

def ip():
    return sta.ifconfig()[0]

def pre0(n):
    if n<10:
        return '0' + str(n)
    else:
        return str(n)

def now():
    from ntptime import settime
    try:
        settime()
    except:
        pass
    utc_epoch=time.mktime(time.localtime())
    Y,M,D,H,m,S,ms,W=time.localtime(utc_epoch + 28800)
    t='%s-%s-%s %s:%s:%s' % (str(Y),pre0(M),pre0(D),pre0(H),pre0(m),pre0(S)) 
    return t

ap=network.WLAN(network.AP_IF)
ap.active(True)
ap.config(authmode=4, password='micropythoN')
sta=network.WLAN(network.STA_IF)
sta.active(True) 

注意, 上面的 boot.py 在開機時自動開啟 AP 模式, 且設定其連線密碼為 'micropythoN', 電腦要連線 ESP32 本身的 AP 以使用 WebREPL 功能時需使用此密碼.

如果不想顯示偵錯訊息, 可以把開頭的 import esp 與 esp.osdebug(None) 前面的註解拿掉. 用 ampy 上傳此 boot.py 重開機後就自動開啟了 STA+AP 混和模式, 可以直接呼叫  scan(), connect(), disconnect(), ip(), now() 等自訂函數, 因記憶體中以建立 sta 與 ap 這兩個 WLAN 物件, 因此也可以呼叫如下的函數進行 WiFi 操作 :

 WLAN 物件的方法 說明
 active([state]) 設定或查詢無線介面為 up (True) 或 down (False)
 config(param/param=value) 設定或查詢無線介面之參數如 mac, ssid 等
 connect(ssid, password) STA 介面連線外部熱點
 disconnect() STA 介面與外部熱點離線 
 ifconfig() 傳回介面的 IP, netmask,gateway, DNS 位址 (tuple)
 isconnected() 查詢 STA 介面是否有連線到外部熱點 (True/False)
 scan() 只用在 STA 物件掃描可供其連線之周圍熱點
 status([param]) 查詢 STA 介面指定之參數值 (例如 'rssi') 或目前介面之狀態 (無參數)


3. 下載 WebREPL 網頁程式 : 

WebREPL 是一個很小的網頁軟體, 除了電腦外, 在 Android 手機中也可以用, 可至 GitHub 下載 :

# https://github.com/micropython/webrepl

將 zip 檔解壓縮後會產生一個 webrepl-master 目錄, 點擊裡面的 webrepl.html 以瀏覽器開啟即可 (建議用 Chrome 或 Firefox, 不過在 Android 手機中要用 Firefox 才行). 左上方的框框內預設為 ws://192.168.4.1:8266/ 表示預設是透過 ESP32 本身的 AP 來使用 WebREPL.




其實 WebREPL 有兩種使用方式 :
  1. 透過 ESP32 本身的 AP 
  2. 透過 ESP32 與筆電共同連線之外部 AP
第二種方式必須在 ESP32 以連線到外部 AP 並獲指派一個 IP 才行, 因此需先用第一種方式進入 WebREPL 介面後, 再呼叫 connect() 連線外部 AP. 使用哪一種方式端視電腦是否要連接 Internet 而定, 因為若使用預設之第一種方式, 筆電必須連線到 ESP32 本身的 AP, 即筆電將無法同時上 Internet.


4. 透過 ESP32 本身 AP 使用 WebREPL :

這種情況不需要外部 AP, 筆電需先開啟 WiFi 連線 ESP32 本身的 AP (SSID 為 'ESP32_XXXX', 密碼為上面 boot.py 中所設定的 'micropythoN'), 左上方框框內連線位址為 ws://192.168.4.1:8266/, 按 "Connect" 鈕應該會出現 Password: 提示, 輸入之前用 import webrepl_setup 啟用 WebREPL 功能時所設定之連線密碼即可.




若回應 WebREPL Connected 與 REPL 提示號即連線成功, 可在此輸入 MicroPython 指令, 例如呼叫 connect() 連線外部 AP, 或使用右方框中的檔案上傳或下載功能.


5. 透過 ESP32 與筆電共同連線之外部 AP 使用 WebREPL :

此種用法是 ESP32 與筆電都要同時連線到外部 AP, 然後透過此 AP 使用 WebREPL 功能, 好處是筆電可以同時上網. 先用上面透過 ESP32 本身 AP 方式進入 WebREPL 介面後, 呼叫 connect() 連線外部 AP, 獲得指配之 IP 後就可以改用此 IP 位址以 WebREPL 連線 ESP32, 我比較喜歡這種方式, 因為這樣原先連線 ESP32 本身 AP 的筆電就可以連外部 AP 上 Internet 了 :

>>> connect('EDIMAX-tony','blablabla')   
Connecting to WiFi AP= EDIMAX-tony  ...
I (3225810) wifi: new:<11,2>, old:<11,0>, ap:<11,2>, sta:<11,2>, prof:11
I (3225810) wifi: state: init -> auth (b0)
I (3225820) wifi: state: auth -> assoc (0)
I (3225830) wifi: state: assoc -> run (10)
I (3225840) wifi: connected with EDIMAX-tony, channel 11, bssid = 80:1f:02:47:1e:a8
I (3225840) wifi: pm start, type: 1

I (3225840) network: CONNECTED
I (3227260) event: sta ip: 192.168.2.108, mask: 255.255.255.0, gw: 192.168.2.2
I (3227260) network: GOT_IP
Connected:  192.168.2.108 
>>> now()
'2019-07-21 14:06:37'
>>> ip() 
'192.168.2.108

可見 ESP32 已經連線至外部 AP 成功, 並獲得指配 192.168.2.108 這個 IP. 然後開啟 WebREPL 網頁 webrepl.html, 將上方框框預設的 ws://192.168.4.1:8266/ 改為 ws://192.168.2.108:8266/ 按 "Connect" 即可 :




WebREPL 介面的缺點是檔案管理功能只有上傳與下載, 不像 ampy 還可以顯示目錄內容, 新增目錄, 刪除目錄或檔案等. 不過也沒關係, 可以用 MicroPython 內建的 os 模組在 WebREPL 介面中操作 :

 os 模組方法 說明
 listdir(dir) 顯示目錄 dir 內容, 例如 '.', '..' 或 'lib'
 mkdir(dir) 新增目錄 dir, 例如 'lib'
 rmdir(dir) 刪除目錄 dir, 例如 'lib' 或 '../lib'
 chdir(dir) 切換至目錄 dir, 例如 'lib' 或 '../lib'
 getcwd() 顯示目前工作目錄
 rename(old, new) 更改檔名 old 為 new
 remove(file) 刪除檔案 file

參考 :

MicroPython on ESP32 學習筆記 (二) : 檔案系統


2019-07-22 補充 :

我找到一個可以在 Android 安裝的 WebREPL App, 但此 App 沒有發布到 Google Play 上, 而是下載 APK 檔安裝. 參考 :

MicroPython WebREPL on Android
# MicroPython WebREPL APK download

這樣就可以用 Android 手機無線存取 ESP32 了.

今天遇到一個問題, WebREPL 過一段時間沒有使用再次連線失敗, 一直出現 disconnect, 即使關掉網頁重開也是一樣, 這應該是連線咬住了, 觀察 Putty 視窗則是印出如下訊息 :

Concurrent WebREPL connection from ('192.168.43.14', 9001) rejected

Concurrent WebREPL connection from ('192.168.43.14', 9002) rejected

Concurrent WebREPL connection from ('192.168.43.14', 9003) rejected

Concurrent WebREPL connection from ('192.168.43.14', 9004) rejected

Concurrent WebREPL connection from ('192.168.43.14', 9005) rejected

可見每按一次 Connect 鈕, WebREPL 就透過不同的 port 向 ESP32 發出連線要求, 但應該是 WebREPL 僅支援一個連線所以才被拒絕連線, 參考下面這篇, 應該就是 WebREPL 的原始碼 :

webrepl: Enforce only one concurrent WebREPL connection

如果同時有 USB 連線, 可在 Putty 的 REPL 介面中呼叫 webrepl.stop() 關閉 WebREPL 功能再呼叫 webrepl.start() 即可 :

>>> webrepl.stop() 
>>> webrepl.start() 
WebREPL daemon started on ws://192.168.4.1:8266
WebREPL daemon started on ws://192.168.43.177:8266
Started webrepl in normal mode
>>>
WebREPL connection from: ('192.168.43.14', 9053)

但如果本來就是無頭存取沒接 USB 線就沒辦法下 stop() 了, 只好按 rest 鍵重開機. 

沒有留言 :