You are currently viewing ESP8266 WebSocket Server:控制輸出

ESP8266 WebSocket Server:控制輸出

在本教程中,您將學習如何使用ESP8266使用WebSocket通信協議建置Web Server。作為範例,我們將向您展示如何建立一個網頁來遠程控制ESP8266的輸出。輸出狀態顯示在網頁上,並在所有客戶端中自動更新。

ESP8266將使用Arduino IDE和ESPAsyncWebServer進行編程。我們也為ESP32提供了類似的WebSocket指南。

如果您一直在關注我們以前的某些Web服務器項目,例如,您可能已經註意到,如果同時打開多個選項卡(在相同或不同設備上),則狀態不會全部更新標籤,除非您刷新網頁。為了解決這個問題,我們可以使用WebSocket協議-發生更改時可以通知所有客戶端,並相應地更新網頁。

本教程基於(StéphaneCalderoni)建立記錄的項目。您可以在這裡閱讀他優秀的教程。

ESP32 ESP8266 WebSocket服務器如何工作

Client通過稱為WebSocket handshake的過程與Server建立WebSocket連接。handshake始於HTTP請求/回應,允許Server在同一端口上處理HTTP連接以及WebSocket連接。建立連接後,Client和Server即可以全雙工模式發送WebSocket數據。

使用WebSockets協議,Server(ESP32板)可以將信息發送到客戶端或所有客戶端,而無需請求。這也使我們可以在發生更改時將信息發送到Web瀏覽器。

此更改可能是網頁上發生的事情(點擊按鈕),也可能是ESP32端發生的事情,例如按下電路上的物理按鈕。

專案概況 

這是我們將為該專案建置的網頁。

  • ESP8266 WebServer顯示一個帶有按鈕的網頁,用於切換GPIO 2的狀態;
  • 為簡單起見,我們將控制GPIO 2 –開發板上的LED。您可以使用本範例來控制任何其他GPIO;
  • 該界面顯示當前的GPIO狀態。每當GPIO狀態發生變化時,界面會立刻更新。
  • GPIO狀態會在所有客戶端中自動更新。這意思是,如果在同一設備或不同設備上打開了多個Web瀏覽器選項,它們將同時更新。

它是如何運作的?

下圖描述了點擊“切換”按鈕時發生的情況。

點擊“切換”按鈕時,將會發生以下情況:

  1. 點擊“切換”按鈕;
  2. 客戶端(您的瀏覽器)通過WebSocket協議發送帶有“ toggle(切換)”消息的數據;
  3. ESP8266(Server)收到此消息,因此它知道應切換LED狀態。如果該LED先前已熄滅,則會開啟LED燈。
  4. 然後,它也通過WebSocket協議以新的LED狀態向所有客戶端發送數據;
  5. 客戶收到消息並相應地更新網頁上的led狀態。這樣,當發生更改時,我們幾乎可以立即更新所有客戶端。

準備Arduino IDE 

我們將使用Arduino IDE對 ESP8266開發板進行編程,請確保已將其安裝在Arduino IDE中。

安裝庫–AsyncWebServer

為了建立WebServer,我們將使用ESPAsyncWebServer庫。該庫需要ESPAsyncTCP庫才能正常工作。點擊下面的鏈接下載庫。

這些庫無法通過Arduino庫管理器安裝,因此您需要將庫文件複製到Arduino安裝庫文件夾。另外,在Arduino IDE中,您可以轉到 “草稿碼”  >“ 匯入程式庫”  >“ 加入.zip程式庫”, 然後選擇剛下載的程式庫。

ESP8266 NodeMCU WebSocket Server程式碼 

以下代程式碼複製到您的Arduino IDE。

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

// 載入必須程式庫
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>

// 替換成您的網絡憑據
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

bool ledState = 0;
const int ledPin = 2;

// 在端口80上建立asyncwebserver物件
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
   /*.button:hover {background-color: #0f8b8d}*/
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
  </style>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP WebSocket Server</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Output - GPIO 2</h2>
      <p class="state">state: <span id="state">%STATE%</span></p>
      <p><button id="button" class="button">Toggle</button></p>
    </div>
  </div>
<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  window.addEventListener('load', onLoad);
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  function onLoad(event) {
    initWebSocket();
    initButton();
  }
  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }
</script>
</body>
</html>
)rawliteral";

