前面的章節在介紹有關網頁設計和建構伺服器的一些基本觀念,主要著重在網頁軟體程式的設計,接下來就讓我們開始練習ESP8266硬體的使用與相關的Arduino程式。為了減少學習者的負擔與困擾,所有實作的程式設計都會以建構在ESP8266內的為主,盡量使用手機或行動通信裝置上的瀏覽器來測試,而不再另外設計測試所需的APP程式。
六、5-1 ESP8266輸出控制練習:單一輸出點控制
六、5-1.1 直接使用GET(URI)的方式控制
在前面的《六、3-1GET請求的解析》一節中曾說明過,在HTTP 的GET請求中最重要的部分是請求行(request Line) ,所謂的請求行主要包括兩個部份,其中一部分是所謂的URI(Uniform Resource Identifier),即請求的內容,也就是跟著網頁位址後面的訊息;例如我們使用瀏覽器連上伺服器網頁首頁時,送出的URI內容便是”/”,而當我們在網址輸入欄鍵入「192.168.0.100/test」這樣的網址資料時,URI則是”/test”。在本單元中我們就以這個特性,示範如何去控制ESP8266模組(ESP-12X)上內建LED的亮滅。
◎ 範例程式功能與動作說明:
1、以ESP8266建立一無線WiFi AP存取點,此AP存取點SSID名稱為 『ESP_softAP01』,而且不使用密碼。
2、此AP存取點內建伺服器的IP位址為:[ 192.168.0.100 ]。
3、當客戶端裝置連線上ESP8266內建伺服器首頁時(也就是只鍵入IP網址[ 192.168.0.100 ]),系統會回應『ESP8266 AP模式-- 單一LED輸出控制』這樣的訊息給客戶端。
4、如果輸入的是: [ 192.168.0.100 /LedOn],則ESP8266模組(ESP-12X)上內建的LED會點亮,而且系統會回應『單一LED輸出控制 -- LED 點亮』的訊息給客戶端。
5、如果輸入的是: [ 192.168.0.100 /LedOff],則ESP8266模組(ESP-12X)上內建的LED會熄滅,而且系統會回應『單一LED輸出控制 -- LED 熄滅』的訊息給客戶端。
6、假如使用者鍵入IP網址內容不在前面幾種的條件裡面,那麼系統會回應『動作錯誤! ==>????』這樣的訊息給客戶端,告訴使用者指令錯誤;其中”????”的部分,就是由客戶端所傳送過來的請求URI內容。
以下是這個範例的完整程式內容:
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
#include <ESP8266WebServer.h> // 新增的ES8266網頁伺服器函式庫
// #include "index.h" // 引入網頁程式碼
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
ESP8266WebServer server(80); // 宣告一伺服器物件並設定通信埠號碼為網頁專用的80
WiFiClient client;
const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
String html_echo;
String html_end="</body></html>"; // html程式的後半段
void setup() {
pinMode(LED,OUTPUT); // 設定ESP8266模組上的內建LED腳為輸出腳
digitalWrite(LED,1); // 先讓ESP8266模組上的內建LED熄滅
Serial.begin(115200);
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
boolean result=WiFi.softAP(softSsid);
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.on("/",handleRoot); // 定義處理客戶首頁連結請求的事件對應函式
server.on("/LedOn",LedOn); // 定義處理客戶LED點亮請求的事件對應函式
server.on("/LedOff",LedOff); // 定義處理客戶LED熄滅請求的事件對應函式
server.onNotFound(handleNotFound); // 定義處理客戶請求錯誤的事件對應函式
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
Serial.println();
}
// 主迴圈程式區:
void loop() {
server.handleClient(); // 呼叫客戶端連線處理函式
}
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
String s=MAIN_page; // 取的html網頁程式的前半段
s+="<h4>ESP8266 AP模式-- 單一LED輸出控制</b></h4>"; // 加上回應訊息文字
s+=html_end; // 補上html程式的後半部分
server.send(200,"text/html",s); // 送出回應的網頁程式
Serial.println("Client is connected!"); // 同時也在Arduino IDE監控視窗顯示提示訊息
Serial.println();
}
// 處理LED點亮請求的事件對應函式:
void LedOn() {
String s=MAIN_page; // 取的html網頁程式的前半段
digitalWrite(LED,0); // 輸出low點亮LED
s+="<h4>單一LED輸出控制 -- LED 點亮</h4>"; // 加上回應LED點亮請求的訊息文字
s+=html_end; // 補上html程式的後半部分
server.send(200,"text/html",s); // 送出回應LED點亮請求的的網頁程式
Serial.println("LED is On!"); // 同時也在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理LED熄滅請求的事件對應函式:
void LedOff() {
String s=MAIN_page;
digitalWrite(LED,1); // 輸出high以熄滅LED
s+="<h4>單一LED輸出控制-- LED 熄滅</h4>"; // 加上回應LED熄滅請求的訊息文字
s+=html_end;
server.send(200,"text/html",s);
Serial.println("LED is Off!"); // 也在Arduino IDE監控視窗顯示LED熄滅的提示訊息
Serial.println();
}
// 處理客戶請求錯誤的事件對應函式:
void handleNotFound(){
String s=MAIN_page;
s+="<h4>動作錯誤! ==> "; // 加上回應請求動作錯誤的訊息文字
s+=server.uri(); // 再加上原來請求的訊息內容
s+="</h4>";
s+=html_end; // 補上html程式的後半部分
server.send(404,"text/html",s); // 回應”404”這個找不到內容的錯誤訊息碼
Serial.println(“URI not found -->”);
Serial.println(server.uri()); // 在Arduino IDE監控視窗顯示錯誤的URI內容
Serial.println();
}
//---------------------------------------------------------------
// 以下為 “index.h”部分的程式內容:
// 將我們的HTML 網頁程式內容直接建構在program memory內:
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background- color:#4caf50; font-size:120%;}
</style>
<title>ESP8266 softAP 的第一個單一LED程式</title>
</head>
<center>
<body>
)=====";
程式名稱:softAP_6_5_1Led1.ino
◎ 程式說明:
本範例可說是【六、4-1以html語法回應客戶主網頁請求】中所介紹範例程式(程式名稱:softAP3_webServer22.ino)的進階版,在此有兩個主要的改良點,一是原來用以回應客戶端請求的html網頁程式從固定內容改成動態回應,二是針對每一種請求給定一個副程式及不同的回應訊息。
前面提到的”index.h”這個html網頁程式是存放在程式記憶體上,而程式記憶體的內容是固定無法改變的!如果我們針對不同的客戶端請求去寫不同的html網頁程式,然後再分別存放在程式記憶體上,等需要時再引入使用雖然是可行的,但是這樣一來程式就會變得冗長和龐大;因此在本範例中,我們就將其中不會變動的部分保留在”index.h”這個html網頁程式分頁夾中,其他的部分就依不同的請求再去完成對應的內容,而這也就是為什麼”index.h”程式的最後部分(117、118行)會是下面的內容:
117 <body>
118 )=====";
在html網頁程式語法中,真正的內容是包在<body> -------- </body>這一組標籤的虛線之中,在程式的第17行我們定義了html程式的後半段;
17 String html_end="</body></html>"; // html程式的後半段
這麼一來我們便可將要回應的主體部分加在這兩者之間就可以了!
由於一般ESP8266的衍生應用模組板(如NodeMcu、ESP-202、WeMos等)大都使用ESP-12X(X=E、F、G)這種系列的郵票模組板,但不管是那一種,在其中都有內建一LED,在燒錄程式時可以看到這顆LED會跟著閃爍,其使用的腳位號碼為2,所以第15行程式就是在定義這根接腳:
15 const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
並在程式第20行將它設定為輸出模式:
20 pinMode(LED,OUTPUT); // 設定LED腳為輸出腳
至於35~38行的程式則在設定對應到客戶端不同URI請求的服務副程式:
35 server.on("/",handleRoot); // 定義處理客戶首頁連結請求的事件對應函式
36 server.on("/LedOn",LedOn); // 定義處理客戶LED點亮請求的事件對應函式
37 server.on("/LedOff",LedOff); // 定義處理客戶LED熄滅請求的事件對應函式
38 server.onNotFound(handleNotFound); // 定義處理客戶請求錯誤的事件對應函式
在完成這些設定之後,不同的URI請求便由各個對應的副程是去負責。
和前面的範例一樣,主迴圈程式只有一行用來攔截與監聽客戶端連線的處理函式:
server.handleClient(); // 呼叫客戶端連線處理函式
後面的52~98行是前述四個副程式所在的位置,以第一個處理首頁’/’請求的自訂函式「void handleRoot()」(52~60行)來說,首先從”index.h”取得html網頁程式的前半段,接著補上回應訊息文字(即"<h4>ESP8266 AP模式-- 單一LED輸出控制</b></h4>”),最後再加上html程式的後半部分,這樣便完成一個完整的網頁程式,接下來只要回傳給客戶端就大功告成!
至於處理點亮LED用的「void LedOn()」 (63~72行)副程式,和上一個大同小異,主要是多了一行點亮LED的程式:
digitalWrite(LED,0); // 輸出low點亮LED
而處理熄滅LED用的「void LedOff() 」(75~84行)副程式,則是多一行熄滅LED的程式:
digitalWrite(LED,1); // 輸出high以熄滅LED
最後一個處理客戶端送來未定義URI請求的副程式「void handleNotFound()」(87~98行),除了會回應["<h4>動作錯誤! ==> "] 外,還會使用下列的程式把原始的URI請求回傳給客戶端以便作為驗證之用:
s+=server.uri(); // 再加上原來請求的訊息內容
◎ 執行結果:
下面的【圖六、17a~d】分別是手機瀏覽器連線首頁、點亮LED、熄滅LED及URI指令錯誤在螢幕上所呈現的結果,當然ESP8266實驗模組板上的接在腳位2的內建LED也會隨之亮滅。
圖六、17a 手機瀏覽器連線後結果
圖六、17b 手機瀏覽器使用URI(/LedOn)點亮LED後結果
圖六、17c 手機瀏覽器使用URI(/LedOff)熄滅LED後結果
圖六、17d 手機瀏覽器使用錯誤URI(/Ledon)之結果
不過如果我們檢視【圖六、17d】的內容應該會發現,ESP8266所接收到的URI指令是:
/Ledon
可是我們的程式會視為錯誤,這是因為所使用的程式碼(server.on())對大小寫是有區別的!這樣的結果雖然很精確,但有時使用起來卻很不方便。
為了去除因為大小寫所造成的困擾,接下來我們提供另外一個範例程式供讀者參考。
◎ 範例程式功能與動作說明:
1、本範例之功能與上一個完全相同
2、所使用之URI指令不用區分大小寫。
同樣的本範例是【六、4-2 以html+CSS語法回應客戶端主網頁請求】小節(程式名稱:softAP3_webServer32.ino)的改良版,和前面幾個範例程式比較少用了一個函式庫(即“ESP8266WebServer.h”),只用最基礎的Arduinou原始函式庫『ESP8266WiF.h』,但同樣的可以達到建立網頁的目的,只是有些部分需要我們自己處理而已,不過這樣程式會更有彈性,接下來就讓我們看一下程式的內容。
以下是這個範例的完整程式內容:
//
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
#include "index.h" // 引入網頁程式碼
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
//String softSsid = "ESP"+String(ESP.getChipId());
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
String html_end="</body></html>"; // html程式的後半段
String Uri;
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
WiFiServer server(80); // 宣告一伺服器物件並設定通信埠號碼為網頁專用的80
WiFiClient client; // 宣告一客戶端物件
void setup() {
pinMode(LED,OUTPUT); // 設定ESP8266模組上的內建LED腳為輸出腳
digitalWrite(LED,1); // 先讓ESP8266模組上的內建LED熄滅
Serial.begin(115200); // 初始化串列通訊埠
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
}
// 主回圈程式區:
void loop() {
client=server.available(); // 測試是否有客戶端裝置連線
if(!client) //
return; // 若無則結束迴圈
String request="",requests=""; // 設定讀取客戶端資訊的暫存字串變數
while(client.connected()) // 測試客戶端裝置是否還在連線
{
request=client.readStringUntil('\r'); // 讀取客戶端裝置傳來的一整行訊息資料
requests+=request; // 將讀取資料合併成更大的字串
if(request=="\n") // 測試是否已到傳送資料的最後一行
break; // 中斷while迴圈
}
Serial.println("Request end!");
client.flush(); // 清除客戶端傳送過來的所有資料
Uri=requests.substring(requests.indexOf("/"),requests.indexOf("HTTP")); // 取得URI的內容
Uri.trim(); // 將萃取出的URI前後的空白部分去除
Serial.print("Uri = '"); // 將結果顯示在在Arduino IDE串列監控視窗中
Serial.print(Uri);
Serial.println("'");
String URI=Uri;
URI.toUpperCase(); // 將URI所有的字元都轉換成大寫
if(URI=="/") // 測試URI請求是否為網頁首頁
handleRoot(); //
else if (URI=="/LEDON") // 測試URI請求是否為點亮LED
LedOn(); // 執行點亮LED副程式
else if (URI=="/LEDOFF") // 測試URI請求是否為熄滅LED
LedOff(); // 執行熄滅LED副程式
else
handleNotFound(); // 如果都不是則執行這個副程式
delay(5);
}
//=====================================
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
String s=MAIN_page; // 取得html網頁程式的前半段
s+="<h4>ESP8266 AP模式-- 單一LED輸出控制</b></h4>"; // 加上回應訊息文字
s+=html_end; // 補上html程式的後半部分
client.print(s); // 送出回應的網頁程式
Serial.println("Client is connected!"); // 同時也在Arduino IDE監控視窗顯示提示訊息
Serial.println();
}
// 處理點亮LED請求的事件對應函式:
void LedOn() {
String s=MAIN_page;
digitalWrite(LED,0); // 輸出low以點亮LED
s+="<h4>單一LED輸出控制-- LED點亮</h4>"; // 加上回應LED點亮請求的訊息文字
s+=html_end; // 補上html程式的後半部分
client.print(s); // 送出點亮LED的訊息
Serial.println("LED is On!"); // 也在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理LED熄滅請求的事件對應函式:
void LedOff() {
String s=MAIN_page;
digitalWrite(LED,1); // 輸出high以熄滅LED
s+="<h4>單一LED輸出控制-- LED 熄滅</h4>"; // 加上回應LED熄滅請求的訊息文字
s+=html_end; // 補上html程式的後半部分
client.print(s); // 送出熄滅LED的訊息碼
Serial.println("LED is Off!"); // 也在Arduino IDE監控視窗顯示LED熄滅的提示訊息
Serial.println();
}
// 處理客戶請求錯誤的事件對應函式:
void handleNotFound(){
String s=MAIN_page;
s+="<h4>動作錯誤! ==> "; // 加上回應請求動作錯誤的訊息文字
s+=Uri; // 再加上原來請求的訊息內容
s+="</h4>";
s+=html_end; // 補上html程式的後半部分
client.print(s); // 送出找不到內容的錯誤訊息碼
Serial.println(“URI not found -->”);
Serial.println(Uri); // 在Arduino IDE監控視窗顯示錯誤的URI內容
Serial.println();
}
/---------------------------------------------------------------------------
// 以下為 “index.h”部分的程式內容:
// 將我們的HTML 網頁程式內容直接建構在program memory內:
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<link rel='icon' href='data:,\'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background- color:#4caf50; font-size:120%;}
</style>
<title>ESP8266 softAP 的第二個單一LED程式</title>
</head>
<center>
<body>
)=====";
程式名稱:softAP_6_5_1Led2.ino
◎ 程式說明:
本範例程式跟之前這個《softAP3_webServer32.ino》程式主要的不同點是從的55行開始,當客戶端的瀏覽器網址欄輸入[192.168.0.100/LedOn]這樣的URI時,在伺服器端也就是ESP8266會收到下面這樣的GET請求訊息:
GET /LedOn HTTP/1.1
其中的「/LedOn」便是真正的請求部分,使用下面的程式便可其中的URI萃取出來,並存放在”Uri”這個字串變數上。
Uri=requests.substring(requests.indexOf("/"),requests.indexOf("HTTP")); // 取得URI的內容
有時這個”Uri”字串變數的前後可能會有多出的看不見的空白字元存在,而這些空白字元是會影響後面的測試判斷結果,為了避免這個問題的發生,我們再用下列的程式把這個”Uri”字串變數前後的空白部份去掉。
Uri.trim(); // 將萃取出的URI前後的空白部分去除
最後再把得到的結果字串內容都轉換成大寫,這樣就可以避掉字元大小寫的問題,開始測試所得到的URI內容了!
URI.toUpperCase(); // 將URI所有的字元都轉換成大寫
接著的62~69行程式是一連串的”if”測試過程,程式是會依不同URI請求判斷結果去呼叫對應的副程式。
後面73~120行是預設四種URI請求所對應的副程式,其內容與架構和上一個幾乎一模一樣,只是所使用的指令由:
server.send(200,"text/html",s) 🡪 client.print(s)
其中的字串“s”的內容便是一個完整的html網頁程式。
至於剩下的部分(125~141行)都是”index.h”這個html語法的程式碼,和上一個範例所使用的完全一樣。
◎ 執行結果:
【圖六、18】是模仿圖【六、17d】但使用"/Ledon"(如紅線框所示)這個URI的結果畫面,可看出即使使用小寫也可以動作,也就是說ESP8266已經不會再去區分指令中英文字元的大小寫了!
圖六、18 手機瀏覽器使用URI(/Ledon)點亮LED後結果
六、5-1.2 使用超連結(href)的方式控制
所謂的超連結(href)就是網頁程式設計html語法中的<a>標籤,以下面這個html程式(“softAP_6_5_1Led3_href.html”)為例,當我們用電腦的瀏覽器開啟它時,可看到【圖六、19】的畫面,其中用紅色線框起來的部分(即”點亮”與”熄滅”這兩段文字),就是超聯結的選取點,它是由程式中的6、7兩行所構成。以第6行來說:
按此<a href="LedOn" target="myIframe">點亮</a><br>
<a>標籤的內容擴充為 『< a href=”LedOn” target=”myIframe”>』,也就是說當我們點選”點亮”這個超連結點時,瀏覽器會向連接的伺服器送出"LedOn"這個URI,如果把這個功能移植到ESP8266上,那麼當手機連接上ESP8266所構成的伺服器時,我們便可由瀏覽器所發送回的URI內容來決定動作的方式。
至於後面的「target=”myIframe”」代表在送出超連結之後,伺服器回應訊息的存放點,而這個點就是程式第8行的[LED狀態:]這段提示文字右邊:
8 LED 狀態:<iframe name="myIframe" width="150" height="25" frameBorder="0"><br>
如果程式中沒有加上這一行,那麼每次點選超連結之後,瀏覽器在接收到伺服器回傳的訊息時,會重新開啟一個頁面來顯示結果;如此一來要再次操作亮滅LED的動作,就必須先按瀏覽器上的「🡨」返回鍵回到之前的主頁面才行,這樣感覺就不很方便!讀者可自行刪減這行程式試試看效果如何。
1 <!doctype html>
2 <html>
3 <body>
4 <center>
5 <h1>ESP8266 softAP 程式 : 單一LED亮滅使用href<br>
6 按此<a href="LedOn" target="myIframe">點亮</a><br>
7 按此<a href="LedOff" target="myIframe">熄滅</a><br>
8 LED 狀態:<iframe name="myIframe" width="150" height="25" frameBorder="0"><br>
9 </h1>
10 </center>
11 </body>
12 </html>
softAP_6_5_1Led3_href.html
圖六、19 《softAP_6_5_1Led3_href.html》於電腦瀏覽器執行結果
◎ 範例程式功能與動作說明:
1、本範例在ESP8266上建構一網頁伺服器,及客戶端連線後的首頁,當使用者連線上時會以超連結的方式供使用者控制ESP8266上LED的亮滅。
2、當點選「點亮」這個鏈結時LED會點亮,並在[LED狀態:]這段提示文字右邊回應「LED點亮!」的訊息。
3、當點選「熄滅」這個鏈結時LED會熄滅,並在[LED狀態:]這段提示文字右邊回應「LED熄滅!」的訊息。
以下是此範例的完整程式列表:
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
#include <ESP8266WebServer.h> // 新增的ES8266網頁伺服器函式庫
//----------------------------------------------
// 在程式記憶體中創建一html網頁內容:
const char MAIN_page[] PROGMEM = R"=====(
<!doctype html>
<html>
<link rel='icon' href='data:,\'>
<body>
<center>
<h1>ESP8266 softAP : 單一LED亮滅使用href示範<br>
按此<a href="LedOn" target="myIframe">點亮</a><br>
按此<a href="LedOff" target="myIframe">熄滅</a><br>
LED 狀態:<iframe name="myIframe" width="150" height="25" frameBorder="0"><br>
</h1>
</center>
</body>
</html>
)=====";
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
ESP8266WebServer server(80); // 宣告一伺服器物件並設定通信埠號碼為網頁專用的80
WiFiClient client;
void setup() {
//
pinMode(LED,OUTPUT); // 設定ESP8266模組上的內建LED腳為輸出腳
digitalWrite(LED,1); // 先讓ESP8266模組上的內建LED熄滅
Serial.begin(115200);
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
boolean result=WiFi.softAP(softSsid);
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.on("/",handleRoot); // 定義處理客戶首頁連結請求的事件對應函式
server.on("/LedOn",LedOn); // 定義處理客戶LED點亮請求的事件對應函式
server.on("/LedOff",LedOff); // 定義處理客戶LED熄滅請求的事件對應函式
server.onNotFound(handleNotFound); // 定義處理客戶請求錯誤的事件對應函式
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
Serial.println();
}
// 主迴圈程式區:
void loop() {
server.handleClient(); // 呼叫客戶端連線處理函式
}
//===================================================
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
String s=MAIN_page; // 取得html網頁程式
server.send(200,"text/html",s); // 送出回應的網頁程式
Serial.print("URI is --> ");
Serial.println(server.uri());
Serial.println("Client is connected!"); // 同時也在Arduino IDE監控視窗顯示提示訊息
Serial.println();
}
// 處理LED點亮請求的事件對應函式:
void LedOn() {
digitalWrite(LED,0); // 輸出low點亮LED
server.send(200,"text/html","LED點亮"); // 送出回應LED點亮請求的網頁程式
Serial.print("URI is --> ");
Serial.println(server.uri());
Serial.println("LED is On!"); // 在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理LED熄滅請求的事件對應函式:
void LedOff() {
digitalWrite(LED,1); // 輸出high以熄滅LED
server.send(200,"text/html","LED熄滅!"); // 回應LED熄滅的訊息
Serial.print("URI is --> ");
Serial.println(server.uri());
Serial.println("LED is Off!"); // 在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理客戶請求錯誤的事件對應函式:
void handleNotFound(){
String s=MAIN_page;
s="動作錯誤! ==> "; // 加上回應請求動作錯誤的訊息文字
s+=server.uri(); // 再加上原來請求的訊息內容
s+=html_end; // 補上html程式的後半部分
server.send(404,"text/html",s); // 回應”404”這個找不到內容的錯誤訊息碼
Serial.println(“URI not found -->”);
Serial.println(server.uri()); // 在Arduino IDE監控視窗顯示錯誤的URI內容
Serial.println();
}
程式名稱:softAP_6_5_1Led3_href.ino
◎ 程式說明:
在程式的開始(1、2行)一樣引入了<ESP8266WiFi.h>這個ESP8266專用的WiFi函式庫,及ES8266網頁伺服器函式庫<ESP8266WebServer.h>。由於我們所使用的html網頁程式不大,為了方便測試與說明,所以不再採用分頁標籤撰寫成<index.h>再引入的方式,而是直接建構在主頁的程式碼中,程式6~20行便是前面《softAP_6_5_1Led3_href.html》這個網頁程式的Arduno版。
接著的33~64行分別是初始化(setup())及主迴圈(loop())程式的部分,其內容和前面的《softAP_6_5_1Led1.ino》範例是一模一樣,在此就不多做贅述。兩者主要的差別是在使用者是以點選網頁主頁中的超連結來傳送URI,而不需要使用者在URL網址欄位中去輸入,這樣比較符合一般人使用的習慣。
至於對應到不同URI的幾個副程式差異也不大,其中對應到網頁首頁的《void handleRoot()》副程式會把整個網頁首頁程式傳送給連線的客戶端,所以在客戶端的行動通信裝置平台的瀏覽器上便會出現類似【圖六、19】的畫面。由於我們在網頁程式中(第15行)加入了下面的指令,所以整個網頁畫面基本上是不會變動,只會在「LED 狀態:」這段文字的右邊顯示ESP8266回應的訊息。
15 LED 狀態:<iframe name="myIframe" width="150" height="25" frameBorder="0"><br>
以處理點亮LED用的『void LedOn()』 (79~86行)副程式來說,和之前的差異,主要是回傳的信息只有”LED點亮”這一段簡短的文字(81行),用來告知客戶端LED已經被點亮了,而不是完整的網頁程式,這樣可以減少一些網路的傳輸流量。
server.send(200,"text/html","LED點亮"); // 送出回應LED點亮請求的網頁訊息
◎ 執行結果:
【圖六、20】是程式啟動之後在Arduino IDE串列監控視窗所看到的一些操作過程的內容,其中標記1是手機客戶端的瀏覽器連線上ESP8266之後,所傳來代表首頁的URI(”/”);而標記2是使用者點選「點亮」這個鏈結時,所傳來用以點亮LED會點亮的URI(”LedOn”);至於標記3則是點選「熄滅」這個鏈結後所得到熄滅LED用的URI(”LedOff”)。
圖六、20 href程式啟動後Arduino IDE串列監控視窗之內容
圖六、21a 手機瀏覽器連線後畫面
圖六、21b 點選「點亮」超連結後手機瀏覽器畫面
圖六、21c點選「熄滅」超連結後手機瀏覽器畫面
接著的【圖六、21a】是手機瀏覽器連線後會看到的畫面,由於這時只是剛連上網頁的首頁,所以只會看到標記1的兩個超連結選項,而標記2的「LED 狀態:」這段文字的右邊還是空白的。當使用者點選「點亮」這個超連結後,手機瀏覽器會看到【圖六、21b】的畫面,此時「LED 狀態:」文字的右邊會出現[LED點亮!]這樣的訊息(標記2);而【圖六、21c】則是點選超連結「熄滅」後手機瀏覽器的畫面,這時「LED 狀態:」文字的右邊則是出現[LED熄滅!]的訊息(標記2)。
以上便是本範例程式執行後,以行動通訊裝置的瀏覽器連線登入後的結果,由於我們在ESP8266上建構了一個伺服器的網頁超連結首頁,所以使用者只要像一般上網一樣的操作就可以,不必特別去記憶和輸入控制用的URI指令碼,因此使用上就方便多了!
接下來比照前一小節的慣例,我們改用另一種方式來設計可執行及實現同樣功能的程式。
◎ 範例程式功能與動作說明:
1、本範例之功能與上一個完全相同。
2、只使用單一的<ESP8266WiFi.h>ESP8266專用WiFi函式庫。
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
//----------------------------------------------
// 在程式記憶體中創建一html網頁內容:
const char MAIN_page[] PROGMEM = R"=====(
<!doctype html>
<html>
<link rel='icon' href='data:,\'>
<body>
<center>
<h1>ESP8266 softAP : 單一LED亮滅使用href示範2<br>
按此<a href="LedOn" target="myIframe">點亮</a><br>
按此<a href="LedOff" target="myIframe">熄滅</a><br>
LED 狀態:<iframe name="myIframe" width="150" height="25" frameBorder="0"><br>
</h1>
</center>
</body>
</html>
)=====";
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
//String softSsid = "ESP"+String(ESP.getChipId());
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
String URI;
IPAddress local_IP(192,168,0,100);
IPAddress gateway(192,168,0,1);
IPAddress subnet(255,255,255,0);
WiFiServer server(80);
WiFiClient client;
void setup() {
pinMode(LED,OUTPUT); // 設定ESP8266模組上的內建LED腳為輸出腳
digitalWrite(LED,1); // 先讓ESP8266模組上的內建LED熄滅
Serial.begin(115200); // 初始化串列通訊埠
digitalWrite(LED,1); // 先讓LED熄滅
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
Serial.println();
}
// 主回圈程式區:
void loop() {
client=server.available(); // 測試是否有客戶端裝置連線
if(!client) //
return; // 若無則結束迴圈
URI=client.readStringUntil('\r'); // 只讀取GET請求的第一行,也就是URI
client.flush(); // 清除接收客戶端緩衝器
Serial.println("Request end!");
Serial.print("Uri = ");
Serial.println(URI); // 在Arduino IDE串列監控視窗中顯示URI的內容
if(URI.indexOf("/LedOn")>0) // 測試URI的內否為點亮LED指令”LedOn”
LedOn(); // 呼叫指令點亮LED處理副程式
else if (URI.indexOf("/LedOff")>0) //測試URI的內否為熄滅LED指令”LedOff”
LedOff(); // 呼叫指令熄滅LED處理副程式
else if (URI.indexOf("/")>0) //測試URI的內否為首頁指令”/”
handleRoot(); // 呼叫網頁首頁處理副程式
else
handleNotFound(); // 呼叫指令錯誤處理副程式
delay(5);
}
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
String s=MAIN_page; // 取得html網頁程式
client.print(s); // 送出回應的網頁程式
Serial.println("Client is connected!"); // 同時也在Arduino IDE監控視窗顯示提示訊息
Serial.println();
}
// 處理點亮LED請求的事件對應函式:
void LedOn() {
digitalWrite(LED,0); // 輸出low以點亮LED
client.print("LED 點亮"); // 送出點亮LED的訊息
Serial.println("LED is On!"); // 也在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理LED熄滅請求的事件對應函式:
void LedOff() {
digitalWrite(LED,1); // 輸出high以熄滅LED
client.print("LED 熄滅"); // 送出熄滅LED的訊息碼
Serial.println("LED is Off!"); // 也在Arduino IDE監控視窗顯示LED熄滅的提示訊息
Serial.println();
}
// 處理客戶請求錯誤的事件對應函式:
void handleNotFound(){
client.print("動作錯誤!");
Serial.print("URI not found -->");
Serial.println(URI);
Serial.println();
}
程式名稱:softAP_6_5_1Led4_href.ino
◎ 程式說明:
本範例程式和前一個《softAP_6_5_1Led3.ino》的差別,在於程式初始化(setup())的部分少了幾行用以設定對應到不同URI請求的程式(即”server.on()”),取而代之的是把判斷URI請求的部分放在主迴圈(loop())內實作出來。之前主迴圈的內容很簡單,我們只要呼叫『server.handleClient()』這個客戶端連線處理函式就好了;在此我們必須先取得客戶端的請求內容(即GET請求),在前面【六、3-1 GET請求的解析】一小節中我們已經分析過,當客戶端瀏覽器連上伺服器時所送出的內容,其中第一行訊息就是GET的請求內容,所以本範例只用第64行程式去取得客戶端傳來的第一行訊息資料:
URI=client.readStringUntil('\r'); // 只讀取GET請求的第一行,也就是URI
接著用Arduino內建的字串處理函式「.indexOf(“???”)」去尋找要比對測試的標的URI,然後再依測試結果,分別呼叫對應的服務副程式(程式70~77行)。不過在用”if……else”測試URI時要注意一下測試標的之順序,其中代表首頁的根符號(“/”)一定要放在最面測,因為不管點亮或熄滅LED的URI,前面都有這個字元,如果先測試根符號(“/”),因為一開始就成立了,那麼永遠會只能執行首頁的動作。
在剩下的82~114行的自建客戶請求處理副程式區中,每一個副程式和上一個的內容都差不多,只是將回應客戶端的動作函式由:
server.send() 🡪 client.print()
請讀者們自行參閱。
◎ 執行結果:
【圖六、22a】是手機瀏覽器連線後螢幕的畫面,和上一個範例的差別是最上面一行的提示訊息為『單一LED亮滅使用href示範2』;因為此時只是剛連上網頁的首頁,所以只會看到標記1的兩個超連結選項,而標記2的「LED 狀態:」這段文字的右邊還是空白的。當使用者點選超連結「點亮」後,手機瀏覽器會看到【圖六、22b】的畫面,此時「LED 狀態:」文字的右邊會出現[LED點亮!]這樣的訊息(標記2);而【圖六、22c】則是點選超連結「熄滅」後手機螢幕的畫面,這時「LED 狀態:」文字的右邊則是出現[LED熄滅!]的訊息(標記2)。
圖六、22a 手機瀏覽器連線後畫面
圖六、22b 點選「點亮」超連結後手機瀏覽器畫面
圖六、22c點選「熄滅」超連結後手機瀏覽器畫面
六、5-1.3 使用表單(Form)的方式控制
上一個範例使用所謂的超連結(href)html語法去控制單一LED的亮滅,讓使用者操作起來比較方便,可是要用兩組超連結文字去實現,感覺起來不夠精簡;接下來我們改用html語法中的表單(form)標籤架構,來達到更精簡的的控制方式與介面。
所謂表單(form)是html語法中一種可以提供輸入的介面,可讓使用者輸入資料,然後將資料回傳給網路伺服器的一種元素元件;表單的建立包含兩個部份:
先使用<form>……</form>和<input>這兩個標籤元素建立我們所要的操作表單介面。
設計表單傳回資料的後端處理程式。
後面的html程式(“softAP_6_5_1Led4_href.html”)便是用來實現表單的第一個部份,當我們用電腦的瀏覽器開啟它時,可看到【圖六、23a】的畫面;其中標記1用紅色線框起來的部分是一個屬性為按鈕(button)的輸入(input)元素,此按鈕中的文字為「點亮LED」一看就可知道是控制點亮LED之用,而標記2的「LED 目前狀態:熄滅」這段文字則是顯示目前ESP8266上LED燈的狀態。
要實現這樣一個網頁畫面,首先我們在程式的6~12行撰寫了一段CSS語法,用來定義兩種不同內容的按鈕(button)外觀(8~12行);它們的差別只在背景的顏色而已,其中的”button”是粉紅色(pink),而”button2”則是草綠色(yellowgreen)。
.button {padding:10px 10px 10px 10px; width:100%; background-color: pink; font-size:120%;}
.button2 {padding:10px 10px 10px 10px; width:100%; background-color: yellowgreen; font-size:120%;}
【圖六、23a】所呈現的內容共有三個部分,是由程式16~19行所構成;最上面的一行是不會變動的提示文字「單一LED亮滅使用Form示範 1」(第16行),第二行是標記2的「LED 目前狀態:熄滅」文字(第17行),這部分的內容會隨著LED的亮滅而改變;第三行則是標記1的按鈕(button),在此是用來控制點亮LED。後面是<form>這個標籤的內容,必須以</form>結束,夾在中間的是<input>這個元素,<input>的種類有很多,例如”text”、”password”、”radio”、”submit”…..等等,在此使用的是”submit”,也就是所謂的提交按鈕。
16 <h4>單一LED亮滅使用Form示範 1</h4>
17 <h3>LED目前狀態 : 熄滅</h3><br>
18 <form action='LedOn'> <input class='button' type='submit' value='點亮LED'>
19 </form><br>
下面這段html語法程式的意思是使用提交按鈕作為輸入(type=’submit’),這個按鈕上的提示文字(value)為’點亮LED’,而按鈕的外觀長相(class)就是前面提到的CSS所定義底色是粉紅的’button’。
<input class='button' type='submit' value='點亮LED'>
至於這個按鈕被按下時會提交回傳給網頁伺服器的內容,是由下面這句html語法來決定,也就是’LedOn’這段文字:
<form action='LedOn'>
因此當手機連接上ESP8266所構成的伺服器時,我們便可由瀏覽器所發送回的URI內容來決定動作的方式,也就是點亮LED。不過由於我們的電腦並未真的連上由ESP8266所構成的AP存取點,所以在電腦的瀏覽器上點選控制按鈕是不能控制ESP8266上的LED亮滅的;但如果使用筆記型電腦的話,由於它具有WiFi無線傳輸介面,是可以實現上述控制LED亮滅功能的!
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background-color: pink; font-size:120%;}
.button2 {padding:10px 10px 10px 10px; width:100%; background-color: yellowgreen; font-size:120%;}
</style>
</head>
<body>
<div id='main'>
<h4>單一LED亮滅使用Form示範 1</h4>
<h3>LED目前狀態 : 熄滅</h3><br>
<form action='LedOn'> <input class='button' type='submit' value='點亮LED'>
</form><br>
</div>
</body>
</html>
程式名稱:softAP_6_5_1Led4_form.html
圖六、23a 《softAP_6_5_1Led4_form.html》於電腦瀏覽器執行結果
如果我們將《softAP_6_5_1Led4_form.html》這個程式的16~19行改寫成下面的內容:
16 <h4>單一LED亮滅使用Form示範 1</h4>
17 <h3>LED目前狀態 : 點亮</h3><br>
18 <form action='LedOff'> <input class='button2' type='submit' value='熄滅LED'>
19 </form><br>
當重新在電腦的瀏覽器上執行時,螢幕上出現的會是【圖六、23b】的畫面,此時標記1的按鈕背景顏色(草綠色)跟提示文字(熄滅LED)都改變了,而標記2的文字也換成「LED 目前狀態:點亮」這樣的內容,這時如果我們按下這個提交按鈕,就會向網頁伺服器送出’LedOff”這樣的URI請求,因此如果結合這兩個動作,我們便可以用同一個按鈕去控制LED的亮滅,並收到操作結果的回應訊息。
圖六、23b 《softAP_6_5_1Led4b_form.html》於電腦瀏覽器執行結果
◎ 範例程式功能與動作說明:
1、使用單一個表單(form)的提交按鈕控制ESP8266上LED的亮滅。
2、此按鈕按一次會LED點亮,再按一次則會讓LED熄滅,而LED亮滅的結果會回傳到連線裝置的瀏覽器螢幕上讓使用者知道。
以下便是此範例程式的完整列表:
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
#include <ESP8266WebServer.h> // 新增的ES8266網頁伺服器函式庫
//----------------------------------------------
// 在程式記憶體中創建一html網頁內容:
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background-color: pink; font-size:120%;}
.button2 {padding:10px 10px 10px 10px; width:100%; background-color: yellowgreen; font-size:120%;}
</style>
</head>
<body>
<div id='main'>
<h4>單一LED亮滅使用Form示範 1</h4>
)=====";
//---------------------------------------------------
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
ESP8266WebServer server(80); // 宣告一伺服器物件並設定通信埠號碼為網頁專用的80
WiFiClient client;
String html_LedOn="<form action='LedOn'><input class='button' type='submit' value='點亮LED'></form><br>";
String html_LedOff="<form action='LedOff'><input class='button2' type='submit' value='熄滅LED'></form><br>";
String html_end="</div></body></html>";
String html_Echo="";
void setup() {
pinMode(LED,OUTPUT); // 設定ESP8266模組上的內建LED腳為輸出腳
digitalWrite(LED,1); // 先讓ESP8266模組上的內建LED熄滅
Serial.begin(115200);
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
boolean result=WiFi.softAP(softSsid);
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.on("/",handleRoot); // 定義處理客戶首頁連結請求的事件對應函式
server.on("/LedOn",LedOn); // 定義處理客戶LED點亮請求的事件對應函式
server.on("/LedOff",LedOff); // 定義處理客戶LED熄滅請求的事件對應函式
server.onNotFound(handleNotFound); // 定義處理客戶請求錯誤的事件對應函式
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
Serial.println();
}
// 主迴圈程式區:
void loop() {
server.handleClient(); // 呼叫客戶端連線處理函式
}
//===================================================
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
html_Echo="<h3>LED目前狀態 : 熄滅</h3><br>";
String s=MAIN_page; // 取得html網頁程式
s+=html_Echo; // 加上回應的訊息
s+=html_LedOn; // 再加上點亮LED的按鈕表單程式
s+=html_end; // 最後補上網頁html程式的結尾標籤
server.send(200,"text/html",s); // 送出回應的網頁程式
Serial.print("URI is --> ");
Serial.println(server.uri());
Serial.println("Client is connected!"); // 同時也在Arduino IDE監控視窗顯示提示訊息
Serial.println();
}
// 處理LED點亮請求的事件對應函式:
void LedOn() {
digitalWrite(LED,0); // 輸出low點亮LED
html_Echo="<h3>LED目前狀態 : 點亮</h3><br>";
String s=MAIN_page; // 取得html網頁程式
s+=html_Echo; // 加上回應的訊息
s+=html_LedOff; // 再加上熄滅LED的按鈕表單程式
s+=html_end; // 最後補上網頁html程式的結尾標籤
server.send(200,"text/html",s); // 送出回應LED點亮請求的網頁程式
Serial.print("URI is --> ");
Serial.println(server.uri());
Serial.println("LED is On!"); // 在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理LED熄滅請求的事件對應函式:
void LedOff() {
digitalWrite(LED,1); // 輸出high以熄滅LED
html_Echo="<h3>LED目前狀態 : 熄滅</h3><br>";
String s=MAIN_page; // 取得html網頁程式
s+=html_Echo; // 加上回應的訊息
s+=html_LedOn; // 再加上點亮LED的按鈕表單程式
s+=html_end; // 最後補上網頁html程式的結尾標籤
server.send(200,"text/html",s); // 送出回應LED點亮請求的網頁程式
Serial.print("URI is --> ");
Serial.println(server.uri());
Serial.println("LED is Off!"); // 在Arduino IDE監控視窗顯示LED點亮的提示訊息
Serial.println();
}
// 處理客戶請求錯誤的事件對應函式:
void handleNotFound(){
String s=MAIN_page; // 取得html網頁程式
s="動作錯誤! ==> "; // 加上回應請求動作錯誤的訊息文字
s+=server.uri(); // 再加上原來請求的訊息內容
s+"</h3><br>";
s+=html_end; // 補上html程式的後半部分
server.send(404,"text/html",s); // 回應”404”這個找不到內容的錯誤訊息碼
Serial.println(“URI not found -->”);
Serial.println(server.uri()); // 在Arduino IDE監控視窗顯示錯誤的URI內容
Serial.println();
}
程式名稱:softAP_6_5_1Led5_but.ino
◎ 程式說明:
程式的6~23行是在實作《softAP_6_5_1Led4b_form.html》這個html網頁程式,不過由於這種將程式放在程式記憶體(ROM)的方式,其內容是不能改變的,而我們的網頁程式是會依控制及操作結果變動,為了具有較大的彈性,所以在此只實作了部分的功能,也就是說只寫到《softAP_6_5_1Led4b_form.html》這個程式的第16行而已。然後在37~41行定義兩個不同外觀與功能的html語法表單按鈕(即“html_LedOn”和”html_LedOff”這兩個字串變數),最後再加上一段html網頁語法的結尾字串(“html_end”)。
String html_LedOn="<form action='LedOn'><input class='button' type='submit' value='點亮LED'></form><br>";
String html_LedOff="<form action='LedOff'><input class='button2' type='submit' value='熄滅LED'></form><br>";
String html_end="</div></body></html>";
接著44~74行的初始化程式區(setup())及主迴圈程式區(loop()),和前面的《softAP_6_5_1Led3_href.ino》範例是一模一樣,在此就不再贅述。如果我們比較一下兩個程式的主要不同之處,主要在於對應到每個不同URI的副程式,接下來就讓我們看一下這些副程式的內容為何。
如果我們檢視一下【圖六、23a】與【圖六、23b】兩個執行結果畫面,可看出其間的差異就在於標記1與標記2這兩個部分,當手機連線上ESP8266時,我們看到的網頁首頁(【圖六、23a】)這兩個部分是由下面這段html程式所構成:
<h3>LED目前狀態 : 熄滅</h3><br>
<form action='LedOn'> <input class='button' type='submit' value='點亮LED'>
因此我們在首頁處理副程式《void handleRoot()》(78~90行)中,把這兩段html程式字串(字串變數”html_Echo”和”html_LedOn”)和主程式(字串“MAIN_page”)結合在一起,然後加上html結尾部分(即字串變數“html_end”)合成字串變數”s”(79~83行),最後以下列指令送回給客戶端的瀏覽器。
85 server.send(200,"text/html",s); // 送出回應的網頁程式
當我們按下【圖六、23a】中標記1的『點亮LED』按鈕時,手機的瀏覽器畫面會切換到【圖六、23b】,代表LED已經點點亮了,這時看到的網頁內容則是由下面這段html程式所構成:
<h3>LED目前狀態 : 點亮</h3><br>
<form action='LedOff'> <input class='button2' type='submit' value='熄滅LED'>
因此負責處理點亮LED請求的副程式《void LedOn()》,除了會令ESP8266上的LED點亮(94行的”digitalWrite(LED,0)”程式)之外,本上和前面首頁處理副程式《void handleRoot()》差不多,只是將表單按鈕改成熄滅LED用的字串變數”html_LedOff”而已。
至於處理LED熄滅請求的事件的對應函式《void LedOn()》,和前面首頁處理副程式《void handleRoot()》及本上是一樣,只是多了一行令ESP8266上的LED熄滅(110行的”digitalWrite(LED,1)”)的程式而已。
◎ 執行結果:
【圖六、24a】是手機瀏覽器連線後螢幕的畫面,就和前面的【圖六、23a】一樣,從最上面的標記1網址輸入欄位列的內容是[ 192.168.0.100 ]可看出,這是瀏覽器剛連線上本伺服器首頁的狀態。在畫面中的最上面一行是『單一LED亮滅使用Form示範1』的提示訊息;因為此時只是剛連上網頁的首頁,所以標記2的「LED 目前狀態:」這段文字的右邊是顯示「熄滅」,而控制用的按鈕(標記3)上的提示文字則是[點亮LED]。
圖六、24a 使用手機瀏覽器連線後畫面
當使用者點選【圖六、24a】中的 [點亮LED] 按鈕後,手機瀏覽器會看到【圖六、24b】的畫面,其中標記1網址輸入欄位列的內容變成[ 192.168.0.100 /LedOn?],表示手機瀏覽器送出了「/LedOn?」這種URI請求,這時「LED 目前狀態:」文字的右邊會出現[點亮]的訊息(標記2),而且控制用的按鈕上的提示文字已經換成[熄滅LED] (標記3)。
圖六、24b 點選「點亮LED」按鈕後手機瀏覽器畫面
當使用者再次按下[LED熄滅!]按鈕時,瀏覽器的畫面會換到【圖六、24c】,如果和【圖六、24a】比較,唯一的差別是最上面的標記1網址輸入欄位列的內容是[ 192.168.0.100/LedOff? ],也就是說此時連覽器送來了「/LedOff?」這種URI請求。在此之後瀏覽器畫面就只會在【圖六、24b】與【圖六、24c】這兩者之間切換,而標記2的訊息則反應著ESP8266上LED的亮滅狀態。
圖六、24c點選「熄滅LED」按鈕後手機瀏覽器畫面
同樣的依之前的慣例,我們改用另一種方式來設計可執行及實現同樣功能的程式。
◎ 範例程式功能與動作說明:
1、本範例之功能與上一個完全相同。
2、只使用單一的<ESP8266WiFi.h>ESP8266專用WiFi函式庫。
以下是此範例程式的完整列表:
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
//----------------------------------------------
// 將HTML 網頁程式內容直接建構在program memory內:
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background-color: pink; font-size:120%;}
.button2 {padding:10px 10px 10px 10px; width:100%; background-color: yellowgreen; font-size:120%;}
</style> </style>
</head>
<body>
<div id='main'>
<h4>單一LED亮滅使用Form示範2</h4>
)=====";
//---------------------------------------------------
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
//String softSsid = "ESP"+String(ESP.getChipId()); // 以ESP8266晶片序號作為AP的SSID名稱
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
const byte LED=2; // ESP-12X郵票模組上內建LED的腳位號碼
String URI;
String html_LedOn="<form action='LedOn'><input class='button' type='submit' value='點亮LED'></form><br>"; // 點亮LED的html表單程式
String html_LedOff="<form action='LedOff'><input class='button2' type='submit' value='熄滅LED'></form><br>"; // 熄滅LED的html表單程式
String html_end="</div></body></html>";
String html_Echo="";
IPAddress local_IP(192,168,0,100); // 設定新的伺服器IP位址
IPAddress gateway(192,168,0,1); // 設定新的伺服器閘道位址
IPAddress subnet(255,255,255,0); // 設定新的伺服器網路遮罩位址
WiFiServer server(80); // 宣告一伺服器物件並設定通信埠號碼為網頁專用的80
WiFiClient client; // 宣告一客戶端物件
void setup() {
pinMode(LED,OUTPUT); // 設定ESP8266模組上的內建LED腳為輸出腳
digitalWrite(LED,1); // 先讓ESP8266模組上的內建LED熄滅
Serial.begin(115200);
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本地IP位址
boolean result=WiFi.softAP(softSsid);
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
Serial.println();
}
// 主迴圈程式區:
void loop() {
client=server.available(); //
if(!client)
return;
// 有客戶端裝置連線上ESP8266 :
URI=client.readStringUntil('\r'); // 取得第一行GET部分的內容
client.flush(); // 將客戶端裝置傳送來的資料清空
Serial.println("Request end!"); // 送出提示訊息至Arduino IDE串列監控視窗中
Serial.print("Uri = ");
Serial.println(URI);
if(URI.indexOf("/LedOn")>0) // 測試URI是否為點亮LED指令
LedOn(); // 若是則呼叫點亮LED副程式
else if (URI.indexOf("/LedOff")>0) // 測試URI是否為熄滅LED指令
LedOff(); // 若是則呼叫熄滅LED副程式
else if (URI.indexOf("/")>0) // 測試是否為網頁首頁URI
handleRoot(); // 呼叫網頁首頁處理副程式
else
handleNotFound(); // 若傳來的URI內容不在預期的指令中呼叫回傳錯誤提示副程式
delay(5);
} // 主迴圈程式結束
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
html_Echo="<h3>LED目前狀態 : 熄滅</h3><br>";
String s=MAIN_page; // 取的網頁的前半段html語言程式碼
s+=html_Echo; // 加上狀態訊息字串
s+=html_LedOn; // 加入html語言表單按鈕程式碼字串
s+=html_end; // 加入網頁結尾的html語言程式碼字串
client.print(s); // 送除回應訊息給發出請求的客戶端
Serial.println("Client is connected!");
Serial.println();
}
// 處理LED點亮請求的事件對應函式:
void LedOn() {
html_Echo="<h3>LED目前狀態 : 點亮</h3><br>";
String s=MAIN_page;
s+=html_Echo;
s+=html_LedOff;
s+=html_end;
digitalWrite(LED,0);
client.print(s);
Serial.println("LED is On!");
Serial.println();
}
// 處理LED熄滅請求的事件對應函式:
void LedOff() {
html_Echo="<h3>LED目前狀態 : 熄滅</h3><br>";
String s=MAIN_page;
s+=html_Echo;
s+=html_LedOn;
s+=html_end;
digitalWrite(LED,1);
client.print(s);
Serial.println("LED is Off!");
Serial.println();
}
// 處理客戶請求錯誤的事件對應函式:
void handleNotFound(){
String s=MAIN_page;
s+="<h3>動作錯誤! ==> ";
s+=URI;
s+="</h3><br>";
s+=html_end;
client.print(s);
Serial.print("URI not found -->");
Serial.println(URI);
Serial.println();
}
程式名稱:softAP_6_5_1Led6_but.ino
◎ 程式說明:
同樣的《softAP_6_5_1Led6_but.ino》這個範例程式可說是前面【六、5-1.3】小節中的《softAP_6_5_1Led4_href.ino》程式改良版,只是把網頁程式中的超連結(href)改成表單(form)而已;其中的5~22行同樣也是在實作《softAP_6_5_1Led4b_form.html》這個html網頁程式的前半段,然後把表單按鈕的html語言部分以“html_LedOn”和”html_LedOff”這兩個html語法的字串變數來取代(32~35行),最後再加上一段html網頁語法的結尾字串“html_end”(36行)。
至於初始化程式(setup())部分,則是少了對應到各種不同的URI請求的設定(即server.on()指令),而這部分的功能改到了主迴圈程式(loop())區塊中去判斷實作。由於網頁中的LED亮滅控制按鈕在按下時,分別會送來點亮(“/LedOn”)和熄滅(“/LedOff”)用的URI請求,當客戶端瀏覽器連上伺服器時所送出的內容,其中第一行訊息就是GET的請求內容,所以本範例主迴圈程式區塊(70~90行)中,實際上只用第75行程式去取得客戶端傳來的第一行訊息資料:
URI=client.readStringUntil('\r'); // 只讀取GET請求的第一行,也就是URI
接著用Arduino內建的字串處理函式「.indexOf(“???”)」去尋找要比對測試的標的URI,然後再依測試結果,分別呼叫對應的服務副程式(程式79~89行)。
程式剩下的部份便是對應到不同URI請求的副程式其中94~103行是用來處理首頁’/’請求的自訂函式《void handleRoot()》:
void handleRoot(){
html_Echo="<h3>LED目前狀態 : 熄滅</h3><br>";
String s=MAIN_page; // 取的網頁的前半段html語言程式碼
s+=html_Echo; // 加上狀態訊息字串
s+=html_LedOn; // 加入html語言表單按鈕程式碼字串
s+=html_end; // 加入網頁結尾的html語言程式碼字串
client.print(s); // 送除回應訊息給發出請求的客戶端
Serial.println("Client is connected!");
Serial.println();
}
在上列的自訂副程式中,我們使用像堆積木的方式,把一個完整的網頁首頁內容累積成目的字串”s”,然後再用標準Arduino的WiFi指令”client.print(s)”回傳給發出請求的客戶端,如果接收無誤,使用者的瀏覽器上便會出現【圖六、24a】的畫面。
至於對應的點亮LED的URI請求(“/LedOn”)副程式,《void LedOn()》和首頁處理副程式《void handleRoot()》的差別只有兩點,一是標記2的LED亮滅提示訊息改成107行的:
html_Echo="<h3>LED目前狀態 : 點亮</h3><br>";
再來就是多了一行(112行)點亮LED輸出的:
digitalWrite(LED,0);
其他的部分完全相同!請讀者自行參考前面的說明。
而熄滅用的URI請求(“/LedOff”)副程式《void LedOff()》,和首頁處理副程式《void handleRoot()》的差別更是只有一點,就是多了一行(125行)熄滅LED輸出的:
digitalWrite(LED,1);
◎ 執行結果:
【圖六、25a】是手機瀏覽器連線後螢幕的畫面,和上一個範例的差別是畫面中的最上面一行是『單一LED亮滅使用Form示範2』的提示訊息;因為是剛連上網頁的首頁,所以會看到標記1的網址輸入欄位列的內容是[ 192.168.0.100 ],而且標記2的「LED 目前狀態:」這段文字的右邊是顯示「熄滅」,至於控制用的按鈕(標記3)上的提示文字則是[點亮LED]。
圖六、25a 使用手機瀏覽器連線後畫面
下面的【圖六、25b】與【圖六、25c】和前面的【圖六、24b】、【圖六、24c】畫面幾乎一模一樣,差別只是在最上面一行的提示訊息變成『單一LED亮滅使用Form示範2』而已,如果不特別去改成”2”,那麼結果將會是完全相同的
圖六、25b 點選「點亮LED」按鈕後手機瀏覽器畫面
圖六、25c點選「熄滅LED」按鈕後手機瀏覽器畫面
六、5-1.4 應用篇:實作一手機遙控繼電器電路
經由前面幾個個範例的說明後,讀者應該對如何控制單一LED的亮滅有些概念了吧!不過如果只是控制LED,可能會覺得不夠成就感,接著就讓我們利用前面學過的範例,在稍作修改後改為透過繼電器去控制一些較大電力的開關或是燈具等家電,這樣設計出來的系統也比較實際。
由於ESP8266的輸出能力並不大,驅動一顆LED燈還OK,如果想直接推動繼電器恐怕是力有未逮,更不要說一般家電用的AC110插座或開關了!為了簡化我們的系統,所以本範例打算使用目前市面上很流行的[ESP8266/ESP-01繼電器WiFi模組],它的外觀如下面的【圖六、26】所示:
圖六、26 ESP8266/ESP-01 WiFi繼電器模組完整外觀
在圖中左上方的是ESP8266/ESP-01 WiFi繼電器模組完整外觀,而右上方的照片是拿掉ESP-01後的零件上視圖,其中用紅線框起來標記1的部分是LED動作的指示LED燈,也是ESP-01這塊模組上的GP00腳;從照片中可看出模組上的繼電器接點可以承受10Amp的電流,其工作電壓交流可到250VAC,即使用在一般的125VAC家庭電源,也可以控制到1250Watt的功率,這麼大的功率對一般的應用來說應該是很夠了。
至於模組左上方標記2黃色8Pin的插座,是供ESP-01連接用的插座,如果參考下方的底視圖可得知,中間標記3綠色2Pin的接線栓是這塊模組的電源輸入腳,工作電壓是5V。至於右邊標記4綠色3Pin的接線栓則是模組上的繼電器輸出控制腳,這個繼電器是所謂的單刀雙擲(SPDT)型繼電器,其中的”COM”是共同腳,”NC”是常閉接點,而”NO”則是常開接點;至於要如何使用就依個人的需要了,一般來說是使用”COM”與”NO”腳,也就是不動作(Off)時兩個點是開路的,當按下開(ON)或啟動時才會連接在一起。
圖六、27 ESP-01S WiFi模組外觀與接腳名稱
【圖六、27】是ESP-01S WiFi模組的外觀與接腳名稱,ESP-01這個系列的模組板,可說是ESP8266這個WiFi單晶片的起家模組,由於便宜又容易使用,早就被許多業餘玩家或專業人士所廣泛使用;目前最新的版本是ESP-01S,不過接腳數目與功能還是跟以前一樣,其接腳編號與功能名稱如下:
GND :ESP-01電源接地腳。
U0TXD/GPIO1 :非同步串列傳輸埠(UART)0的發送腳。
GPIO2/U1TXD :主要功能為輸出/入腳GPIO02。
CH_PD/Chip_EN :晶片致能腳,燒錄時須接到VCC。
GPIO00 :輸出/入腳GPIO00,燒錄時須接地。
EXT_RSTB :晶片重置腳。
U0RXD/GPIO3 :非同步串列傳輸埠(UART)0的接收腳。
VCC/3.3V :ESP-01電源的+輸入腳,電壓為3.3V過高會燒毀。
【圖六、27】左邊ESP-01S模組板右下方用紅線框起來的地方,是併接在「GPIO2/U1TXD」腳的一顆LED顯示器,當燒錄程式時這顆LED會隨之閃爍,等燒錄完成後便可以拿來當成輸出/入腳使用。在燒錄ESP-01時,除了要接上與電腦連接的U0TXD (Pin2)與U0RXD(Pin7)之外,在接上電源之前CH_PD(Pin4)與GPIO00(Pin5)還必須分別接到VCC(Pin8/3.3V)及GND電位,否則會無法正常燒錄!由於ESP-01系列模組並不具有與電腦連接的介面,所以大多是使用USB轉UART/RS232模組來燒錄(如【圖六、28】所示),或是偷工減料使用Arduino Uno板來代用(如【圖六、29】所示)亦可!
圖六、28 使用USB轉UART模組燒錄ESP-01
圖六、29 使用Arduino Uno板來取代USB轉UART模組燒錄ESP-01
不過對初學者來說還是經常會弄錯腳位,甚至接到5V的電源,以致於將ESP-01模組燒毀;為了一勞永逸,建議使用【圖六、30】所示的ESP-01專用USB轉UART燒錄模組,這樣既方便使用,又不必擔心把ESP-01燒壞了!
圖六、30 常見USB轉ESP-01 UART燒錄模組
在前面的章節介紹過的ESP-202實驗模組板,也可以拿來燒錄ESP-01;下面的【圖六、31】介紹了ESP-202 WiFi模組板外觀接腳名稱,與連接ESP-01方法。如果把ESP-202當成ESP-01燒錄器使用,和原來作為實驗板的差別有兩點,一是標記1所示的兩個跳線接頭的位置,如果兩個接頭都在左邊是作為實驗板之用,此時程式會直接燒錄在板子上面的ESP8266郵票板;如果要拿來燒錄外接的ESP-01,那麼兩個跳線接頭都必須移到在右邊,不過此時標記2的兩個指撥開關的位置就必須撥在1下(OFF)2上(ON)的地方,這剛好和當成試驗板用時相反。
圖六、31 ESP-202 WiFi模組板外觀接腳名稱與連接ESP-01方法
◎ 範例程式功能與動作說明:
1、使用單一個表單(form)的提交(submit)按鈕控制ESP8266/ESP-01繼電器模組開關動作,電源開機時繼電器是處於不動作(Off)狀態。
2、此按鈕按一次繼電器會啟動(開/On),再按一次則會繼電器會不動作(關/Off),而繼電器動作的結果會回傳到連線裝置瀏覽器的螢幕上讓使用者知道。
依照之前的慣例,我們還是先寫一段html的網頁程式,先在電腦上驗證瀏覽器的畫面無誤後,再移植到ESP8266上。下面的《softAP_6_5_1Led6_RY0.html》程式,便是此測試及驗證用的html程式:
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background-color: pink; font-size:120%;}
.button2 {padding:10px 10px 10px 10px; width:100%; background-color: yellowgreen; font-size:120%;}
</style>
</head>
<body>
<div id='main'>
<h4>使用手機遙控單一繼電器範例程式</h4>
<h3>繼電器目前狀態 : 關(Off)</h3><br>
<form action='LedOff'><input class='button' type='submit' value='開(On)'>
</form><br>
</div>
</body>
</html>
程式名稱:softAP_6_5_1Led5_RY0.html
本範例程式是前一小節中的《softAP_6_5_1Led4b_form.html》這個html網頁程式的改良版,其中不同之處只有16~18行的內容改成下面的程式而已,其餘的部分完全一樣。
16. <h4>使用手機遙控單一繼電器範例程式</h4>
17. <h3>繼電器目前狀態 : 關(Off)</h3><br>
18. <form action='LedOff'><input class='button' type='submit' value='開(On)'>
為了減少程式的變動,所以當控制按鈕按下時所送出的RUI和前一個範例一樣,分別是代表啟動的「/LedOn」,和關閉的「/LedOff」,這樣整個ESP8266的程式就只有網頁html部分需要稍作修改就可以套用了!
圖六、32 《softAP_6_5_1Led5_RY0.html》於電腦瀏覽器執行結果
上面的【圖六、32】是《softAP_6_5_1Led5_RY0.html》這個html程式在電腦上瀏覽器執行結果,畫面符合我們的需求,因此我們只要將前一個範例程式《softAP_6_5_1Led6_but.ino》中,網頁html部分程式稍作修改就可以了。
以下是此範例程式的完整列表:
#include <ESP8266WiFi.h> // 引入ESP8266專用的WiFi函式庫
//----------------------------------------------
// 將我們的HTML 網頁程式內容直接建構在program memory內:
const char MAIN_page[] PROGMEM = R"=====(
<!DOCTYPE html>
<html>
<head>
<meta name='viewport' content='width=device-width, initial-scale=1.0'/>
<meta charset='utf-8'>
<style>body {font-size:140%;} #main {display:table; margin:auto;
padding:0 10px 0 10px;} h3,{text-align:center;} h4,{text-align:center;}
.button {padding:10px 10px 10px 10px; width:100%; background-color:pink; font-size:120%;}
.button2 {padding:10px 10px 10px 10px; width:100%; background-color:yellowgreen; font-size:120%;}
</style>
</head>
<body>
<div id='main'>
<h4>使用手機遙控單一繼電器範例程式</h4>
)=====";
//---------------------------------------------------
String softSsid = "ESP_softAP01"; // 設定AP存取點的SSID名稱
const char* softPassword = "12345678"; // 設定AP存取點的密碼值
const byte LED=0; // 將繼電器輸出控制腳改為GPIO00
String URI;
String html_LedOn="<form action='LedOn'><input class='button' type='submit' value='開(On)'></form><br>"; // 啟動繼電器的html表單程式
String html_LedOff="<form action='LedOff'><input class='button2' type='submit' value='關(Off)'></form><br>"; // 關閉繼電器的html表單程式
String html_end="</div></body></html>";
String html_Echo="";
IPAddress local_IP(192,168,0,100);
IPAddress gateway(192,168,0,1);
IPAddress subnet(255,255,255,0);
WiFiServer server(80);
WiFiClient client;
void setup() {
// put your setup code here, to run once:
pinMode(LED,OUTPUT); // 設定GPIO00腳為輸出腳
digitalWrite(LED,1); // 先讓GPIO00(繼電器控制腳)不動作(‘0’啟動)
Serial.begin(115200);
Serial.println();
Serial.print("Setting soft-AP with configuratin... ");
WiFi.softAPConfig(local_IP,gateway,subnet); // 設定新的本的IP位址
boolean result=WiFi.softAP(softSsid);
if(result==true)
{ // 初始化設定AP存取點成功
Serial.println("soft-AP ready!");
Serial.print("softAP = "); // 在Arduino IDE串列監控視窗中顯示目前
Serial.println(softSsid); // 顯示SSID名稱
Serial.print("softIP = "); // 在Arduino IDE串列監控視窗中顯示目前使用的
Serial.println(WiFi.softAPIP()); // 本地IP位址,在此為[ 192.168.0.100 ]
server.begin(); // 啟動伺服器功能
}
else
Serial.println("soft-AP failed");
}
// 主迴圈程式區:
void loop() {
client=server.available();
if(!client)
return;
URI=client.readStringUntil('\r');
client.flush();
Serial.println("Request end!");
Serial.print("Uri = ");
Serial.println(URI);
if(URI.indexOf("/LedOn")>0)
LedOn();
else if (URI.indexOf("/LedOff")>0)
LedOff();
else if (URI.indexOf("/")>0)
handleRoot();
else
handleNotFound();
delay(5);
} // 主迴圈程式結束
// 處理首頁’/’請求的自訂函式:
void handleRoot(){
html_Echo="<h3>繼電器目前狀態 : 關(Off)</h3><br>";
String s=MAIN_page; // 取的網頁的前半段html語言程式碼
s+=html_Echo; // 加上狀態訊息字串
s+=html_LedOn; // 加入html語言表單按鈕程式碼字串
s+=html_end; // 加入網頁結尾的html語言程式碼字串
client.print(s); // 送除回應訊息給發出請求的客戶端
Serial.println("Client is connected!");
Serial.println();
}
// 處理啟動繼電器(LedOn)請求的事件對應函式:
void LedOn() {
html_Echo="<h3>繼電器目前狀態 : 開(On)</h3><br>";
String s=MAIN_page; // 取的網頁的前半段html語言程式碼
s+=html_Echo; // 加上狀態訊息字串
s+=html_LedOff; // 加入html語言表單按鈕程式碼字串
s+=html_end; // 加入網頁結尾的html語言程式碼字串
client.print(s); // 送除回應訊息給發出請求的客戶端
digitalWrite(LED,0); // 啟動繼電器
Serial.println("LED is On!");
Serial.println();
}
// 處理關閉繼電器(LedOff)請求的事件對應函式:
void LedOff() {
html_Echo="<h3>繼電器目前狀態 : 關(Off)</h3><br>";
String s=MAIN_page; // 取的網頁的前半段html語言程式碼
s+=html_Echo; // 加上狀態訊息字串
s+=html_LedOn; // 加入html語言表單按鈕程式碼字串
s+=html_end; // 加入網頁結尾的html語言程式碼字串
client.print(s); // 送除回應訊息給發出請求的客戶端
digitalWrite(LED,1); // 關閉繼電器
Serial.println("LED is Off!");
Serial.println();
}
void handleNotFound(){
String s=MAIN_page;
s+="<h3>動作錯誤! ==> ";
s+=URI;
s+="</h3><br>";
s+=html_end;
client.print(s);
Serial.print("URI not found -->");
Serial.println(URI);
Serial.println();
}
程式名稱:softAP_6_5_1Led6_RY0.ino
◎ 程式說明:
《softAP_6_5_1Led6_RYO.ino》這個範例程式可說是前面【六、5-1.3】小節中的《softAP_6_5_1Led6_but.ino》程式改良版;其中的5~22行是在實作《softAP_6_5_1Led6_RY0.html》這個html網頁程式的前半段(1~16行),然後把表單按鈕的html語言部分以“html_LedOn”和”html_LedOff”這兩個html語法的字串變數來取代(30~33行):
String html_LedOn="<form action='LedOn'><input class='button' type='submit' value='開(On)'></form><br>";
String html_LedOff="<form action='LedOff'><input class='button2' type='submit' value='關(Off)'></form><br>";
最後再加上一段html網頁語法的結尾字串“html_end”(34行):
String html_end="</div></body></html>";
而初始化程式(setup())與主迴圈(loop())程式部分一字不改的沿用就可以,其他要修改的部分就是剩下的幾個自訂的URI服務函式,其中網頁首頁的服務函式《void handleRoot()》與繼電器關閉函式《void LedOff()》,是把輸出狀態訊息改成繼電器狀態訊息(92與118行):
html_Echo="<h3>繼電器目前狀態 : 關(Off)</h3><br>";
至於繼電器啟動函式《void LedOn()》,則是改成下面的內容(105行)就可以了:
html_Echo="<h3>繼電器目前狀態 : 開(On)</h3><br>";
由於沒有刻意去修飾一些文字,所以整個程式只需要做些許的變動,就可以從控制LED的亮滅,改成控制繼電器的開關動作,這樣是不是很簡單呢﹖
◎ 執行結果:
【圖六、33】是手機瀏覽器連線後螢幕的畫面,和上一個範例的差別是畫面中的最上面一行是『使用手機遙控單一繼電器範例程式』的提示訊息;因為是剛連上網頁的首頁,所以會看到標記1的網址輸入欄位列的內容是[ 192.168.0.100 ],而且「繼電器目前狀態:」這段文字的右邊(標記2)是顯示「關(Off)」,至於控制用的按鈕(標記3)上的提示文字則是[開(On)]。
圖六、33 手機連線ESP8266/ESP-01 WiFi繼電器模組後瀏覽器畫面
【圖六、34】上方是按下開啟(開/On)按鈕後手機螢幕的畫面,下方則是繼電器實際開關的狀態,此時接在GPIO00的LED燈是點亮的;在標記1的網址輸入欄位列的內容會變成[ 192.168.0.100 /LedOn?],而且「繼電器目前狀態:」這段文字的右邊(標記2)是顯示[開(On)],至於控制用的按鈕(標記3)上的提示文字則切換成「關(Off)」。
圖六、34 按下開啟(開/On)按鈕後瀏覽器畫面與繼電器狀態
【圖六、35】是按下關閉(關/Off)按鈕後的畫面,看起來和【圖六、33】幾乎一模一樣,只是標記1的網址輸入欄位列的內容會變成[ 192.168.0.100 /LedOff?]而已,控制用的按鈕(標記3)上的提示文字又再次切換回「關(Off)」,以後手機瀏覽器的畫面就只會在【圖六、34】與【圖六、35】之間切換。由於標記2是顯示[關(Off)],所以下面繼電器照片中接在GPIO00的LED燈是熄滅的。
圖六、35按下關閉(關/Off)按鈕後瀏覽器畫面及繼電器狀態
沒有留言:
張貼留言