2021年6月3日 星期四

ESP32 以 AP(Access Point) 設置 Web Server

        ESP32預設是 STA模式,架設 Web Server必須連上一台無線基地台(AP),並用基地台分配的IP作為手機連線之用。如果用這種方式來做的遙控自走車,還必須要附加一個AP,那實在很不方便,而且如果要實作無人機,就會受到AP無限距離的影響,所以 ESP32 除了STA模式外,還有AP模式。

一、使用ESP32的AP模式
        再把ESP32設定成AP模式,有些參考書籍,除了WiFi.h要引用兩個 head檔:
        #include <WiFiClient.h>
        #include <WiFiAP.h>
        但實際測試,只要有引用 #include <WiFi.h>,這兩個 head檔是可以不用引用。

二、設定基地台(AP)的SSID及密碼:

        const char* ssid     = "ESP32";        
        const char* password = "1234567890";
        這個是想要將 ESP32設定成AP,當手機要連上ESP32時,就必須要先搜尋到 ESP32這個基
        地台,再輸入登入密碼:124567890,就可以將手機連線到ESP32作為的基地台(AP)。

三、啟動ESP32為AP模式,使用設定的SSID及password,作為其他登入設備所連線的資料。
       
         WiFi.softAP(ssid,password);
  
四、設定一個資料型態是 IPAddress的 ESP32IP的變數,用來記錄將ESP32設定成AP後的IP位
        址。
        IPAddress esp32IP=WiFi.softAPIP();
五、將AP的IP位址顯示在監視視窗(monitor)或是OLED顯示器上。

六、此時就可以使用手機上的瀏覽器輸入在監視視窗或是OLED上顯示IP位址。

七、手機就可以藉由了瀏覽器與ESP32做溝通。
 



























參考:

MicroPython在 ESP8266/ESP32(二) 使用 Thonny 開發工具

         除了 uPyCraft 整合開發環境(IDE)外,還有一套開發整合環境 Thonny,提供了 Windows, Mac OS X, and Linux版本。這是

         下載 Thonny 的官方網址:https://thonny.org/。在進入 Thonny 網站後,點選右上方的 Windows版本,就會下載 Thonny-3.2.7.exe (目前的版本是 3.2.7)。

       
        點選下載的 Thonny檔案,按下滑鼠右鍵,選擇以 系統管理員身分執行(A) 安裝程式,幾個步驟既可完成安裝。在桌面會出現 Thonny 的捷徑。

        執行後,在應用程式下方是 Micropython 的命令視窗(Shell),以直譯的方式執行 Micropython 的指令,可以看到內建 Python 3.7.7版,意謂著在不連結到 ESP8266/ESP32時,是可以直接執行 Python 的指令,不像 uPyCraft 必須先連結上 ESP8266/ESP32,才可以使用 Micropython。

         要設定使用中文環境,可以在功能表 Tools下,選擇 Option。

        在 Generial頁籤下,從 Language 下拉表中選擇 繁體中文-TW,按下 OK 按鈕後,再結束程式後,重新啟動程式,就會成為中文的整合發展環境。

        在Thonny的功能表/執行,使用 選擇直譯器:

        在直譯器的頁籤中,可以選擇Thonny要使用那一個直譯器來執行程式。如果要當作一般 python的IDE,就選擇第一項 執行Thonny的同一個直譯器(預設值)。

        如果要使用 ESP32上的 MicroPython就選擇 MicroPython(ESP32)。從視窗中也可以看到可以使用 ESP8266上的MicroPython。若是 ESP32上還未燒錄MicroPython的韌體,會出現視窗,選擇ESP32的連接埠(要是電腦同時接上好幾個 ESP32,Thonny可以選擇要跟那一個ESP32通訊),再來就是選擇要燒錄到 ESP32 內 MicroPython 的檔案。按下 install按鈕,就開始進行燒錄韌體。

         先清除 ESP32內的資料( Erasing flash )。

       
        開始燒錄韌體到 ESP32。
        
        燒錄韌體完成:

        出現 Done. 就是這樣簡單的就完成燒錄 MicroPython到 ESP32。
        
        按下確定的按鈕,回到 Thonny的 IDE視窗,在下半部的互動環境( Shell 或是稱作 Terminal)視窗,就可以看到 Thonny開始與 ESP32的 MicroPython 聯繫。


        從Python 3.7.7 (bundled)開始變成 MicroPython v1.12。

        在Shell中輸入:from machine import Pin   #輸入後,按下Enter按鍵
                                    Pin(2, Pin.OUT).value(1)   #輸入後,按下Enter按鍵
        此時,如果 ESP32微控板上的藍色LED會亮起, 表示已經可以和 ESP32 聯繫了。若是按下ESP32上的EN按鈕,讓EPS32重新啟動或是從USB上移除ESP32後,再接回,會發現ESP32上的藍色LED不會亮,這是因為並沒有將指令儲存在ESP32上。               

        接下來,使用程式腳本(Script)的方式將程式撰寫完後上傳到 ESP32。
