2020年10月22日 星期四

四、1 直接使用GET(URI)的方式控制輸出

 四、 ESP32存取點(AP)模式輸出控制及應用

四、1 直接使用GET(URI)的方式控制輸出

在前面的《三、存取點(AP)模式內建網路伺服器(WebServer)設計—GET請的解析》一節中曾說明過,在HTTP 的GET請求中最重要的部分是請求行(request Line) ,所謂的請求行主要包括兩個部份,其中一部分是所謂的URI(Uniform Resource Identifier),即請求的內容,也就是跟著網頁位址後面的訊息例如我們使用瀏覽器連上伺服器網頁首頁時送出的URI內容便是”/而當我們在網址輸入欄鍵入「192.168.4.1/test」這樣的網址資料時URI則是”/test”在本單元中我們就以這個特性示範如何去控制ESP32開發模組板上內建LED的亮滅


電路圖

圖四、1-1 不同類型ESP32開發模組板內建LED(GPIO2)位置


本實習所使用的LED燈為了方便起見所以是採用內建於ESP32開發模組板上GPIO2的LED燈,也就是說所並不需要再外接了!不過並不是所有的ESP32開發模組板上都內建有這顆接在GPIO2的LED燈,上面【圖四、1-1】中的兩款是本實習建議使用的ESP32開發模組板左邊是「WeMos D1 R32」板右邊是常見的「ESP32 DEVKIT」板這顆接在GPIO2的LED燈的位置已標示在圖片中使用者應該很容易找到才是


範例程式功能與動作說明

1、以ESP32建立一無線WiFi  AP存取點,此AP存取點SSID名稱為  『ESP32_softAP01』,而且不使用密碼。

2、此AP存取點內建伺服器的IP位址為:[ 192.168.4.1 ]

3、當客戶端裝置連線上ESP32內建伺服器首頁時(也就是只鍵入IP網址[ 192.168.4.1 ]),系統會回應下面【圖四、1-2】的畫面給客戶端。畫面上方的[Soft AP模式] 使用Get控制單一輸出實習』部分固定不變是用來提示本實習的內容而下方的『請輸入指令(On/Off)』部分則會依操作狀況改變在此是當使用者連上網頁首頁或者是輸入錯誤指令時ESP32開發模組板回應的訊息。


圖四、1-2 系統首頁畫面


4、如果輸入的是: [ 192.168.4.1 /on],則如【圖四、1-3】所示ESP32開發模組板上內建的LED會點亮,而且系統會回應『GPIO2:High --> LED點亮』的訊息給客戶端。


圖四、1-3 使用URI指令「/on」點亮ESP32開發板內建LED畫面


5、如果輸入的是: [ 192.168.0.100 /LedOff],則如【圖四、1-4】所示ESP32開發模組板上內建的LED會熄滅,而且系統會回應『GPIO2:Low --> LED熄滅』的訊息給客戶端。


圖四、1-4 使用URI指令「/off」熄滅ESP32開發板內建LED畫面


6、假如使用者輸入的內容不在前面幾種的條件裡面,那麼系統會則如【圖四、1-2】所示會回應『請輸入指令(On/Off)』這樣的訊息給客戶端,告訴使用者應該輸入什麼樣的指令在此On/Off指令碼中的英文字元大小寫都可以使用以方便使用者操作。


程式列表與說明

