搭建ESP8266 Web Server –程式碼和原理圖

本課程是一個循序漸進的指南,顯示了如何建置一個獨立的ESP8266 Web Server來控制兩個輸出(兩個LED)。該ESP8266 NodeMCU Web Server具有行動回應能力,可通過您本地網絡中的瀏覽器用任何設備對其進行存取。

如果您想了解更多有關ESP8266模塊的信息,請先閱讀我的ESP8266 WiFi模塊入門指南。 

本教程介紹了兩種構建Web服務器的方法:

  • 第1部分:使用Arduino IDE建立Web Server
  • 第2部分:使用NodeMCU韌體建立Web Server

這裡我們先只介紹第1部分的開發方式,第2部分之後有機會再來介紹給大家。

準備Arduino IDE 

1.在您的操作系統上下載並安裝Arduino IDE(某些舊版本將無法使用)。

2. 然後,您需要為Arduino IDE安裝ESP8266插件。為此,請轉到檔案>偏好設定

3. 輸入http://arduino.esp8266.com/stable/package_esp8266com_index.json進入“額外的開發板管理員網址”字段,如下圖所示。然後,點擊“確定”按鈕。

4. 轉到工具>開發板>開發板管理員

5. 向下滾動,選擇ESP8266開發板選單,並安裝“ ESP8266 Community的esp8266 ”,如下圖所示。

6.轉到工具>開發板,然後選擇您的ESP8266開發板。然後,重新打開Arduino IDE。

程式碼 

將以下程式碼複製到您的Arduino IDE,但尚未上傳。您需要進行一些更改以使其適合您。

/*********
  Terry Lee
  完整說明請參閱 http://honeststore.com.tw  
*********/

// 載入Wi-Fi資料庫
#include <ESP8266WiFi.h> 

// 將下列ssid及pass替換為您的網絡憑據
const char* ssid     = "替換成你的SSID";
const char* password = "替換成你的PASSWORD";

// 設定web server端口為80 port
WiFiServer server(80);

// 設定變數header為HTTP請求值
String header;

// 輔助變數存儲當前輸出狀態
String output5State = "off";
String output4State = "off";

// 將輸出變數分配給GPIO引腳
const int output5 = 5;
const int output4 = 4;

// 當前時間
unsigned long currentTime = millis();
// 前次時間
unsigned long previousTime = 0; 
// 定義暫時時間以毫秒為單位 (example: 2000ms = 2s)
const long timeoutTime = 2000;