void notifyClients() {
  ws.textAll(String(ledState));
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    if (strcmp((char*)data, "toggle") == 0) {
      ledState = !ledState;
      notifyClients();
    }
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
    switch (type) {
      case WS_EVT_CONNECT:
        Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
        break;
      case WS_EVT_DISCONNECT:
        Serial.printf("WebSocket client #%u disconnected\n", client->id());
        break;
      case WS_EVT_DATA:
        handleWebSocketMessage(arg, data, len);
        break;
      case WS_EVT_PONG:
      case WS_EVT_ERROR:
        break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

String processor(const String& var){
  Serial.println(var);
  if(var == "STATE"){
    if (ledState){
      return "ON";
    }
    else{
      return "OFF";
    }
  }
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  initWebSocket();

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Start server
  server.begin();
}

void loop() {
  ws.cleanupClients();
  digitalWrite(ledPin, ledState);
}

將下列的網路憑據替換成您的區域SSID及密碼,該程式碼就可以立即作用。

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

 程式碼如何工作 

 

繼續閱讀以了解程式碼的工作原理,或跳至“展示”部分。

導入庫

導入必要的庫以建立WebServer。

#include <ESP8266WiFi.h> 
#include <ESPAsyncTCP.h> 
#include <ESPAsyncWebServer.h> 

網路憑證

將網路憑據替換以下變數值:

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

GPIO輸出

建立一個變數名為 ledState 來保存GPIO狀態和一個變數 ledPin參照為您要控制的GPIO。在這種情況下,我們將控制開發板LED(連接到GPIO 2)。

bool ledState = 0;
const int ledPin = 2;

AsyncWebServer和AsyncWebSocket

建立一個 AsyncWebServer 端口為80的物件。

AsyncWebServer server(80);

ESPAsyncWebServer程式庫包含一個WebSocket插件,可以容易處理WebSocket連接。建立一個AsyncWebSocket 物件稱為 ws 來處理 / ws 路徑的連結。

AsyncWebSocket ws("/ws");

建立網頁

 index_html 變數要建立,設置網頁樣式和使用WebSocket協議處理客戶端-服務器交互所需要HTML,CSS和JavaScript。

注意:我們將建立網頁需要的所有內容都放置在Arduino草稿碼中的index_html使用的變量上。
請注意,分別HTML,CSS和JavaScript程式,然後將它們上傳到ESP8266文件系統並在程式碼中引用它們,會更為實用。

下面是index_html的內容

<!DOCTYPE HTML>
<html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
  </style>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP WebSocket Server</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Output - GPIO 2</h2>
      <p class="state">state: <span id="state">%STATE%</span></p>
      <p><button id="button" class="button">Toggle</button></p>
    </div>
  </div>
<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }

  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  window.addEventListener('load', onLoad);
  function onLoad(event) {
    initWebSocket();
    initButton();
  }

  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }
</script>
</body>
</html>

CSS

在<style></style>標籤之間,我們使用CSS對網頁進行樣式設置的語言。隨時對其進行更改,以使網頁看起來像您希望的樣式。這裏不會解釋此網頁的CSS如何作業,因為它與本WebSocket教程無關。

<style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2 {
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
 </style>

HTML

在<body></body>標籤之間,我們加入用戶可見的網頁內容。

<div class="topnav">
  <h1>ESP WebSocket Server</h1>
</div>
<div class="content">
  <div class="card">
    <h2>Output - GPIO 2</h2>
    <p class="state">state: <span id="state">%STATE%</span></p>
    <p><button id="button" class="button">Toggle</button></p>
  </div>
</div>

標題為<h1>ESP WebSocket Server</h1>,可隨意修改該標題。

<h1>ESP WebSocket Server</h1>

然後,標題<h2>帶有“Output – GPIO 2”文本。

<h2>Output - GPIO 2</h2>

之後,我們有一段顯示當前GPIO狀態。

<p class="state">state: <span id="state">%STATE%</span></p>

%STATE%是GPIO狀態的預留參數。發送網頁時,ESP8266會將其替換為當前值。HTML text上的預留參數應介於%之間。意思是%STATE% text就像一個變數,然後將其替換為實際值。

將網頁發送給客戶端后,只要GPIO狀態發生變化,狀態就需要動態更改。我們將通過WebSocket協議接收該信息。然後,JavaScript處理如何處理接收到的信息以相應地更新狀態。為了能夠使用JavaScript處理該text,該text必須具有我們可以引用的ID。在本案中,id代表state (<span id =“ state”>)。

最後,有一個帶有按鈕的段落可切換GPIO狀態。

<p><button id="button" class="button">Toggle</button></p>

請注意,我們為按鈕指定了ID(id =“button”)。

JavaScript –處理WebSockets

JavaScript在 <script> </ script>標籤之間。一旦Web界面完全加載到瀏覽器中,它便負責初始化與服務器WebSocket的連接,並通過WebSocket處理數據交換。

<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }

  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }

  window.addEventListener('load', onLoad);

  function onLoad(event) {
    initWebSocket();
    initButton();
  }

  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }

  function toggle(){
    websocket.send('toggle');
  }