以下是這個範例的完整程式內容:

  1. /*

  2. ESP32 soft AP 範例三 : 四、1 直接使用GET(URI)的方式控制輸出

  3. */

  4.  

  5. #include <WiFi.h>

  6. #include  "index.h"

  7.  

  8. const char* ssid     = "ESP32_softAP01";

  9. const char* password = "12345678";

  10. const byte  indLED=2;

  11. String  echoBack="";

  12.  

  13. WiFiServer server(80);

  14.  

  15. // 初始化設定程式開始:

  16. void setup()

  17. {

  18.     Serial.begin(115200);

  19.     pinMode(indLED,OUTPUT);

  20.     delay(10);

  21.  

  22.     // We start by connecting to a WiFi network

  23.     WiFi.softAP(ssid);

  24.     Serial.println("Setting softAP ...");

  25.     Serial.println();

  26.     Serial.print("Your softAP is : ");

  27.     Serial.println(ssid);

  28.     Serial.print("IP address: ");

  29.     Serial.println(WiFi.softAPIP());

  30.     

  31.     server.begin();         // 啟動伺服器功能

  32. }   // 初始化設定程式結束.

  33.  

  34. // 主迴圈程式開始:

  35. void loop(){

  36.   

  37.   WiFiClient client = server.available();   // 監聽是否有客戶端到來

  38.   // wait for a client (web browser) to connect

  39.   if (client)

  40.   {

  41.     echoBack="請輸入指令(On/Off)";

  42.     Serial.println("\n[Client connected]");

  43.     while (client.connected())

  44.     {

  45.       // read line by line what the client (web browser) is requesting

  46.       if (client.available())

  47.       {

  48.         String line = client.readStringUntil('\r');

  49.         line.toUpperCase();

  50.         // Check to see if the client request was "GET /H" or "GET /L":

  51.         if (line.indexOf("GET /ON") >= 0) {

  52.           echoBack="GPIO2:High --> LED點亮";

  53.           Serial.println(line);

  54.           Serial.println(echoBack);

  55.           digitalWrite(indLED, HIGH);       // GET /H turns the LED on

  56.         }

  57.        if (line.indexOf("GET /OFF") >= 0) {

  58.           echoBack="GPIO2:Low --> LED熄滅";

  59.           Serial.println(line);

  60.           Serial.println(echoBack);

  61.           digitalWrite(indLED, LOW); // GET /L turns the LED off

  62.         }

  63.  

  64.         // 測試是否為客戶端請求結束空白行:

  65.         if (line.length() == 1 && line[0] == '\n')

  66.         {

  67.           String tmpString = MAIN_page;    // 取出html網頁回應程式

  68.           tmpString.replace("%echoBack%", echoBack ); //帶入回應字串變數 // 至回應網頁html程式中

  69.           client.print( tmpString );

  70.           break;

  71.       

  72.  }

  73.       }

  74.     }

  75.     delay(1); // give the web browser time to receive the data

  76.     // close the connection:

  77.     client.stop();

  78.     Serial.println("Client Disconnected.");

  79.   }

  80. }   // 主迴圈程式結束.

  81.  

  82. // 以下部分為「index.h」標籤頁面的內容:

  83. const char MAIN_page[] PROGMEM = R"=====(

  84. HTTP/1.1 200 OK

  85. Content-Type:text/html

  86.  

  87. <!DOCTYPE html>

  88. <html>

  89.  <head>

  90.  <meta name='viewport' content='width=device-width, initial-scale=1.0'/>

  91.  <meta charset='utf-8'>

  92.  <link rel="icon" href="data:,">

  93.  <style>

  94.    body {font-size:100%;} 

  95.    #main {display: table; margin: auto;  padding: 0 10px 0 10px; } 

  96.  </style>

  97.    <title>Soft AP模式-使用Get控制單一輸出實習</title>

  98.  </head>

  99.  

  100.  <body> 

  101.    <div id='main'>

  102.      <h2><center>[Soft AP模式] <br>

  103.          使用Get控制單一輸出實習<br><br>

  104.          %echoBack%

  105.          </center>

  106.      </h2>

  107.    </div> 

  108.  </body>

  109. </html>

  110. )=====";

程式名稱:ESP32_softAP4_getRUI.ino


本範例和上一個在初始化程式(setup())部分幾乎完全一樣只是多了19行的設定GPIO2為輸出的功能:


19.    pinMode(indLED,OUTPUT);


而在主迴圈(loop())的部分則多了第41行的預先設定回傳訊息用字串變數echoBack的內容為"請輸入指令(On/Off)"的程式:


41.     echoBack="請輸入指令(On/Off)";


當有客戶端裝置連線到伺服器,主迴圈程式剩下的部分便會開始接收與回應客戶端的請求訊息。43~74行程式是以while()迴圈的方式來持續的接收客戶端傳來的請求訊息,直到接收到代表請求結束的空行字串為止。48~49行程式會逐行讀取客戶端送來的訊息,並把該行字串訊息所有的英文字元轉換成大寫,以方便後面的判斷動作這樣也可以減少使用者因為輸入大小寫的問題而產生錯誤。


48.      String line = client.readStringUntil('\r'); // 逐行讀取客戶端送來的訊息

49.      line.toUpperCase();     // 將該行訊息所有的英文字元轉換成大寫


接著的51~56行程式在判斷客戶端所傳來的URI是否為代表點亮LED的字串『"GET /ON"』﹖如果是,則先將回應訊息字串變數「echoBack」的內容改為『" GPIO2:High --> LED點亮"』,並把訊息顯示在Arduino IDE的監控式窗,最後再點亮接在GPIO2的LED(55行)。