void setup() {
  Serial.begin(115200);
  // 將輸出變數初始化為輸出PIN引腳模式
  pinMode(output5, OUTPUT);
  pinMode(output4, OUTPUT);
  // 將輸出設定為LOW低電位
  digitalWrite(output5, LOW);
  digitalWrite(output4, LOW);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // 列出得到的區域端IP及啟動web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // 傾聽clients傳入的值

  if (client) {                             // 假如有一個新的client端連線,
    Serial.println("New Client.");          // 在序列端口中印出訊息
    String currentLine = "";                // 設定String儲存從客戶端傳入的數據
    currentTime = millis();
    previousTime = currentTime;
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // 當client端連線時,持續循環{}內動作 currentTime = millis(); if (client.available()) { // 如果有客戶端讀取的字節 char c = client.read(); // 閱讀一個字元, 然後 Serial.write(c); // 印出到序列顯示器 header += c; if (c == '\n') { // 如果字元是換行符號 // 如果當前行為空白,則您可以連續兩個換行符號 // 這是client端HTTP請求的結束,所以發送回應: if (currentLine.length() == 0) { // HTTP標頭始終以回應代碼開始 (e.g. HTTP/1.1 200 OK) // 和content-type,使客戶知道即將到來,然後是一個空白行 client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html; charset=utf-8"); client.println("Connection: close"); client.println(); // 打開和關閉GPIO if (header.indexOf("GET /5/on") >= 0) {
              Serial.println("GPIO 5 on");
              output5State = "on";
              digitalWrite(output5, HIGH);
            } else if (header.indexOf("GET /5/off") >= 0) {
              Serial.println("GPIO 5 off");
              output5State = "off";
              digitalWrite(output5, LOW);
            } else if (header.indexOf("GET /4/on") >= 0) {
              Serial.println("GPIO 4 on");
              output4State = "on";
              digitalWrite(output4, HIGH);
            } else if (header.indexOf("GET /4/off") >= 0) {
              Serial.println("GPIO 4 off");
              output4State = "off";
              digitalWrite(output4, LOW);
            }
  
            // 顯示HTML網頁
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS 格式的ON/OFF按鍵 
            // 隨時更改背景顏色和字體大小屬性
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");
            
            // 網頁標題
            client.println("<body><h1>ESP8266 Web Server</h1>");
            
            // 顯示當前狀態,以及GPIO 5的開/關按鍵狀態
            client.println("<p>GPIO 5 - State " + output5State + "</p>");
            // 如果output5State狀態是關閉,則按鍵會顯示ON 
            if (output5State=="off") {
              client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // 顯示當前狀態,以及GPIO 4的開/關按鍵狀態  
            client.println("<p>GPIO 4 - State " + output4State + "</p>");
            // 如果output4State狀態是關閉,則按鍵會顯示ON       
            if (output4State=="off") {
              client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");
            
            // HTTP回應以隔一行結尾
            client.println();
            // 跳出循環
            break;
          } else { // 如果你有一個換行符號,就清空currentLine變數值
            currentLine = "";
          }
        } else if (c != '\r') {  // 如果您有其他任何訊息,但不是回車字符,
          currentLine += c;      // 則將其值加到currentLine變數尾端
        }
      }
    }
    // 清除標題變數
    header = "";
    // 關閉連接
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

您需要使用網絡憑證修改以下兩個變數,以使ESP8266可以與路由器建立連接。

// 將下列ssid及pass替換為您的網絡憑據
const char* ssid     = "替換成你的SSID";
const char* password = "替換成你的PASSWORD";

上傳草稿圖 

將草稿圖上傳到ESP-12E

如果您使用的是ESP-12E NodeMCU套件,則上傳草稿圖非常簡單,因為它具有內建的編程器。將您的板子插入電腦。確保選擇了正確的開發板和COM端口。

然後,點擊Arduino IDE中的上傳按鈕,等待幾秒鐘,直到看到消息“ 儲存完畢”。在左下角。

原理圖 

要構建本教程的電路,您需要以下部分:

所需零件:

  • ESP8266 12-E 
  • 2個LED
  • 2個電阻 (220或330歐姆均可)
  • 麵包板
  • 跳線

如下圖所示,將兩個LED連接到ESP8266 –一個LED連接到 GPIO 4 (D2),另一個 GPIO 5 (D1)。

測試Web Server 

現在,在上傳程式碼後,它將立即生效。不要忘記檢查您是否選擇了正確的開發板和COM端口,否則在上傳時會出現錯誤。以115200的鮑率打開序列監視器。

找到ESP IP地址

按下ESP8266 RESET按鈕,它將在序列監視器上輸出ESP IP地址

複製該IP地址,因為您需要它來存取Web Server。

存取Web Server

打開瀏覽器,輸入ESP IP地址,您將看到以下頁面。當您在ESP IP地址上請求時,此頁面由ESP8266發送。

如果看一下序列監視器,您可以看到背景情況。ESP從新客戶端(在本例中為您的瀏覽器)接收HTTP請求。

您還可以查看有關HTTP請求的其他信息-這些字段稱為HTTP標頭字段,它們定義HTTP事務的操作參數。

測試Web服務器

讓我們測試一下Web Server。點擊按鈕GPIO 5上。ESP在/ 5 / on URL上收到請求,然後將LED 5點亮。

