2020年7月6日 星期一

七.1-2 使用者可自行選擇連接WiFi分享器實習之一

七.1-2 使用者可自行選擇連接WiFi分享器實習之一

前面說過如果我們的IOT物連網系統只能在一個區域內使用卻無法連結上浩瀚無邊的網際網路(Internet)的話只能算是一個半吊子的物連網但是如果只能在設計程式的時候直接把要用的無線WiFi分享器參數燒在晶片內就太沒有彈性除了除了不方便之外也很難有商用化的可能。因此在這個範例實習中將教導各位如何利用人家已經寫好的函式庫設計一個可由使用者自行選定要用的無線WiFi分享器的方法但是最重要的是在使用這個函式庫之後所需撰寫的程式沒有幾行這樣一來就可以減少開發者很多的負擔

在Arduino的世界裡,最早出現的一個可供ESP8266用來設定使用者自行連線的函式庫,是一個名為「WiFiManager.h」的函式庫,作者為”tzapu”,而其原始來源網站為「https://github.com/tzapu/WiFiManager」。後續也陸陸續續有其他的高手提出類似功能的函式庫出來供大家使用不過筆者的遭遇是安裝太多個以後整個Arduino IDE環境就變得一團亂衝突一大堆而且雖然說這個函式庫的功能很強但還是感覺不太能符合自己的需求因此就放棄使用改由自己寫了一個中文化的連線設定介面程式這個連線程式自己用是沒問題但由於程式碼很長又沒空把它寫成函式庫如果直接拿來教學恐怕會打擊學者的信心因此又上窮碧落下黃泉再次從網海中去找尋簡單又易用程式庫終於皇天不負苦心人找到了本範例程式所要介紹的這個名為「WiFiConnect.h」的函式庫,此函式庫原始來源網站為「https://github.com/smurf0969/WiFiConnect有興趣了解更多內容的讀者可以到這個網頁去看一下。

在這個網站中,原作者Stuart Blair也提到他之所以會撰寫這個函式庫,主要也是覺得前面提到的「WiFiManager.h」函式庫不勿太符合他的需求,所以決定以前面的函式庫為藍本自己動手寫一個,看來文人相輕自古皆然啊!這個函式庫最大的優點就是簡單易用,而且還加了一個有OLED顯示器的加強版而這個版本也就是下一個範例實習要介紹的

接下來就為各位介紹如何安裝這個函式庫,首先在Arduino IDE中點選「草稿碼🡪匯入程式庫🡪管理程式庫」,一直到開啟下面的【圖七•1-2_1程式庫管理員」為止。接著在標記1的地方輸入”WiFiconnect”這個搜尋特徵字串,此時應該很容易就可以在下方的程式庫視窗中看到標記2的『WiFiconnect』選項,目前撰寫此文時是在1.01版。

圖七•1-2_1  WiFiConnect.h函式庫安裝方法圖


根據作者的說明,要使用這個函式庫,你的Arduino IDE版本必須在1.8.8(含)以上,而且還用到「ArduinoJson 6.9.1」這個版本的函式庫(只針對本範例),如果編譯時出現找不到這個函式庫的錯誤訊息,請自行再加裝它。


功能與動作說明

1、本範例在建構一可由使用者自行選定所要使用的WiFi分享器之ESPXX系列晶片IOT物聯網系統此系統可使用ESP8266系列或是ESP32系列的晶片模組。

2、此系統在開機時會自行連上最後一次連線的WiFi分享器,如果連線失敗,系統會自動進入可重新設定連線的本地AP模式(IP預設為:192.168.4.1),使用者可使用如手機等具無線WiFi介面的行動通訊裝置,連線進入本機內建的網頁伺服器頁面進行重新設定的動作。當進入連線設定功能時,內建的指示LED會以間隔0.2秒的速度快速亮滅5次後,進入恆亮的狀態等待使用者連線。

3、如果使用者想要更換所使用的WiFi分享器,可以在重新開機時按下重新設定按鈕,同樣的可以進入上述的重新設定連線功能。