from machine import Pin
from time import sleep
led = Pin(2, Pin.OUT)
while True:
     led.value(1)
     sleep(0.5)
     led.value(0)
     sleep(0.5)

        寫完程式後, 按下儲存的按鈕,會出現視窗,1.選擇本機,是將Script存在個人電腦內,2.按下 MicroPython設備,則會另外出現視窗顯示 ESP32 上的儲存的檔案。


        由視窗中可以看到 ESP32 上,只有一個檔案 boot.py。在 File name欄位輸入 main.py ,就可以將寫好的程式(Script)上傳到 ESP32。
        
        按下 ESP32微控板上的 EN按鈕(Restart),板上的藍色LED會以每0.5秒間隔閃爍。 ESP32在重新啟動後,會先執行 boot.py檔,之後就會執行 main.py。之後,每一次 ESP32重新接上電源,就會執行 boot.py後就是執行 main.py。


        若是 main.py內的程式是無限迴圈(如不斷的閃爍藍色LED),則互動環境(Shell)無法與 ESP32聯繫,所以必須使用功能列的 Stop按鈕,來停止或是重新啟動後端的程式。



註1:參考網站及資料:https://randomnerdtutorials.com/getting-started-thonny-micropython-python-ide-esp32-esp8266/

2020年8月25日 星期二

ESP32 作為 Web Server

ESP32本身具有WiFi連線的功能,而 ESP32 當作Web Server就是可以將監測的信號傳送到網路上的用戶端或是雲端伺服器。
要將ESP32設定成 Web Server,要有幾個步驟:

一、載入WiFi的函數庫
     
     #include <WiFi.h>

二、設定要連上無線基地台的ID及密碼

    const char* ssid     = "無線基地台的名字";                     
    const char* password = "連上無線基地台的密碼";
    
    ESP32 Web Server成功連上無線基地台後,會得到基地台給虛擬的 IP。因此這個時候在同網段的電腦或是手機,就可以用網頁瀏覽器連上這個 IP,與 ESP32 Web Server連線傳輸。     

三、宣告一個伺服器物件,名稱可以自訂,一般為了容易識別都設成 server;通訊埠也是設定網頁的80。若是要使用其他埠號,則用瀏覽器連上Web Server時,就要加上埠號。
 
    WiFiServer server(80);

     (似乎可以宣告兩個以上的伺服器物件,使用不同的埠號,這以後來測試看看)

四、啟動無線物件開始連結基地台,並不斷偵測無線是否已經連上了。如果沒有連上,每隔0.5秒不斷測試,並在監視視窗顯示狀態。

    WiFi.begin(ssid,password);
    while (WiFi.status() != WL_CONNECTED) {          //利用迴圈偵測無線物件連線的狀態
       delay(500);
       Serial.print(".");
    }

五、啟動 Web Server
    
    server.begin();

六、顯示連上基地台後,分配給 ESP32 Web Server的IP位址。可供同網段的電腦或手機用瀏覽器連線。
    1. 顯示在監視視窗上
        Serial.println("");
        Serial.println("WiFi connected.");
        Serial.println("IP address: ");
        Serial.println(WiFi.localIP());
   
      顯示到連線到無線基地台所分配到的 IP是 192.168.1.116 


    2. 之前使用過 OLED Display,正好也可以將 IP顯示在OLED。這比用USB連線上到ESP32電路板上,才能知道IP位址。
        display.setFont(ArialMT_Plain_16);
        display.drawString(00,00,"WiFi connected.");
        display.drawString(00,20,"IP address: ");
        display.drawString(00,40,WiFi.localIP());
        display.display(); 

    
     在編譯後,OLED顯示器的 drawString()內的參數第3個是字串,跟 localIP()是 IPAddress是不匹配的,所以要把 localIP() 改成 String 資料型態。因此使用String()轉換型態。
     
     String IPAddressofServer = String(Wifi.localIP());
     display.drawString(00,40,IPAddressofServer); 
     

   結果在 OLED 上顯示的 IP 卻不是 192.168.1.116。所以 IPAddress()是整數矩陣型態,無法使用 String()型態轉換。在 Google搜尋了 "IPAddress() to string"的方法,找到了:
      (1).建立一個轉換函數:
           String IpAddress2String(const IPAddress& ipAddress)
            {
                return String(ipAddress[0]) + String(".") +\
                String(ipAddress[1]) + String(".") +\
                String(ipAddress[2]) + String(".") +\
                String(ipAddress[3])  ; 
             }
        
            String IPAddressofServer = IpAddress2String(Wifi.localIP());
            display.drawString(00,40,IPAddressofServer);
     
      (2)後來查到一個Wifi.localIP()內建的方法:WiFi.localIP().toString()
            
            display.drawString(00,40,WiFi.localIP().toString());



