LED狀態也會在網頁上更新。

測試 GPIO 4 按鈕並檢查它是否以類似的方式工作。

程式碼如何工作 

現在,讓我們仔細看一下程式碼,看看它是如何工作的,方便您可以對其進行修改以滿足您自己的需求。 首先您需要做的第一件事是include ESP8266WiFi 程式庫。
// 載入Wi-Fi資料庫
#include <ESP8266WiFi.h> 

如前所述,您需要在雙引號內中輸入您的ssid和密碼。

const char* ssid = "";
const char* password = "";

然後,將Web Server端口設為80。

// 設定web server端口為80 port
WiFiServer server(80);

接下來建立一個變數來存儲HTTP請求的標頭:

String header;

接下來,建立輔助變數以存儲輸出取得的當前狀態。如果要增加更多輸出並保存其狀態,則需要建立更多變數。

// 輔助變數存儲當前輸出狀態
String output5State = "off";
String output4State = "off";

您還需要為每個輸出分配一個GPIO。這裡我們使用GPIO 4 (D2)和 GPIO 5(D1)。您也可以使用任何其他合適的GPIO。

// 將輸出變數分配給GPIO引腳
const int output5 = 5;
const int output4 = 4;

setup()

接著,讓我們進入 setup()。在setup()中,該函數只會在ESP第一次啟動時運行一次。首先,出於調試目的,我們以115200的鮑率啟動序列通信。

Serial.begin(115200);

接著將GPIO定義為OUTPUT,並將其設置為LOW。

// 將輸出變數初始化為輸出PIN引腳模式
  pinMode(output5, OUTPUT);
  pinMode(output4, OUTPUT);
  // 將輸出設定為LOW低電位
  digitalWrite(output5, LOW);
  digitalWrite(output4, LOW);

以下幾行開始與Wi-Fi連接 WiFi.begin(ssid,密碼),等待連接成功,然後在序列監視器中印出ESP IP地址。

// Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // 列出得到的區域端IP及啟動web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();

loop()

在loop() 裡,我們編程當新客戶端與Web Server建立連接時會發生什麼。 ESP始終通過下列該行程式碼監聽傳入的客戶端輸出狀態值:

WiFiClient client = server.available();   // 傾聽clients傳入的值

收到客戶的請求後,首先將儲存傳入的數據。只要客戶端保持連接,隨後的while循環將一直運行。我們不建議您更改程式碼以下的部分,除非您確實知道自己要做什麼。