4、當連線成功時,內建的指示LED會以間隔0.4秒的速度亮滅5次後,進入恆亮的狀態代表連線成功。


電路圖

圖七•1-2_2  使用WeMos D1 R2模組板D7/GPIO13電路圖


WeMos D1 R1這塊模組板是把ESP8266做成了與Arduino Uno外觀與接腳相容的板子但是他上面標示的腳位並不是ESP8266原本的GPIO腳位;在我們這個範例中使用GPIO13當作使用者連線設定按鈕的輸入腳而在WeMos D1 R1這塊模組板上GPIO3🡺D7這根接腳因為在程式中已經把這根接腳設定為有內部提升電阻的入腳所在外面直接使用一個另一端接地的按鍵就可以了。


圖七•1-2_3  使用ESP32 DevKit模組板連接D13/GPIO13電路圖


如果你打算使用採用ESP-WROOM-32這片郵票板所做成的模組板來測試例如NodeMcu ESP32 DevKit型的模組板那上面的接腳編號就直接可對應到原來的GPIO腳位因此就可以把這個連線設定按鈕接在D13腳上。


程式列表與說明



 

#include "WiFiConnect.h" 

 

#ifdef ESP32        // 測試使否使用ESP32系列晶片

  int ledOn=1;

  int ledOff=0;

#else               // 或是使用ESP8266系列晶片

  int ledOn=0;

  int ledOff=1;

#endif

 

WiFiConnect wc;     // 宣告一WiFiConnect類別物件變數

 

const byte  setConnectPin=13;    // 選定GPIO13腳為設定連接腳

const byte  indLED=2;           // ESP系列模組郵票板指示用LED腳位

 

// 連線設定回應副程式:

void configModeCallback(WiFiConnect *mWiFiConnect) {

  Serial.println("Entering Access Point!");

  Serial.println("進入 AP 存取點模式!");

}

 

// WiFi連線設定副程式 :

void startWiFi(boolean showParams = false) {

 

  // 啟動函式庫內建偵錯副程式

  wc.setDebug(true);

  // 設定連線回應副程式 

  wc.setAPCallback(configModeCallback);

  // 啟動WiFi連線參數清除

  //wc.resetSettings(); // 可用來清除之前連線所儲存的所有參數

    /*

       AP_NONE = Continue executing code   --> 繼續往下執行

       AP_LOOP = Trap in a continuous loop --> 進入無窮AP設定迴圈狀態

       AP_RESET = Restart the chip         --> 啟動晶片重置動作

    */

    if ((digitalRead(setConnectPin)==0)|| !wc.autoConnect()) { 

   // 測試是否按下WiFi連線按鍵,及ESPXX晶片是否自動連上WiFi分享器

      // 若任一條件成立則進入使用者連線設定功能:

      for(int i=0;i<5;i++)        // 讓指示LED快閃(0.2秒)5次

      {

        digitalWrite(indLED,ledOn);

        delay(200);

        digitalWrite(indLED,ledOff);

        delay(200);

      }

      delay(1000);

      digitalWrite(indLED,ledOn);   // 最後讓指示LED恆亮代表進入連線模式       

      wc.startConfigurationPortal(AP_LOOP); //啟動連線設定功能

    }

}   // WiFi連線設定副程式結束

 

// setup() 初始化部開始:

void setup() {

  Serial.begin(115200);

  pinMode(indLED,OUTPUT);

  pinMode(setConnectPin,INPUT_PULLUP);

  Serial.println();

  Serial.println("Program Start!");

  Serial.println("程式開始!");

  delay(100);

 

  // 啟動WiFi連線副程式

  startWiFi();

  // WiFi連線成功 :

  Serial.println();

  Serial.print("WiFi Connected, IP address: ");

  Serial.println(WiFi.localIP());

  Serial.print("連線成功, 本地WiFi的IP位址為 : ");

  Serial.println(WiFi.localIP());

  Serial.println();

  for(int i=0;i<5;i++)        // 讓指示LED快閃(0.3秒)5次

  {

    digitalWrite(indLED,ledOn);

    delay(300);

    digitalWrite(indLED,ledOff);

    delay(300);

  }

  delay(1000);

  digitalWrite(indLED,ledOn);     // 最後讓指示LED恆亮代表已經連線成功

  delay(1000);

} // setup() 初始化部分結束

 