六、現在若是用手機(要在同一個網域,也就是手機也是連上同一台無線基地台)的瀏覽器上,輸入192.168.1.116,是一片空白。接下要設定當有使用端(client)連線上Web Server(ESP32)時,會適當給予回應。
    先宣告一個client物件,是用來 Server有接受到連線時的使用端資訊(client)
     WiFiClient client = server.available();
     if (client) {     
         當有連線到 Web Server,client會接收到連線的資料。
         所以可以使用 client.print(""); 將要顯示在資料顯示在網頁上
     }

   例如:
    void loop() {
        WiFiClient client = server.available(); 
        if (client) {                         
           client.println("HTTP/1.1 200 OK");      //因此顯示第一個顯示網頁的畫面  
           client.println("Content-type:text/html");
           client.println();
           client.print("<h1>");
           client.print(" Web Server");
           client.println("</h1>");     
       }
   }


七、若要控制ESP32(例如傳給值給ESP32的Web Server,將偵測到的溫溼度顯示在OLED上)或是與Web Server互動(再將溫溼度顯示到手機上的網頁),這些首先都是要能把值傳到 ESP32上的Web Server,ESP32再根據接收的資料(控制字元),來判斷要回應甚麼動作。
       
      1.client.read() 是用來讀取網頁上傳送過來的資料
      2.client.connect() 用來確認client端是否還連線在 Web Server上,連線則傳回1,否則傳回0。
                                   我們必須先用這個函數來確認,client還連線在Server,以確保下面讀取到
                                   的資料是由client傳過來的。在測試的時候,曾拿掉這個判斷,會讀到還沒
                                   連線前的資料,造成誤判。
      3.client.available() 用來確認網頁是否有資料可以讀取,如果沒有資料就會傳回0。
      
      4.client傳遞資料的儲存

      String newLine="" ;             //宣告一個字串變數用來儲存clinet傳送過來的資料
      if (c=='\n') {                       //如果讀到的字元是 '\n',表示這個網頁是第一次連上 Web Server。
           if(newLine.length()==0){    //讀到字元\n,而且資料字串是空白,表示clint沒有傳遞資料,
                                                          所以是第一次連到 Server,所以顯示初始的網頁。
             client.println("HTTP/1.1 200 OK");      //初始的網頁,會有一個可以顯示溫溼度的連結  
             client.println("Content-Type:text/html");
             client.println();
             client.println("<!DOCTYPE HTML>");
             client.println("<html>");
             client.print("<h1>");
             client.print(" Web Server");
             client.println("</h1> <h3>");
             client.print("Click <a href=\"/T\">Here</a> to Dispaly Temperature and Humidity.");
             client.println("</h1></h3>");
             client.println("</html>");
             break;                                     //顯示首頁完,跳出while迴圈
           }
           else {          //讀到\n,而資料字串長度不是0,表示已經到client傳遞資料的尾端,清除資料
                                 字串
             newLine="";
           }  
        }
       else if (c!='\r') {  //新的client連線,但讀到資料不是 /n 跟 /r,把讀到的字元存入資料字串     
         newLine +=c;      
       }

    5.判斷資料字串: endsWith用來判斷資料字串(newLine)是否是 "GET /T"結尾的。
             
       if (newLine.endsWith("GET /T")){
           ht();                                                 //呼叫ht()函數,在 OLED上顯示溫濕度  
       }

    6.相關的程式:
   
    void ht(){
         h=dht.readHumidity();
         hh=h;
         t=dht.readTemperature();
         tt=t;
         if (isnan(h)||isnan(t)){
             display.drawString(00,5,"Failed to read from DHT sensor!");
             display.display();
             return;                      
         }
         display.clear();
         display.drawString(00,1,"Humi:");
         display.drawString(60,1,hh);
         display.drawString(90,1,"%");
         display.drawString(00,30,"Temp:");
         display.drawString(60,30,tt);
         display.drawString(90,30,"c");
         display.display();
     }

    void loop() {
        WiFiClient client = server.available(); 
         if (client){                                    //有網頁連線上到 Web Server
             display.clear();
             display.drawString(00,00,"client connected.");
             display.display();
             String newLine="";
             while(client.connected()){
             if (client.available()){                //available()是表示client有傳遞資料 
                 char c=client.read();
                 Serial.write(c);
                 if (c=='\n') {                   //如果讀到的字元是 '\n',表示這個網頁是第一次連上 Server
                    if (newLine.length()==0){
                       client.println("HTTP/1.1 200 OK");      //因此顯示首頁  
                       client.println("Content-Type:text/html");
                       client.println();
                       client.println("<!DOCTYPE HTML>");
                       client.println("<html>");
                       client.print("<h1>");
                       client.print(" Web Server");
                       client.println("</h1> <h3>");
                       client.print("Click <a href=\"/T\">Here</a> to Dispaly Temperature and Humidity.");
                       client.println("</h1></h3>");
                       client.println("</html>");
                       break;                                //顯示首頁完,跳出while迴圈
                   }
                   else {
                          newLine="";
                   }  
                }
                else if (c!='\r') {
                          newLine +=c;      
                }
       
               if (newLine.endsWith("GET /T")){    //呼叫ht()函數,在 OLED上顯示溫濕度  
                    ht();  
               }
            } //available
          } //while
        }
      } //loop