if (client) {                             // 假如有一個新的client端連線,
    Serial.println("New Client.");          // 在序列端口中印出訊息
    String currentLine = "";                // 設定String儲存從客戶端傳入的數據
    currentTime = millis();
    previousTime = currentTime;
    while (client.connected() && currentTime - previousTime <= timeoutTime) { // 當client端連線時,持續循環{}內動作
      currentTime = millis();         
      if (client.available()) {             // 如果有客戶端讀取的字節
        char c = client.read();             // 閱讀一個字元, 然後
        Serial.write(c);                    // 印出到序列顯示器
        header += c;
        if (c == '\n') {                    // 如果字元是換行符號
          // 如果當前行為空白,則您可以連續兩個換行符號
          // 這是client端HTTP請求的結束,所以發送回應:
          if (currentLine.length() == 0) {
            // HTTP標頭始終以回應代碼開始 (e.g. HTTP/1.1 200 OK)
            // 和content-type,使客戶知道即將到來,然後是一個空白行
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html; charset=utf-8");
            client.println("Connection: close");
            client.println();

if and else語句的下一部分檢查在網頁中按下了哪個按鈕,並對應地控制輸出。如前所述,我們會根據所按下的按鈕在不同的URL上發出請求。

            // 打開和關閉GPIO
            if (header.indexOf("GET /5/on") >= 0) {
              Serial.println("GPIO 5 on");
              output5State = "on";
              digitalWrite(output5, HIGH);
            } else if (header.indexOf("GET /5/off") >= 0) {
              Serial.println("GPIO 5 off");
              output5State = "off";
              digitalWrite(output5, LOW);
            } else if (header.indexOf("GET /4/on") >= 0) {
              Serial.println("GPIO 4 on");
              output4State = "on";
              digitalWrite(output4, HIGH);
            } else if (header.indexOf("GET /4/off") >= 0) {
              Serial.println("GPIO 4 off");
              output4State = "off";
              digitalWrite(output4, LOW);
            }

例如,如果您按了 GPIO 5“開啟”按鈕,URL更改為ESP IP地址,後跟/ 5 / ON,我們在HTTP標頭上收到該信息。因此,我們可以檢查標題是否包含表達式GET / 5 / on。 如果包含,則程式碼在序列監視器上印出一條消息,更改 output5State 變數打開,並打開LED。 其他按鈕也是如此運作。因此,如果要增加更多輸出控制,則應修改代程式碼的這一部分。

顯示HTML網頁

接下來需要做的是生成網頁。ESP8266將通過一些HTML文本向瀏覽器發送響應以顯示網頁。

該網頁使用 client.println()功能。您應該輸入要發送給客戶端的參數。

您應該始終發送的第一個text是下列這一行,表示我們正在發送HTML。

<!DOCTYPE html><html>

然後,以下行使網頁在任何Web瀏覽器中都回應。

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");

下一個用於防止與網站圖標相關的請求。

client.println("<link rel=\"icon\" href=\"data:,\">");

網頁樣式

接下來,我們有一些CSS用來設置按鈕和網頁外觀的樣式。我們選擇Helvetica字體,定義要顯示為區塊並在中心對齊的內容。

client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");

我們使用一些屬性來設置按鈕樣式,以定義顏色,大小,邊框等。

client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");

然後,我們定義第二個按鈕的樣式,具有我們先前定義的按鈕的所有屬性,但是具有不同的顏色。是關閉按鈕的樣式。

client.println(".button2 {background-color: #77878A;}</style></head>");

設置網頁第一個標題

在下一行中,設置網頁的第一個標題,您可以將此text更改為任意內容。

// 網頁標題
client.println("<body><h1>ESP8266 Web Server</h1>");

顯示按鈕及其對應狀態

然後,寫一個段落來顯示 GPIO 5當前狀態。如您所見,我們使用output5State 變數,以便在此變數更改時狀態立即更新。

client.println("<p>D1(GPIO 5) - 狀態 " + output5State + "</p>");

然後,根據GPIO的當前狀態,顯示開或關按鈕。

if (output5State=="off") {
client.println("<p><a href=\"/5/on\"><button class=\"button\">開</button></a></p>");
} else {
client.println("<p><a href=\"/5/off\"><button class=\"button button2\">關</button></a></p>");
} 

GPIO 4也是一樣的解析。

斷開連接

最後,當回應結束時,我們清除header變量,並使用以下命令停止與客戶端的連接 client.stop()

// 清除標題變數
header = "";
// 關閉連接
client.stop();

更進一步 

現在您知道了程式碼的工作原理,可以修改程式碼以增加更多輸出,或修改您的網頁。要修改您的網頁,您可能需要了解一些HTML和CSS。

您可以控制一個繼電器來控制幾乎所有的電子設備,而不必控制兩個LED 。

要建立Web Server以顯示感測器讀數,您可以閱讀以下教程:

  • ESP8266 DHT溫濕度Web服務器(Arduino IDE)
  • ESP8266 DS18B20 Temperature Web Server(Arduino IDE)

另外,如果您想使用MicroPython對ESP8266進行編程,則可以閱讀以下教程:ESP32 / ESP8266 MicroPython Web Server –控制輸出

如果您喜歡ESP8266,請確保您了解我們有關ESP8266的家庭自動化課程。

謝謝閱讀。

發佈留言