</script>

讓我們看一下它是如何工作的。

閘道器是WebSocket接口的入口點。

var gateway = `ws://${window.location.hostname}/ws`;

window.location.hostname 獲得當前頁面地址(Web Server IP地址)。

建立一個新的全域變量,名為 websocket。

var websocket;

增加事件監聽器,該事件監聽器呼叫 onload 函數,它在網頁重載時會起作用。

window.addEventListener('load', onload);

onload() 函數調用 initWebSocket() 函數初始化與服務器和服務器之間的WebSocket連接,而initButton() 用於將事件監聽器增加到按鈕的功能。

function onload(event) {
  initWebSocket();
  initButton();
}

 initWebSocket()函數在先前定義的閘道器上初始化WebSocket連接。我們還為WebSocket連接狀態是開啟、關閉或接收消息時分配了幾個回調函數。

function initWebSocket() {
  console.log('Trying to open a WebSocket connection…');
  websocket = new WebSocket(gateway);
  websocket.onopen    = onOpen;
  websocket.onclose   = onClose;
  websocket.onmessage = onMessage;
}

打開連接後,我們只需在控制台中印出一條消息,然後發送一條消息“ hi”。ESP8266在收到該消息後,代表我們知道連接已初始化。

function onOpen(event) {
  console.log('Connection opened');
  websocket.send('hi');
}

如果由於某種原因Web socket連接已關閉,我們會再次調用 initWebSocket()函數 在2000毫秒(2秒)後再次運行。

function onClose(event) {
  console.log('Connection closed');
  setTimeout(initWebSocket, 2000);
} 

setTimeout() 方法在指定的毫秒數後調用函數或 運算式評估求值。

最後,我們需要處理收到新消息時發生的情況。服務器(您的ESP板)將發送“ 1”或“ 0”消息。根據收到的消息,我們希望在顯示狀態的段落上顯示“ ON”或“ OFF”消息。記住<span> 標記 id =“state”?我們將獲取該元素並將其值設置為ON或OFF。

function onMessage(event) {
  var state;
  if (event.data == "1"){
    state = "ON";
  }
  else{
    state = "OFF";
  }
  document.getElementById('state').innerHTML = state;
}

initButton() 函數通過其ID獲取按鈕(button)並增加’click’類型的事件監聽器 。

function initButton() {
  document.getElementById('button').addEventListener('click', toggle);
}

這意思是當您點擊按鈕時, toggle 函數會被調用。

這 toggle 函數將與WebSocket連接並送出訊息來 “切換” text。

function toggle(){
  websocket.send('toggle');
}

然後,ESP8266會在收到此消息後進行處理–切換當前的GPIO狀態。

處理WebSockets –Server

這此之前,您已經了解瞭如何在客戶端(瀏覽器)上處理WebSocket連接。現在,讓我們看一下如何在服務器端處理它。

通知所有客戶

 notifyClients()函數通過一條消息通知所有客戶端,其中包含您作為參數傳遞的內容。在這種情況下,每當發生更改時,我們都希望將當前的LED狀態通知所有客戶端。

void notifyClients() {
  ws.textAll(String(ledState));
}

AsyncWebSocket 類提供了一個 textAll() 向同一時間連接到服務器的所有客戶端發送相同消息的方法。

處理WebSocket消息

handleWebSocketMessage() function是一個回調函數,只要我們通過WebSocket協議從客戶端接收到新數據,該函數便會運行。

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    if (strcmp((char*)data, "toggle") == 0) {
      ledState = !ledState;
      notifyClients();
    }
  }
}

如果我們收到“toggle”消息,則會切換 ledState變數。此外,我們通過致電notifyClients()功能。這樣,所有客戶端都會收到有關更改的通知,並相應地更新介面。