參考資料:
  1.ESP32程式設計(基礎篇),曹永忠,2020年2月,渥瑪數位。

MicroPython在 ESP8266/ESP32(ㄧ) 使用 uPyCraft 開發工具

        除了使用C語言來撰寫控制微控器(MicroController)的程式,目前非常多人使用的Python程式語言也可以撰寫控制程式;只是一般微控器上的記憶體容量並不大,所以無法使用Python的所有功能。因此劍橋大學的 Damien P. George教授開發了 Python的精簡版,能使用在微控器上的 MicroPython。但必須要注意它並非能使用所有Python的函數庫及功能。(註1、2)

         ESP8266及ESP32模組的相片如下,左邊的是ESP8266,右邊的是ESP32。在 Arduino中要燒錄程式到微控器時,都要按右下角的按鈕(BOOT/FLASH)。

        市面上有可以一鍵燒錄的ESP32模組,如下圖。還提供可以外加電源輸入的插槽(左下角)。


        要在 ESP32 或是 ESP8266上使用 MicroPython 前,必須將相對應 MicroPython 的韌體(Firmware)燒錄到微控器上。在 Google上搜尋 MicroPython 就可以找到連接的網址:https://micropython.org/,上方的 DOWNLOAD 網頁內,就可以選擇要搭配相關微控器的MicroPython。

       ESP32:https://micropython.org/download/esp32/

        

        ESP8266:https://micropython.org/download/esp8266/

        網站是使用 esptool.py 來燒錄韌體。但如果對於文字模式的操作有困難,建議可以使用uPyCraft 這套由大陸 DFRoot 公司所推出免費的整合式開發軟體(IDE),它整合了終端機、Python 程式編輯器及軟體線上燒錄的功能。下載網址:https://github.com/DFRobot/uPyCraft。下載zip檔後,解壓縮後,以系統管理員身分執行 uPyCraft 應用程式。

        若是在執行後,出現找不到 MSVCR100.dll 的訊息,請到微軟的下載中心 Download Center
網站:https://www.microsoft.com/en-us/download/details.aspx?id=26999。

        

       Microsoft Visual C++ 2010 Service Pack 1 Redistributable Package MFC Security Update        選擇 Chinese(Traditional) 語系後,按下 Download 按鈕。


        在下載頁面,記得要下載的是 vcredist_86.exe,然後進行安裝。就可以解決問題。