51.        if (line.indexOf("GET /ON") >= 0) {

52.          echoBack="GPIO2:High --> LED點亮";

53.          Serial.println(line);

54.          Serial.println(echoBack);

55.          digitalWrite(indLED, HIGH);         // GET /H turns the LED on

56.        }


再下來的57~62行程式應改很容看出是在測試所傳來的URI是否為代表熄滅LED的字串『"GET /OFF"』﹖如果是,則會將回應訊息字串變數「echoBack」的內容改為『" GPIO2:Low --> LED熄滅"』外,一樣並把訊息顯示在Arduino IDE的監控式窗之後,再讓接在GPIO2的LED熄滅。


57.       if (line.indexOf("GET /OFF") >= 0) {

58.          echoBack="GPIO2:Low --> LED熄滅";

59.          Serial.println(line);

60.          Serial.println(echoBack);

61.          digitalWrite(indLED, LOW);          // GET /L turns the LED off

62        }


當程式測試接收到代表結束請求傳送的空白行字串時(65~72行),便會把網頁首頁程式MAIN_page[]傳送到tmpString這個字串變數中同時也把回應訊息字串變數「echoBack」帶入到tmpString這個網頁html程式內在送出回應網頁程式至客戶端後以”break”的整令結束while()迴圈。


65.     if (line.length() == 1 && line[0] == '\n')  // 測試HTTP請求是否結束

66.     {

67.        String tmpString = MAIN_page;         // 取出html網頁回應程式

68.        tmpString.replace("%echoBack%", echoBack); // 帶入回應字串變數

69. 至回應網頁html程式中

70.        client.print( tmpString ); // 送出回應網頁程式至客戶端

71.        break;

72.      }


後面剩下的83~110行是「index.h」這個頁面的內容,是一個完整的html網頁程式,在此一樣是使用C++語言中稱為原始字串 (Raw String) 的語法


const  char  MAIN_page[]  PROGMEM = R"=====( ……….. )=====";


這個html網頁程式的主體(即99~107行的<body>…</body>中間)部分如下


99. <body> 

100.   <div id='main'>

101.     <h2><center>[Soft AP模式] <br>

102.         使用Get控制單一輸出實習<br><br>

103.         %echoBack%

104.         </center>

105.     </h2>

106   </div> 

107. </body>


其中的101、102行用來實現【圖四、1-2】畫面上方的『[Soft AP模式] 使用Get控制單一輸出實習』的提示訊息,而103行則會將前面68行所傳來的「echoBack」字串變數帶入程式中,將最後的測試及輸出結果回應給客戶端的使用者。


執行結果:

在程式執行之後開啟手機/平板/筆電的WiFi功能,在看到”ESP32_softAP01”這個AP存取點後點選它,接著啟動瀏覽器,並在網址輸入欄中輸入[ 192.168.4.1 ]這個IP位址並前往。如果連線正常將會看到【圖四、1-2】畫面也就是系統內建伺服器的首頁畫面

假如在網址輸入欄中輸入[ 192.168.4.1/on ] 的內容並前往如果連線正常將會看到【圖四、1-3】的畫面此時ESP32開發板上內建於GPIO2上的LED會點亮。當在瀏覽器輸入[ 192.168.4.1/off ]的內容時出現的是【圖四、1-4】的畫面也就是讓LED熄滅的狀態

如果按照我們前面所訂定的功能與規範使用者在手機瀏覽器網址輸入欄中輸入的是前三者之外的內容例如輸入[ 192.168.4.1/o ]也就是錯誤的RUI請求那麼系統應該會回應【圖四、1-2】畫面;但是如果輸入的是[ 192.168.4.1/onoff ] 或[ 192.168.4.1/offon ]會是什麼結果呢如果讀者有去實作本範例出來將會發現前者會點亮LED而後者則是令LED熄滅也就是說這個範例所能提供的控制動作並不是太精準當然我們可以把程式改良到很精確但是由於使用者操作起來也不是很方便除非只是想設計一個非常簡易的系統否則這種方式不建議採用在此只是想讓讀者能熟悉當ESP32定位在一個網頁伺服器時該如何檢測瀏覽器RUI的請求並給予正確的回應


沒有留言:

張貼留言

三、使用Line Notify傳送照片之安全監控系統之二---低功耗篇

在前一個章節中 , 我們建構了一個標準照片擷取 、 傳送與儲存的按全監控裝置 , 不過假如我們使用的場域中有許多的地方都必須按裝這類的裝置時 , 例如在一個有許多門 、 窗的家庭或辦公室 , 由於我們的系統使用無線WiFi作為信號傳輸之用 , 所以信號的傳輸除非裝置離WiFi分享...