if (strcmp((char*)data, "toggle") == 0) {
  ledState = !ledState;
  notifyClients();
}

配置WebSocket Server

現在,我們需要配置一個事件監聽器,以處理WebSocket協議的不同異步步驟。可以通過定義以下事件來實現此事件處理程序:onEvent() 如下:

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
 void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

這 類型參數表示發生的事件。它可以採用以下值:

  • WS_EVT_CONNECT 客戶端登錄時;
  • WS_EVT_DISCONNECT 客戶註銷時;
  • WS_EVT_DATA 當從客戶端接收到數據包時;
  • WS_EVT_PONG 響應ping請求;
  • WS_EVT_ERROR 從客戶端收到錯誤時。

初始化WebSocket

最後, initWebSocket() 函數初始化WebSocket協議。

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

processor()

processor ()函數負責在HTML文本上搜索預留參數,然後將其替換為我們想要的內容,然後再將網頁發送到瀏覽器。在我們的情況下,我們將替換%STATE% 預留參數,若預留參數 ledState的值是 1則顯示ON。否則,將其切換為OFF。

String processor(const String& var){
  Serial.println(var);
  if(var == "STATE"){
    if (ledState){
      return "ON";
    }
    else{
      return "OFF";
    }
  }
}

setup()

在setup()裡面,初始化串列監視器以進行調試。

Serial.begin(115200);

設置 ledPin 作為一個 OUTPUT 並將其設置為 LOW 程序在首次啟動時。

pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);

初始化Wi-Fi並在串列監視器上印出ESP8266 IP地址。

WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Connecting to WiFi..");
}

// Print ESP Local IP Address
Serial.println(WiFi.localIP());

通過調用初始化WebSocket協議 initWebSocket() 先前建立的功能。

initWebSocket();

處理請求

服務保存在 index_html當您在根目錄/ URL上收到請求時,該變量–您需要傳遞處理器 用作將預留參數替換為當前GPIO狀態的參數。

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html, processor);
});

最後,啟動服務器。

server.begin();

loop()

LED將通過物理方式控制 loop()

void loop() {
  ws.cleanupClients();
  digitalWrite(ledPin, ledState);
}

請注意,我們都稱 cleanupClients()方法。原因如下(來自ESPAsyncWebServer庫GitHub頁面的說明):

瀏覽器有時無法正確關閉WebSocket連接,即使 關閉()函數在JavaScript中被調用。這最終將耗盡Web服務器的資源,並導致服務器崩潰。定期致電cleanupClients() 主要功能 loop()當超過最大客戶端數量時,通過關閉最舊的客戶端來限制客戶端的數量。可以在每個週期調用一次,但是,如果您希望使用更少的功率,那麼每秒調用一次就足夠了。

範例 

在您的網路憑據上插入 ssid 和 密碼變量,您可以將代碼上傳到開發板上。不要忘記檢查您是否選擇了正確的開發板和COM端口。

上載程式碼後,以115200的鮑率打開串列監視器,然後按一下板載EN / RST按鈕。應印出ESP IP地址。

打開區域網上的瀏覽器,並鍵入ESP8266 IP地址。您應該可以訪問網頁來控制輸出。

ESP32 WebSocket服務器切換輸出項目概述

點擊按鈕切換LED。您可以同時打開多個Web瀏覽器選項卡,也可以從不同的設備訪問Web服務器,並且只要有更改,LED狀態就會在所有客戶端中自動更新。

總結 

在本教程中,您學習了如何使用ESP8266設置WebSocket服務器。WebSocket協議允許客戶端和服務器之間進行全雙工通信。初始化後,服務器和客戶端可以在任何給定時間交換數據。

這非常有用,因為服務器可以在發生任何事情時將數據發送到客戶端。例如,您可以在此設置中增加一個物理按鈕,當按下該按鈕時,該按鈕會通知所有客戶端以更新Web界面。

在本示例中,我們向您展示了如何控制ESP8266的一個GPIO。您可以使用此方法來控制更多的GPIO。您還可以使用WebSocket協議在任何給定時間發送傳感器讀數或通知。

我們希望您發現本教程對您有所幫助。

參考原文:https://randomnerdtutorials.com/esp8266-nodemcu-websocket-server-arduino/

This Post Has One Comment

  1. JOSEPH

    註明來源比較恰當。

發佈留言