如果選成 vcredist_x64.exe 是沒用有的。猜想  uPyCraft 是不是32位元版的原因。 

        開啟程式後,在 Tools 功能表下,從 board 中選取 esp32,再設定 Serial 中設定 esp32 模組連接的串列埠號(要按各自 esp32 連結到電腦的埠號)。


        若 ESP32模組未安裝 MicroPython韌體的話,uPyCraft會出現下面的視窗:


        此時,可以直接燒錄 uPyCraft所提供的 MicroPython韌體,但還是建議使用 MicroPython官網所提供韌體。burn_addr(燒錄韌體的起始位址)要設定成 0x1000,就可以開始燒錄。

        按下 ok按鈕後,先進行清除(Erase)的工作,如果無法開始清除,試著按住ESP32模組上右下角的BOOT按鍵,直到開始清除。


        清除後,接著就會進行燒錄(Burn)的工作。

        燒錄完,不會出現任何的提示訊息,此時可以按下uPyCraft視窗右邊功能鈕的連結(Connect)。


        連接上 ESP32 模組,在 uPyCraft下半部的 Shell 視窗就會出現 MicroPython 的提示 >>>,可以輸入指令進行測試,另外左邊的視窗,點選 device,會顯示 ESP32模組上的檔案。


        接下來自行輸入一個 python 程式,或是由 範例 (Examples)中選取一個程式,進行測試是否可以在 ESP32 模組上使用 Python,最簡單的測試範例就是可以讓 onBoard 的 LED閃爍。所以選擇 blink.py。


        撰寫好 MicroPython 程式,可以使用功能表 Edit下的 syntaxCheck 進行語法的檢查。
   

        如果有錯誤的地方,例如 while Ture 後面,忘了加上:經過 yntaxCheck 檢查,會在 Shell 視窗出現錯誤的訊息。如下圖:


       語法檢查後,沒有問題就可以在 Tools 功能表下的 DownloadAndRun 命令或是直接按下快捷鍵 F5,將 MicroPython 檔案 (blink.py)上傳到 ESP32 後,執行程式,檢查結果是否正確。


        在 uPyCraft 左邊的視窗,在 device 資料夾中,可以看到剛上傳到 ESP32的檔案 (blink.py), 還有 boot.py。


        如果要執行在 ESP32 內的某個 MicroPython 檔案,可以利用 uPyCraft 左邊的視窗,從 device 資料夾中點選檔案後,按下滑鼠右鍵,選擇 Run 的命令。如果選擇 Default Run,則是 ESP32一接上電源後就會馬上執行程式 blink.py。

 
        選擇 Default Run命令後,會產生一個 main.py檔案,裡面的指令就是 ESP32 接上電源後就會執行的檔案(blink.py)。再按下 ESP32模組上的 RST 或是 EN 按鈕就會看到執行的結果。 如果要停止執行,選擇 Tools功能表下的 Stop命令。


        要注意的是: 如果直接關掉 uPyCraft 程式或是拔起 ESP32模組,再開啟  uPyCraft 或是插回 ESP32模組,此時  uPyCraft 將無法連線上 ESP32模組,會出現重新燒錄韌體的視窗。

       MicroPython檔案系統,在根目錄(device)下常會有兩個 python 檔案:boot.py 與 main.py。在 ESP32開機後,會先去根目錄下找尋 boot.py 檔案,存在的話就先執行此開機檔; 然後再尋找 main.py,如果有的話就會再執行這個程式。 main.py 裡面主要就是一個執行特定應用邏輯無窮迴圈。(註3)

        一旦將 blink.py設定成  Default Run,會產生 main.py 無限迴圈執行檔案,以致關掉uPyCraft程式或是拔起 ESP32模組後 ,uPyCraft 無法連線上 ESP32模組。

       要解決這個問題,若是在設定成  Default Run 後,先從 Tools 功能表下的 Stop 命令停止程式執行,再刪除 main.py,將會出現 delete error。

       

        目前想到解決的方法是:

       1.開啟 main.py

       2.將 main.py內的 exec(open('./main.py').read(),globals()) 程式刪除掉。

       3.再從 Tools 功能表中,選擇 Download命令,將 main.py清除空白。


        如果未清除 main.py 內的 exec(open('./main.py').read(),globals()) ,就關掉 uPyCraft 程式或是拔起 ESP32模組,那除了重新燒錄韌體外,可以選擇用 Thonny 整合開發軟體來刪除 main.py。

        uPyCraft更多的使用方法,請參考註2的說明文件。

        另外要注意的是:使用 uPyCraft 燒錄 ESP8266 韌體時,burn_addr 要設定成 0x0 (預設值)。


註1:超圖解Python物聯網實作入門,趙英傑,旗標出版社(2018)。

註2:uPyCraft簡體中文說明文件:http://docs.dfrobot.com.cn/upycraft

註3:MicroPython on ESP8266 (六) : 檔案系統測試,小狐狸事務所,http://yhhuang1966.blogspot.com/2017/05/micropython-on-esp8266_18.html

註4:經典ESP學習網站(Random Nerd Tutorials): https://randomnerdtutorials.com/