// loop() 主迴圈部分開始:

void loop() {

  delay(100);

  // 如果在主程式中發現WiFi連線斷開,令系統重置重新開始!

  if (WiFi.status() != WL_CONNECTED) {

    if (!wc.autoConnect()) wc.startConfigurationPortal(AP_RESET);

  }

} // loop() 主迴圈部分結束



程式名稱ESP_CH7_AutoConnect1.ino

本範例程式是由函式庫中原版的「BasicAutoConnect.ino」程式修改而來,主要是為了讓它能有更多更方便的用途。在程式開始的第一行就是先引入本次範例所用到的也最重要的函式庫,而且除了這個函式庫之外,整個程式就沒有再需要引用到其他的函式庫了!


  1. #include "WiFiConnect.h" 


接著3~9行的程式內容與功用和上一個範例相同,主要是為了配合不同系列的ESPXX晶片模組板結構上的不同。11~14行宣告了一些變數其中用來指定設定連接腳的「setConnectPin」讀者可依自己的需要或喜好改成其他的接腳不過要注意ESPXX系列晶片中有一些接腳因為有多重用途所以不是隨便就可以拿來當輸入輸出用詳細的接腳功能內容及使用方法可回去第二章參考一下。


  1. WiFiConnect wc;     // 宣告一WiFiConnect類別物件變數

12.

13. const byte  setConnectPin=13;    // 選定GPIO13腳為設定連接腳

14. const byte  indLED=2;           // ESP系列模組郵票板指示用LED腳位


在函式庫「BasicAutoConnect.ino」原版的範例程式中有設計一個連線設定回應的副程式可是只有一行實在看不出有甚麼特別用途在此筆者只是加上一行中文的回應訊息如果覺得沒必要可以把它刪除


// 連線設定回應副程式:

void configModeCallback(WiFiConnect *mWiFiConnect) {

  Serial.println("Entering Access Point!");

  Serial.println("進入 AP 存取點模式!");

}


在這個範例程式中,真正有用的是23~50行的WiFi連線設定副程式:『void startWiFi(boolean showParams = false){}』,程式一開始先啟動函式庫內建的連線偵錯副程式「wc.setDebug(true)」,這樣一來所有的連線過程,包括參數的傳遞及動作執行的結果,都可以在Arduino IDE的序列監控視窗中看到這對程式設計及系統開發者有很大的幫助萬一結果不對就可以很容易的找出問題所在


25.  // 啟動函式庫內建偵錯副程式

26.  wc.setDebug(true);

由於ESPXX系列的晶片在連線過特定的WiFi分享器之後會把這個分享器的所有連線參數如SSID與密碼都儲存起來這樣一來在下次重新上電開機時很多人可能不知道如果你的ESPXX系列晶片有執行過自動連線的功能就會自動的連接最後一次連線的WiFi分享器因此原本的範例程式中除非連線失敗否則是不會進入使用者連線設定模式的這樣一來初次學習者可能會感覺不到這個函式庫的功用除非你實驗用的模組是第一次使用。

因為這個緣故所以原作者在函式庫中提供了下面這指令好讓使用者可以用來清除之前連線所儲存的所有參數;不過要記得先把註解符號”//”拿掉等燒錄成功之後原來的範例程式是不會再有任何動作的此時再把這個指令註解掉你就會有一個看起來是全新的ESPXX系列模組可用了!


29.  // 啟動WiFi連線參數清除

30.  //wc.resetSettings(); // 可用來清除之前連線所儲存的所有參數


說實在原來的範例程式的確是簡單又好用可是設想的應用情境不算完整所以感覺有些美中不足不是很夠用;如我們使用的場域有好幾個WiFi分享器可用但是我們之前連上的可能因某些原因如被移動位置導致信號減弱因而讓連線狀況不穩定這時想要換一個WiFi分享器就不太容易了。

針對這個缺點筆者在判斷是否要啟動使用者連線設定功能時多加了一個判斷條件也就是如果在開機時連線設定輸入接腳(即GPIO13)有被按下的話就跟連線失敗一樣都會啟動使用者連線設定功能。


36.    if ((digitalRead(setConnectPin)==0)|| !wc.autoConnect()) { 

37.   // 測試是否按下WiFi連線按鍵,及ESPXX晶片是否自動連上WiFi分享器

38.      // 若任一條件成立則進入使用者連線設定功能:

39.      for(int i=0;i<5;i++)        // 讓指示LED快閃(0.2秒)5次

40.      {

41.        digitalWrite(indLED,ledOn);

42.        delay(200);

43.        digitalWrite(indLED,ledOff);

44.        delay(200);

45.      }

46.      delay(1000);

47.      digitalWrite(indLED,ledOn);  // 最後讓指示LED恆亮代表進入連線模式       

48.      wc.startConfigurationPortal(AP_LOOP); //啟動連線設定功能

49.    }


至於39~46行程式主要是為了讓使用者知道已經進入WiFi分享器連線設定模式因此利用ESPXX系列模組板內建的指示LED執行快閃(0.2秒)5次後再保持恆亮的方式作為提示之用。


其實整個函式庫中最重要也是最有用的指令就是下面這個副程式所有的連線設定功能盡在其中使用者也不用管動作有多複雜只要正確的呼叫來用就可以了!


48.      wc.startConfigurationPortal(AP_LOOP); //啟動連線設定功能


在原作者的設計中,這個指令共有三種參數可以選用,第一個「AP_NONE」代表遇到自動連線失敗時,就不管了三七二十一直接跳過去不予理會。而第二個「AP_LOOP」則是遇到自動連線失敗時,會令ESPXX晶片進入AP模式,並等待使用者連上系統的內建伺服器網頁,進行WiFi分享器連線設定的功能。至於最後一個「AP_RESET」則是乾脆把晶片重置重新開機。使用者可依自己的需要使用不同的設定參數。


    /*

       AP_NONE = Continue executing code   --> 繼續往下執行

       AP_LOOP = Trap in a continuous loop --> 進入無窮AP設定迴圈狀態

       AP_RESET = Restart the chip         --> 啟動晶片重置動作

    */


在setup()初始化部分開始的54~60行和前一個範例程式差不多唯一不同的就是多了一行用來設定連線輸入接腳「setConnectPin」的輸入模式為內部有提升電阻的狀態這樣一來可以節省一個輸入按鈕要用的外部電阻


56.  pinMode(setConnectPin,INPUT_PULLUP);


第63行程式在呼叫最核心的startWiFi()」副程式後就靜待連線的結果如果成功連上WiFi分享器的話剩下的71~80行程式就和前一個範例程式的後半段一樣會令ESPXX模組板上的指示LED以間隔0.4秒的速度亮滅5次後,進入恆亮的狀態代表連線成功。


62.  // 啟動WiFi連線副程式

63.  startWiFi();


在前一個範例中我們的主迴圈程式「loop() {}是空的因為這是設計者自己要處理或發揮的部分在此可以加上一段定時檢測連線狀態的程式這樣一來如果在主程式中發現WiFi連線斷開就可以讓系統進入重置狀態重新開始啟動。


  delay(100);

  // 如果在主程式中發現WiFi連線斷開,令系統重置重新開始!

  if (WiFi.status() != WL_CONNECTED) {

    if (!wc.autoConnect()) wc.startConfigurationPortal(AP_RESET);

  }


執行結果:

當ESPXX晶片系統開機並進入使用者連線設定功能時,如【圖七•1-2_4】所示,可分別在Arduino IDE的序列監控視窗中(圖左邊),看到相關的提示訊息;其中標記1在提示系統已經進入內部AP存取點的模式,而標記2則是顯示此AP點的SSID名稱,為了避免同時間有許多的ESPXX晶片都在進行同樣的動作,如果使用了相同的SSID名稱,就會天下大亂了!所以這個函式庫會以文字「ESP_」加上該ESPXX晶片的內部序號作為此AP點的SSID名稱,這樣就不會有名稱重複的問題了。


圖七•1-2_4  ESPXX模組進入連線設定模式Arduino IDE監控視窗與手機畫面


至於標記3則是此AP點內建網路伺服器的預設IP位址,其值為ESPXX晶片標準的預設值:[192.168.4.1];當系統已經進入內部AP存取點的模式時,如果使用者過了很久還沒有用手機連上線的話,就會看到標記4的提示訊息,也就是會處於無窮迴圈狀態,當看到這個訊息時,只能重新開機才能再進行連線設定的動作。

最後圖右邊的標記5是使用者手機打開WiFi掃描功能時,會在螢幕上看到的內容,這個AP存取點名稱應該會在可用WiFi分享器的列表上,要注意的是這個AP存取點並沒有使用連線密碼的功能,所以不要讓我們的系統長時間處在這種不安全的狀態中,要儘快完成連線設定的動作。

當使用者的手機連上ESPXX晶片的軟體AP點WiFi分享器之後,啟動瀏覽器並輸入IP位址:[192.168.4.1]以連接伺服器網頁,這時可看到【圖七•1-2_5】所示的畫面;其中標記1的部分是由之前啟動的連線偵錯副程式「wc.setDebug(true)」所送來的,內容為ESPXX晶片與手機瀏覽器的通訊過程表示已經送出設定用的網頁(圖右)到手機端了凡是由 [*WC : XXXX..]這種文字所開始的訊息都是這個偵錯副程式所提供。接著點選右圖手機上標記2的按鈕進行周圍可用WiFi分享器掃描的動作

圖七•1-2_5  手機已連線ESPXX模組Arduino IDE監控視窗與手機畫面


圖七•1-2_6  手機選取掃描設定鍵後Arduino IDE監控視窗與手機畫面


如果掃描成功將會看到【圖七•1-2_6】的畫面,圖左是Arduino IDE監控視窗的內容,標記1的部分是ESPXX晶片所掃描的周圍可見的WiFi分享器,而右圖標記2的部分,則是ESPXX晶片傳送到手機瀏覽器的內容,正常兩者內容應該一樣,在此因為截圖的時間不一致所以有些落差。接著使用者可用點選的方式,或是直接在標記3輸入要選取的SSID名稱,並在標記4的地方輸入這個SSID的連線密碼,最後按下標記5的「SAVE」按鈕,便完成所有的WiFi分享器連線設定工作了!


圖七•1-2_7  手機選取SSID與輸入密碼完成設定後畫面


當使用者按下上圖標記5的「SAVE」按鈕之後手機的瀏覽器會把儲存及連線的指令送給我們的ESPXX晶片此時可以在Arduino IDE監控視窗內看到【圖七•1-2_7】的畫面,其中圖右是手機的螢幕可看到標記1所示的訊息告訴使用者已經通知ESPXX晶片開始連線但成不成功並不會回傳到手機上而標記2則是顯示ESPXX晶片連線的過程如果成功的話就會看到標記3的訊息這部分是我們這個範例程式加上去的除了提醒使用者連線成功之外還會顯示連線到的WiFi分享器所分配給這個ESPXX晶片的本地IP位址

操作到這裡由使用者自行設定使用WiFi分享器的動作算是大功告成功德圓滿


1 則留言:

  1. 開發板 NodeMCU 1.0 (ESP-12E Module) 編譯錯誤

    回覆刪除