{"id":99437,"date":"2020-10-07T18:02:46","date_gmt":"2020-10-07T18:02:46","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=99437"},"modified":"2025-03-14T16:35:10","modified_gmt":"2025-03-14T16:35:10","slug":"esp32-websocket-server-arduino","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-arduino\/","title":{"rendered":"ESP32 WebSocket Server: Control Outputs (Arduino IDE)"},"content":{"rendered":"\n<p>In this tutorial you&#8217;ll learn how to build a web server with the ESP32 using WebSocket communication protocol. As an example, we&#8217;ll show you how to build a web page to control the ESP32 outputs remotely. The output state is displayed on the web page and it updates automatically in all clients.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Server-Control-Outputs-Arduino-IDE.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 WebSocket Server Control Outputs Arduino IDE\" class=\"wp-image-99532\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Server-Control-Outputs-Arduino-IDE.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Server-Control-Outputs-Arduino-IDE.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Server-Control-Outputs-Arduino-IDE.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Server-Control-Outputs-Arduino-IDE.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>The ESP32 will be programmed using Arduino IDE and the ESPAsyncWebServer. We also have a similar <a href=\"https:\/\/randomnerdtutorials.com\/esp8266-nodemcu-websocket-server-arduino\/\">WebSocket guide for the ESP8266<\/a>.<\/p>\n\n\n\n<p>If you\u2019ve been following some of our <a href=\"https:\/\/randomnerdtutorials.com\/esp32-async-web-server-espasyncwebserver-library\/\">previous web server projects like this one<\/a>, you may have noticed that if you have several tabs (in the same or on different devices) opened at the same time, the state doesn\u2019t update in all tabs automatically unless you refresh the web page. To solve this issue, we can use WebSocket protocol \u2013 all clients can be notified when a change occurs and update the web page accordingly.<\/p>\n\n\n\n<p class=\"rntbox rntclgray\">This tutorial was based on a project created and documented by one of our readers (St\u00e9phane Calderoni). You can read his excellent <a href=\"https:\/\/m1cr0lab-esp32.github.io\/remote-control-with-websocket\/\" target=\"_blank\" rel=\"noreferrer noopener\">tutorial here<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing WebSocket<\/h2>\n\n\n\n<p>A WebSocket is a persistent connection between a client and a server that allows bidirectional communication between both parties using a TCP connection. This means you can send data from the client to the server and from the server to the client at any given time.&nbsp;<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"727\" height=\"785\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP3-ESP82662-WebSocket-Server-How-it-Works-f.png?resize=727%2C785&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 ESP8266 WebSocket Server How it Works\" class=\"wp-image-99447\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP3-ESP82662-WebSocket-Server-How-it-Works-f.png?w=727&amp;quality=100&amp;strip=all&amp;ssl=1 727w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP3-ESP82662-WebSocket-Server-How-it-Works-f.png?resize=278%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 278w\" sizes=\"(max-width: 727px) 100vw, 727px\" \/><\/figure><\/div>\n\n\n<p>The client establishes a WebSocket connection with the server through a process known as <em>WebSocket handshake<\/em>. The handshake starts with an HTTP request\/response, allowing servers to handle HTTP connections as well as WebSocket connections on the same port. Once the connection is established, the client and the server can send WebSocket data in full duplex mode.<\/p>\n\n\n\n<p>Using the WebSockets protocol, the server (ESP32 board) can send information to the client or to all clients without being requested. This also allows us to send information to the web browser when a change occurs.<\/p>\n\n\n\n<p>This change can be something that happened on the web page (you clicked a button) or something that happened on the ESP32 side like pressing a physical button on a circuit.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Project Overview<\/h2>\n\n\n\n<p>Here&#8217;s the web page we&#8217;ll build for this project.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"924\" height=\"506\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?resize=924%2C506&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 WebSocket Server Toggle Outputs Project Overview\" class=\"wp-image-99459\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?w=924&amp;quality=100&amp;strip=all&amp;ssl=1 924w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?resize=300%2C164&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?resize=768%2C421&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 924px) 100vw, 924px\" \/><\/figure><\/div>\n\n\n<ul class=\"wp-block-list\">\n<li>The ESP32 web server displays a web page with a button to toggle the state of GPIO 2;<\/li>\n\n\n\n<li>For simplicity, we&#8217;re controlling GPIO 2 &#8211; the on-board LED. You can use this example to control any other GPIO;<\/li>\n\n\n\n<li>The interface shows the current GPIO state. Whenever a change occurs on the GPIO state, the interface is updated instantaneously;<\/li>\n\n\n\n<li>The GPIO state is updated automatically in all clients. This means that if you have several web browser tabs opened on the same device or on different devices, they are all updated at the same time.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">How it Works?<\/h3>\n\n\n\n<p>The following image describes what happens when click on the &#8220;Toggle&#8221; button.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"867\" height=\"791\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Update-All-Clients.png?resize=867%2C791&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 WebSocket Web Server Update All Clients How it Works\" class=\"wp-image-99462\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Update-All-Clients.png?w=867&amp;quality=100&amp;strip=all&amp;ssl=1 867w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Update-All-Clients.png?resize=300%2C274&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Update-All-Clients.png?resize=768%2C701&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 867px) 100vw, 867px\" \/><\/figure><\/div>\n\n\n<p>Here&#8217;s what happens when you click on the &#8220;Toggle&#8221; button:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Click on the &#8220;Toggle&#8221; button;<\/li>\n\n\n\n<li>The client (your browser) sends data via WebSocket protocol with the &#8220;toggle&#8221; message;<\/li>\n\n\n\n<li>The ESP32 (server) receives this message, so it knows it should toggle the LED state. If the LED was previously off, turn it on;<\/li>\n\n\n\n<li>Then, it sends data with the new LED state to all clients also through WebSocket protocol;<\/li>\n\n\n\n<li>The clients receive the message and update the led state on the web page accordingly. This allows us to update all clients almost instantaneously when a change happens.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Preparing Arduino IDE<\/h2>\n\n\n\n<p>We\u2019ll program the&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\">ESP32<\/a>&nbsp;board using Arduino IDE, so make sure you have it installed in your Arduino IDE.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-the-esp32-board-in-arduino-ide-windows-instructions\/\">Installing the ESP32 Board in Arduino IDE (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Installing Libraries \u2013 Async Web Server<\/h3>\n\n\n\n<p>We&#8217;ll build the web server using the following libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/ESP32Async\/ESPAsyncWebServer\" target=\"_blank\" rel=\"noopener\" title=\"\">ESPAsyncWebServer&nbsp;<\/a>by ESP32Async<\/li>\n\n\n\n<li><a href=\"https:\/\/github.com\/ESP32Async\/AsyncTCP\" target=\"_blank\" rel=\"noopener\" title=\"\">AsyncTCP<\/a> by ESP32Async<\/li>\n<\/ul>\n\n\n\n<p>You can install these libraries in the Arduino Library Manager. Open the Library Manager by clicking the Library icon at the left sidebar.<\/p>\n\n\n\n<p>Search for <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> and install the <strong>ESPAsyncWebServer by ESP32Async<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"666\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=666%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing ESPAsyncWebServer ESP32 Arduino IDE\" class=\"wp-image-167890\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?w=666&amp;quality=100&amp;strip=all&amp;ssl=1 666w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-ESPAsyncWebServer-Library-ArduinoIDE-2-f.png?resize=300%2C264&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 666px) 100vw, 666px\" \/><\/figure><\/div>\n\n\n<p>Then, install the AsyncTCP library. Search for <span class=\"rnthl rntliteral\">AsyncTCP<\/span> and install the <strong>AsyncTCP by ESP32Async<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"722\" height=\"586\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=722%2C586&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Installing AsyncTCP ESP32 Arduino IDE\" class=\"wp-image-167886\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?w=722&amp;quality=100&amp;strip=all&amp;ssl=1 722w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2024\/06\/Install-AsyncTCP-Library-ArduinoIDE.png?resize=300%2C243&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 722px) 100vw, 722px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Code for ESP32 WebSocket Server<\/h2>\n\n\n\n<p>Copy the following code to your Arduino IDE.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  Complete project details at https:\/\/RandomNerdTutorials.com\/esp32-websocket-server-arduino\/\n  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n*********\/\n\n\/\/ Import required libraries\n#include &lt;WiFi.h&gt;\n#include &lt;AsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;\n\n\/\/ Replace with your network credentials\nconst char* ssid = &quot;REPLACE_WITH_YOUR_SSID&quot;;\nconst char* password = &quot;REPLACE_WITH_YOUR_PASSWORD&quot;;\n\nbool ledState = 0;\nconst int ledPin = 2;\n\n\/\/ Create AsyncWebServer object on port 80\nAsyncWebServer server(80);\nAsyncWebSocket ws(&quot;\/ws&quot;);\n\nconst char index_html[] PROGMEM = R&quot;rawliteral(\n&lt;!DOCTYPE HTML&gt;&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;ESP Web Server&lt;\/title&gt;\n  &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n  &lt;link rel=&quot;icon&quot; href=&quot;data:,&quot;&gt;\n  &lt;style&gt;\n  html {\n    font-family: Arial, Helvetica, sans-serif;\n    text-align: center;\n  }\n  h1 {\n    font-size: 1.8rem;\n    color: white;\n  }\n  h2{\n    font-size: 1.5rem;\n    font-weight: bold;\n    color: #143642;\n  }\n  .topnav {\n    overflow: hidden;\n    background-color: #143642;\n  }\n  body {\n    margin: 0;\n  }\n  .content {\n    padding: 30px;\n    max-width: 600px;\n    margin: 0 auto;\n  }\n  .card {\n    background-color: #F8F7F9;;\n    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);\n    padding-top:10px;\n    padding-bottom:20px;\n  }\n  .button {\n    padding: 15px 50px;\n    font-size: 24px;\n    text-align: center;\n    outline: none;\n    color: #fff;\n    background-color: #0f8b8d;\n    border: none;\n    border-radius: 5px;\n    -webkit-touch-callout: none;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    -webkit-tap-highlight-color: rgba(0,0,0,0);\n   }\n   \/*.button:hover {background-color: #0f8b8d}*\/\n   .button:active {\n     background-color: #0f8b8d;\n     box-shadow: 2 2px #CDCDCD;\n     transform: translateY(2px);\n   }\n   .state {\n     font-size: 1.5rem;\n     color:#8c8c8c;\n     font-weight: bold;\n   }\n  &lt;\/style&gt;\n&lt;title&gt;ESP Web Server&lt;\/title&gt;\n&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n&lt;link rel=&quot;icon&quot; href=&quot;data:,&quot;&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=&quot;topnav&quot;&gt;\n    &lt;h1&gt;ESP WebSocket Server&lt;\/h1&gt;\n  &lt;\/div&gt;\n  &lt;div class=&quot;content&quot;&gt;\n    &lt;div class=&quot;card&quot;&gt;\n      &lt;h2&gt;Output - GPIO 2&lt;\/h2&gt;\n      &lt;p class=&quot;state&quot;&gt;state: &lt;span id=&quot;state&quot;&gt;%STATE%&lt;\/span&gt;&lt;\/p&gt;\n      &lt;p&gt;&lt;button id=&quot;button&quot; class=&quot;button&quot;&gt;Toggle&lt;\/button&gt;&lt;\/p&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;script&gt;\n  var gateway = `ws:\/\/${window.location.hostname}\/ws`;\n  var websocket;\n  window.addEventListener('load', onLoad);\n  function initWebSocket() {\n    console.log('Trying to open a WebSocket connection...');\n    websocket = new WebSocket(gateway);\n    websocket.onopen    = onOpen;\n    websocket.onclose   = onClose;\n    websocket.onmessage = onMessage; \/\/ &lt;-- add this line\n  }\n  function onOpen(event) {\n    console.log('Connection opened');\n  }\n  function onClose(event) {\n    console.log('Connection closed');\n    setTimeout(initWebSocket, 2000);\n  }\n  function onMessage(event) {\n    var state;\n    if (event.data == &quot;1&quot;){\n      state = &quot;ON&quot;;\n    }\n    else{\n      state = &quot;OFF&quot;;\n    }\n    document.getElementById('state').innerHTML = state;\n  }\n  function onLoad(event) {\n    initWebSocket();\n    initButton();\n  }\n  function initButton() {\n    document.getElementById('button').addEventListener('click', toggle);\n  }\n  function toggle(){\n    websocket.send('toggle');\n  }\n&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)rawliteral&quot;;\n\nvoid notifyClients() {\n  ws.textAll(String(ledState));\n}\n\nvoid handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {\n  AwsFrameInfo *info = (AwsFrameInfo*)arg;\n  if (info-&gt;final &amp;&amp; info-&gt;index == 0 &amp;&amp; info-&gt;len == len &amp;&amp; info-&gt;opcode == WS_TEXT) {\n    data[len] = 0;\n    if (strcmp((char*)data, &quot;toggle&quot;) == 0) {\n      ledState = !ledState;\n      notifyClients();\n    }\n  }\n}\n\nvoid onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,\n             void *arg, uint8_t *data, size_t len) {\n  switch (type) {\n    case WS_EVT_CONNECT:\n      Serial.printf(&quot;WebSocket client #%u connected from %s\\n&quot;, client-&gt;id(), client-&gt;remoteIP().toString().c_str());\n      break;\n    case WS_EVT_DISCONNECT:\n      Serial.printf(&quot;WebSocket client #%u disconnected\\n&quot;, client-&gt;id());\n      break;\n    case WS_EVT_DATA:\n      handleWebSocketMessage(arg, data, len);\n      break;\n    case WS_EVT_PONG:\n    case WS_EVT_ERROR:\n      break;\n  }\n}\n\nvoid initWebSocket() {\n  ws.onEvent(onEvent);\n  server.addHandler(&amp;ws);\n}\n\nString processor(const String&amp; var){\n  Serial.println(var);\n  if(var == &quot;STATE&quot;){\n    if (ledState){\n      return &quot;ON&quot;;\n    }\n    else{\n      return &quot;OFF&quot;;\n    }\n  }\n  return String();\n}\n\nvoid setup(){\n  \/\/ Serial port for debugging purposes\n  Serial.begin(115200);\n\n  pinMode(ledPin, OUTPUT);\n  digitalWrite(ledPin, LOW);\n  \n  \/\/ Connect to Wi-Fi\n  WiFi.begin(ssid, password);\n  while (WiFi.status() != WL_CONNECTED) {\n    delay(1000);\n    Serial.println(&quot;Connecting to WiFi..&quot;);\n  }\n\n  \/\/ Print ESP Local IP Address\n  Serial.println(WiFi.localIP());\n\n  initWebSocket();\n\n  \/\/ Route for root \/ web page\n  server.on(&quot;\/&quot;, HTTP_GET, [](AsyncWebServerRequest *request){\n    request-&gt;send(200, &quot;text\/html&quot;, index_html, processor);\n  });\n\n  \/\/ Start server\n  server.begin();\n}\n\nvoid loop() {\n  ws.cleanupClients();\n  digitalWrite(ledPin, ledState);\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP32\/ESP32_WebSocket_Server.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p>Insert your network credentials in the following variables and the code will work straight away.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">How the Code Works<\/h2>\n\n\n\n<p>Continue reading to learn how the code works or skip to the <a href=\"#1\" title=\"#1\">Demonstration<\/a> section.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Importing Libraries<\/h3>\n\n\n\n<p>Import the necessary libraries to build the web server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;WiFi.h&gt;\n#include &lt;AsyncTCP.h&gt;\n#include &lt;ESPAsyncWebServer.h&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Network Credentials<\/h3>\n\n\n\n<p>Insert your network credentials in the following variables:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>const char* ssid = \"REPLACE_WITH_YOUR_SSID\";\nconst char* password = \"REPLACE_WITH_YOUR_PASSWORD\";<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">GPIO Output<\/h3>\n\n\n\n<p>Create a variable called <span class=\"rnthl rntliteral\">ledState<\/span> to hold the GPIO state and a variable called <span class=\"rnthl rntliteral\">ledPin<\/span> that refers to the GPIO you want to control. In this case, we&#8217;ll control the on-board LED (that is connected to <span class=\"rnthl rntclblue\">GPIO 2<\/span>).<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>bool ledState = 0;\nconst int ledPin = 2;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">AsyncWebServer and AsyncWebSocket<\/h3>\n\n\n\n<p>Create an <span class=\"rnthl rntliteral\">AsyncWebServer<\/span> object on port 80.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebServer server(80);<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">ESPAsyncWebServer<\/span> library includes a WebSocket plugin that makes it easy to handle WebSocket connections. Create an <span class=\"rnthl rntliteral\">AsyncWebSocket<\/span> object called <span class=\"rnthl rntliteral\">ws<\/span> to handle the connections on the <span class=\"rnthl rntliteral\">\/ws<\/span> path.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>AsyncWebSocket ws(\"\/ws\");<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Building the Web Page<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">index_html<\/span> variable contains the HTML, CSS and JavaScript needed to build and style the web page and handle client-server interactions using WebSocket protocol. <\/p>\n\n\n\n<p class=\"rntbox rntclgray\"><strong>Note: <\/strong> we&#8217;re placing everything needed to build the web page on the <span class=\"rnthl rntliteral\">index_html<\/span> variable that we use on the Arduino sketch. Note that it may be more practical to have separated HTML, CSS and JavaScript files that then you upload to the ESP32 filesystem and reference them on the code.<\/p>\n\n\n\n<p class=\"rntbox rntclgreen\">Recommended reading: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-spiffs-spi-flash-file-system\/\">ESP32 Web Server using SPIFFS (SPI Flash File System)<\/a><\/p>\n\n\n\n<p>Here&#8217;s the content of the <span class=\"rnthl rntliteral\">index_html<\/span> variable:<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;!DOCTYPE HTML&gt;\n&lt;html&gt;\n&lt;head&gt;\n  &lt;title&gt;ESP Web Server&lt;\/title&gt;\n  &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n  &lt;link rel=\"icon\" href=\"data:,\"&gt;\n  &lt;style&gt;\n  html {\n    font-family: Arial, Helvetica, sans-serif;\n    text-align: center;\n  }\n  h1 {\n    font-size: 1.8rem;\n    color: white;\n  }\n  h2{\n    font-size: 1.5rem;\n    font-weight: bold;\n    color: #143642;\n  }\n  .topnav {\n    overflow: hidden;\n    background-color: #143642;\n  }\n  body {\n    margin: 0;\n  }\n  .content {\n    padding: 30px;\n    max-width: 600px;\n    margin: 0 auto;\n  }\n  .card {\n    background-color: #F8F7F9;;\n    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);\n    padding-top:10px;\n    padding-bottom:20px;\n  }\n  .button {\n    padding: 15px 50px;\n    font-size: 24px;\n    text-align: center;\n    outline: none;\n    color: #fff;\n    background-color: #0f8b8d;\n    border: none;\n    border-radius: 5px;\n    -webkit-touch-callout: none;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    -webkit-tap-highlight-color: rgba(0,0,0,0);\n   }\n   .button:active {\n     background-color: #0f8b8d;\n     box-shadow: 2 2px #CDCDCD;\n     transform: translateY(2px);\n   }\n   .state {\n     font-size: 1.5rem;\n     color:#8c8c8c;\n     font-weight: bold;\n   }\n  &lt;\/style&gt;\n&lt;title&gt;ESP Web Server&lt;\/title&gt;\n&lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n&lt;link rel=\"icon\" href=\"data:,\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n  &lt;div class=\"topnav\"&gt;\n    &lt;h1&gt;ESP WebSocket Server&lt;\/h1&gt;\n  &lt;\/div&gt;\n  &lt;div class=\"content\"&gt;\n    &lt;div class=\"card\"&gt;\n      &lt;h2&gt;Output - GPIO 2&lt;\/h2&gt;\n      &lt;p class=\"state\"&gt;state: &lt;span id=\"state\"&gt;%STATE%&lt;\/span&gt;&lt;\/p&gt;\n      &lt;p&gt;&lt;button id=\"button\" class=\"button\"&gt;Toggle&lt;\/button&gt;&lt;\/p&gt;\n    &lt;\/div&gt;\n  &lt;\/div&gt;\n&lt;script&gt;\n  var gateway = `ws:\/\/${window.location.hostname}\/ws`;\n  var websocket;\n  function initWebSocket() {\n    console.log('Trying to open a WebSocket connection...');\n    websocket = new WebSocket(gateway);\n    websocket.onopen    = onOpen;\n    websocket.onclose   = onClose;\n    websocket.onmessage = onMessage; \/\/ &lt;-- add this line\n  }\n  function onOpen(event) {\n    console.log('Connection opened');\n  }\n\n  function onClose(event) {\n    console.log('Connection closed');\n    setTimeout(initWebSocket, 2000);\n  }\n  function onMessage(event) {\n    var state;\n    if (event.data == \"1\"){\n      state = \"ON\";\n    }\n    else{\n      state = \"OFF\";\n    }\n    document.getElementById('state').innerHTML = state;\n  }\n  window.addEventListener('load', onLoad);\n  function onLoad(event) {\n    initWebSocket();\n    initButton();\n  }\n\n  function initButton() {\n    document.getElementById('button').addEventListener('click', toggle);\n  }\n  function toggle(){\n    websocket.send('toggle');\n  }\n&lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">CSS<\/h3>\n\n\n\n<p>Between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;style&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/style&gt;<\/span><\/span> tags we include the styles to style the web page using CSS. Feel free to change it to make the web page look as you wish. We won&#8217;t explain how the CSS for this web page works because it is not relevant for this WebSocket tutorial.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;style&gt;\n  html {\n    font-family: Arial, Helvetica, sans-serif;\n    text-align: center;\n  }\n  h1 {\n    font-size: 1.8rem;\n    color: white;\n  }\n  h2 {\n    font-size: 1.5rem;\n    font-weight: bold;\n    color: #143642;\n  }\n  .topnav {\n    overflow: hidden;\n    background-color: #143642;\n  }\n  body {\n    margin: 0;\n  }\n  .content {\n    padding: 30px;\n    max-width: 600px;\n    margin: 0 auto;\n  }\n  .card {\n    background-color: #F8F7F9;;\n    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);\n    padding-top:10px;\n    padding-bottom:20px;\n  }\n  .button {\n    padding: 15px 50px;\n    font-size: 24px;\n    text-align: center;\n    outline: none;\n    color: #fff;\n    background-color: #0f8b8d;\n    border: none;\n    border-radius: 5px;\n    -webkit-touch-callout: none;\n    -webkit-user-select: none;\n    -khtml-user-select: none;\n    -moz-user-select: none;\n    -ms-user-select: none;\n    user-select: none;\n    -webkit-tap-highlight-color: rgba(0,0,0,0);\n   }\n   .button:active {\n     background-color: #0f8b8d;\n     box-shadow: 2 2px #CDCDCD;\n     transform: translateY(2px);\n   }\n   .state {\n     font-size: 1.5rem;\n     color:#8c8c8c;\n     font-weight: bold;\n   }\n &lt;\/style&gt;<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">HTML<\/h3>\n\n\n\n<p>Between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;body&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/body&gt;<\/span><\/span> tags we add the web page content that is visible to the user.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;div class=\"topnav\"&gt;\n  &lt;h1&gt;ESP WebSocket Server&lt;\/h1&gt;\n&lt;\/div&gt;\n&lt;div class=\"content\"&gt;\n  &lt;div class=\"card\"&gt;\n    &lt;h2&gt;Output - GPIO 2&lt;\/h2&gt;\n    &lt;p class=\"state\"&gt;state: &lt;span id=\"state\"&gt;%STATE%&lt;\/span&gt;&lt;\/p&gt;\n    &lt;p&gt;&lt;button id=\"button\" class=\"button\"&gt;Toggle&lt;\/button&gt;&lt;\/p&gt;\n  &lt;\/div&gt;\n&lt;\/div&gt;<\/code><\/pre>\n\n\n\n<p>There&#8217;s a heading 1 with the text &#8220;ESP WebSocket Server&#8221;. Feel free to modify that text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;h1&gt;ESP WebSocket Server&lt;\/h1&gt;<\/code><\/pre>\n\n\n\n<p>Then, there&#8217;s a heading 2 with the &#8220;Output &#8211; GPIO 2&#8221; text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>&lt;h2&gt;Output - GPIO 2&lt;\/h2&gt;<\/code><\/pre>\n\n\n\n<p>After that, we have a paragraph that displays the current GPIO state.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p class=\"state\"&gt;state: &lt;span id=\"state\"&gt;%STATE%&lt;\/span&gt;&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">%STATE%<\/span> is a placeholder for the GPIO state. It will be replaced with the current value by the ESP32 at the time of sending the web page. The placeholders on the HTML text should go between <span class=\"rnthl rntliteral\">%<\/span> signs. This means that this <span class=\"rnthl rntliteral\">%STATE%<\/span> text is like a variable that will then be replaced with the actual value.<\/p>\n\n\n\n<p>After sending the web page to the client, the state needs to change dynamically whenever there&#8217;s a change in the GPIO state. We&#8217;ll receive that information via WebSocket protocol. Then, JavaScript handles what to do with the information received to update the state accordingly. To be able to handle that text using JavaScript, the text must have an id that we can reference. In this case the id is <span class=\"rnthl rntliteral\"> state<\/span> (<span class=\"rnthl rntliteral\"> &lt;span id=&#8221;state&#8221;&gt;<\/span>).<\/p>\n\n\n\n<p>Finally, there&#8217;s a paragraph with the button to toggle the GPIO state.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;p&gt;&lt;button id=\"button\" class=\"button\"&gt;Toggle&lt;\/button&gt;&lt;\/p&gt;<\/code><\/pre>\n\n\n\n<p>Note that we&#8217;ve given an id to the button (<span class=\"rnthl rntliteral\">\nid=&#8221;button&#8221;<\/span>).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">JavaScript &#8211; Handling WebSockets<\/h3>\n\n\n\n<p>The JavaScript goes between the <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;script&gt;<\/span><\/span> <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;\/script&gt;<\/span><\/span> tags. It is responsible for initializing a WebSocket connection with the server as soon the web interface is fully loaded in the browser and handling data exchange through WebSockets.<\/p>\n\n\n\n<pre class=\"wp-block-code language-html\"><code>&lt;script&gt;\n  var gateway = `ws:\/\/${window.location.hostname}\/ws`;\n  var websocket;\n  function initWebSocket() {\n    console.log('Trying to open a WebSocket connection...');\n    websocket = new WebSocket(gateway);\n    websocket.onopen    = onOpen;\n    websocket.onclose   = onClose;\n    websocket.onmessage = onMessage; \/\/ &lt;-- add this line\n  }\n  function onOpen(event) {\n    console.log('Connection opened');\n  }\n\n  function onClose(event) {\n    console.log('Connection closed');\n    setTimeout(initWebSocket, 2000);\n  }\n  function onMessage(event) {\n    var state;\n    if (event.data == \"1\"){\n      state = \"ON\";\n    }\n    else{\n      state = \"OFF\";\n    }\n    document.getElementById('state').innerHTML = state;\n  }\n\n  window.addEventListener('load', onLoad);\n\n  function onLoad(event) {\n    initWebSocket();\n    initButton();\n  }\n\n  function initButton() {\n    document.getElementById('button').addEventListener('click', toggle);\n  }\n\n  function toggle(){\n    websocket.send('toggle');\n  }\n&lt;\/script&gt;<\/code><\/pre>\n\n\n\n<p>Let&#8217;s take a look at how this works.<\/p>\n\n\n\n<p>The gateway is the entry point to the WebSocket interface.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>var gateway = `ws:\/\/${window.location.hostname}\/ws`;<\/code><\/pre>\n\n\n\n<p><span class=\"rnthl rntliteral\">window.location.hostname<\/span> gets the current page address (the web server IP address).<\/p>\n\n\n\n<p>Create a new global variable called <span class=\"rnthl rntliteral\">websocket<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>var websocket;<\/code><\/pre>\n\n\n\n<p>Add an event listener that will call the <span class=\"rnthl rntliteral\">onload<\/span> function when the web page loads.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>window.addEventListener('load', onload);<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">onload()<\/span> function calls the <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function to initialize a WebSocket connection with the server and the <span class=\"rnthl rntliteral\">initButton()<\/span> function to add event listeners to the buttons.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onload(event) {\n  initWebSocket();\n  initButton();\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function initializes a WebSocket connection on the gateway defined earlier. We also assign several callback functions for when the WebSocket connection is opened, closed or when a message is received.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function initWebSocket() {\n  console.log('Trying to open a WebSocket connection\u2026');\n  websocket = new WebSocket(gateway);\n  websocket.onopen    = onOpen;\n  websocket.onclose   = onClose;\n  websocket.onmessage = onMessage;\n}<\/code><\/pre>\n\n\n\n<p>When the connection is opened, we simply print a message in the console and send a message saying \u201chi\u201d. The ESP32 receives that message, so we know that the connection was initialized.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onOpen(event) {\n  console.log('Connection opened');\n  websocket.send('hi');\n}<\/code><\/pre>\n\n\n\n<p>If for some reason the web socket connection is closed, we call the <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function again after 2000 milliseconds (2 seconds).<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onClose(event) {\n  console.log('Connection closed');\n  setTimeout(initWebSocket, 2000);\n} <\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">setTimeout()<\/span> method calls a function or evaluates an expression after a specified number of milliseconds.<\/p>\n\n\n\n<p>Finally, we need to handle what happens&nbsp; when we receive a new message. The server (your ESP board) will either send a &#8220;1&#8221; or a &#8220;0&#8221; message. Accordingly to the received message, we want to display an &#8220;ON&#8221; or a &#8220;OFF&#8221; message on the paragraph that displays the state. Remember that <span class=\"rnthl rntliteral\"><span style=\"color: #333399;\">&lt;span&gt;<\/span><\/span> tag with <span class=\"rnthl rntliteral\">id=\u201dstate\u201d<\/span>? We\u2019ll get that element and set its value to ON or OFF.<\/p>\n\n\n\n<pre class=\"wp-block-code language-javascript\"><code>function onMessage(event) {\n  var state;\n  if (event.data == \"1\"){\n    state = \"ON\";\n  }\n  else{\n    state = \"OFF\";\n  }\n  document.getElementById('state').innerHTML = state;\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">initButton()<\/span> function gets the button by its id (<span class=\"rnthl rntliteral\">button<\/span>) and adds an event listener of type <span class=\"rnthl rntliteral\">&#8216;click&#8217;<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>function initButton() {\n  document.getElementById('button').addEventListener('click', toggle);\n}<\/code><\/pre>\n\n\n\n<p>This means that when you click the button, the <span class=\"rnthl rntliteral\">toggle<\/span> function is called.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">toggle<\/span> function sends a message using the WebSocket connection with the <span class=\"rnthl rntliteral\">&#8216;toggle&#8217;<\/span> text.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>function toggle(){\n  websocket.send('toggle');\n}<\/code><\/pre>\n\n\n\n<p>Then, the ESP32 should handle what happens when it receives this message \u2013 toggle the current GPIO state.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Handling WebSockets &#8211; Server<\/h3>\n\n\n\n<p>Previously, you&#8217;ve seen how to handle the WebSocket connection on the client side (browser). Now, let&#8217;s take a look on how to handle it on the server side.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Notify All Clients<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">notifyClients()<\/span> function notifies all clients with a message containing whatever you pass as a argument. In this case, we&#8217;ll want to notify all clients of the current LED state whenever there&#8217;s a change.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void notifyClients() {\n  ws.textAll(String(ledState));\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">AsyncWebSocket<\/span> class provides a <span class=\"rnthl rntliteral\">textAll()<\/span> method for sending the same message to all clients that are connected to the server at the same time.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Handle WebSocket Messages<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">handleWebSocketMessage()<\/span> function is a callback function that will run whenever we receive new data from the clients via WebSocket protocol.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {\n  AwsFrameInfo *info = (AwsFrameInfo*)arg;\n  if (info-&gt;final &amp;&amp; info-&gt;index == 0 &amp;&amp; info-&gt;len == len &amp;&amp; info-&gt;opcode == WS_TEXT) {\n    data&#091;len] = 0;\n    if (strcmp((char*)data, \"toggle\") == 0) {\n      ledState = !ledState;\n      notifyClients();\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<p>If we receive the \u201ctoggle\u201d message, we toggle the value of the <span class=\"rnthl rntliteral\">ledState<\/span> variable. Additionally, we notify all clients by calling the <span class=\"rnthl rntliteral\">notifyClients()<\/span> function. This way, all clients are notified of the change and update the interface accordingly.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (strcmp((char*)data, \"toggle\") == 0) {\n  ledState = !ledState;\n  notifyClients();\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Configure the WebSocket server<\/h4>\n\n\n\n<p>Now we need to configure an event listener to handle the different asynchronous steps of the WebSocket protocol. This event handler can be implemented by defining the <span class=\"rnthl rntliteral\">onEvent()<\/span> as follows:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,\n void *arg, uint8_t *data, size_t len) {\n  switch (type) {\n    case WS_EVT_CONNECT:\n      Serial.printf(\"WebSocket client #%u connected from %s\\n\", client-&gt;id(), client-&gt;remoteIP().toString().c_str());\n      break;\n    case WS_EVT_DISCONNECT:\n      Serial.printf(\"WebSocket client #%u disconnected\\n\", client-&gt;id());\n      break;\n    case WS_EVT_DATA:\n      handleWebSocketMessage(arg, data, len);\n      break;\n    case WS_EVT_PONG:\n    case WS_EVT_ERROR:\n      break;\n  }\n}<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">type<\/span> argument represents the event that occurs. It can take the following values:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntliteral\">WS_EVT_CONNECT<\/span> when a client has logged in;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_DISCONNECT<\/span> when a client has logged out;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_DATA<\/span> when a data packet is received from the client;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_PONG<\/span> in response to a ping request;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">WS_EVT_ERROR<\/span> when an error is received from the client.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Initialize WebSocket<\/h4>\n\n\n\n<p>Finally, the <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function initializes the WebSocket protocol.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void initWebSocket() {\n  ws.onEvent(onEvent);\n  server.addHandler(&amp;ws);\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">processor()<\/h3>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">processor()<\/span> function is responsible for searching for placeholders on the HTML text and replace them with whatever we want before sending the web page to the browser. In our case, we&#8217;ll replace the <span class=\"rnthl rntliteral\">%STATE%<\/span> placeholder with <span class=\"rnthl rntliteral\">ON<\/span> if the <span class=\"rnthl rntliteral\">ledState<\/span> is <span class=\"rnthl rntliteral\">1<\/span>. Otherwise, replace it with <span class=\"rnthl rntliteral\">OFF<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>String processor(const String&amp; var){\n  Serial.println(var);\n  if(var == \"STATE\"){\n    if (ledState){\n      return \"ON\";\n    }\n    else{\n      return \"OFF\";\n    }\n  }\n}<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">setup()<\/h3>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, initialize the Serial Monitor for debugging purposes.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Set up the <span class=\"rnthl rntliteral\">ledPin<\/span> as an <span class=\"rnthl rntliteral\">OUTPUT<\/span> and set it to <span class=\"rnthl rntliteral\">LOW<\/span> when the program first starts.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>pinMode(ledPin, OUTPUT);\ndigitalWrite(ledPin, LOW);<\/code><\/pre>\n\n\n\n<p>Initialize Wi-Fi and print the ESP32 IP address on the Serial Monitor.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>WiFi.begin(ssid, password);\nwhile (WiFi.status() != WL_CONNECTED) {\n  delay(1000);\n  Serial.println(\"Connecting to WiFi..\");\n}\n\n\/\/ Print ESP Local IP Address\nSerial.println(WiFi.localIP());<\/code><\/pre>\n\n\n\n<p>Initialize WebSocket protocol by calling the <span class=\"rnthl rntliteral\">initWebSocket()<\/span> function created previously.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>initWebSocket();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Handle Requests<\/h3>\n\n\n\n<p>Serve the text saved on the <span class=\"rnthl rntliteral\">index_html<\/span> variable when you receive a request on the root <strong>\/<\/strong> URL \u2013 you need to pass the <span class=\"rnthl rntliteral\">processor<\/span> function as an argument to replace the placeholders with the current GPIO state.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.on(\"\/\", HTTP_GET, &#091;](AsyncWebServerRequest *request){\n  request-&gt;send_P(200, \"text\/html\", index_html, processor);\n});<\/code><\/pre>\n\n\n\n<p>Finally, start the server.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>server.begin();<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">loop()<\/h3>\n\n\n\n<p>The LED will be physically controlled on the <span class=\"rnthl rntliteral\">loop()<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void loop() {\n  ws.cleanupClients();\n  digitalWrite(ledPin, ledState);\n}<\/code><\/pre>\n\n\n\n<p>Note that we all call the <span class=\"rnthl rntliteral\">cleanupClients()<\/span> method. Here\u2019s why (explanation from the ESPAsyncWebServer library GitHub page):<\/p>\n\n\n\n<p>Browsers sometimes do not correctly close the WebSocket connection, even when the <span class=\"rnthl rntliteral\">close()<\/span> function is called in JavaScript. This will eventually exhaust the web server\u2019s resources and will cause the server to crash. Periodically calling the <span class=\"rnthl rntliteral\">cleanupClients()<\/span> function from the main <span class=\"rnthl rntliteral\">loop()<\/span>limits the number of clients by closing the oldest client when the maximum number of clients has been exceeded. This can be called every cycle, however, if you wish to use less power, then calling as infrequently as once per second is sufficient.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"1\">Demonstration<\/h2>\n\n\n\n<p>After inserting your network credentials on the <span class=\"rnthl rntliteral\">ssid<\/span> and <span class=\"rnthl rntliteral\">password<\/span> variables, you can upload the code to your board. Don&#8217;t forget to check if you have the right board and COM port selected.<\/p>\n\n\n\n<p>After uploading the code, open the Serial Monitor at a baud rate of 115200 and press the on-board EN\/RST button. The ESP IP address should be printed.<\/p>\n\n\n\n<p>Open a browser on your local network and insert the ESP32 IP address. You should get access to the web page to control the output.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"924\" height=\"506\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?resize=924%2C506&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 WebSocket Server Toggle Outputs Project Overview\" class=\"wp-image-99459\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?w=924&amp;quality=100&amp;strip=all&amp;ssl=1 924w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?resize=300%2C164&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Web-Server-Control-Outputs-Web-Page.png?resize=768%2C421&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 924px) 100vw, 924px\" \/><\/figure><\/div>\n\n\n<p>Click on the button to toggle the LED. You can open several web browser tabs at the same time or access the web server from different devices and the LED state will be update automatically in all clients whenever there&#8217;s a change.<\/p>\n\n\n<div style=\"text-align:center\"><iframe src=\"https:\/\/player.vimeo.com\/video\/465823958?color=ff9933&title=1&byline=0&portrait=0\" width=\"720\" height=\"405\" frameborder=\"0\" webkitallowfullscreen mozallowfullscreen allowfullscreen><\/iframe><\/div><\/br>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial you&#8217;ve learned how to set up a WebSocket server with the ESP32. The WebSocket protocol allows a full duplex communication between the client and the server. After initializing, the server and the client can exchange data at any given time. <\/p>\n\n\n\n<p>This is very useful because the server can send data to the client whenever something happens. For example, you can add a <a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-web-server-physical-button\/\">physical button<\/a> to this setup that when pressed notifies all clients to update the web interface. <\/p>\n\n\n\n<p>In this example, we&#8217;ve shown you how to control one GPIO of the ESP32. You can use this method to control more GPIOs. You can also use the WebSocket protocol to send sensor readings or notifications at any given time.<\/p>\n\n\n\n<p>We hope you&#8217;ve found this tutorial useful. We intend to create more tutorials and examples using the WebSocket protocol. So, stay tuned.<\/p>\n\n\n\n<p>Learn more about the ESP32 with our resources:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/micropython-programming-with-esp32-and-esp8266\/\">MicroPython Programming with ESP32 and ESP8266<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp32\/\">More ESP32 Projects and Guides&#8230;<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial you&#8217;ll learn how to build a web server with the ESP32 using WebSocket communication protocol. As an example, we&#8217;ll show you how to build a web page &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 WebSocket Server: Control Outputs (Arduino IDE)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-websocket-server-arduino\/#more-99437\" aria-label=\"Read more about ESP32 WebSocket Server: Control Outputs (Arduino IDE)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":99532,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-99437","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2020\/10\/ESP32-WebSocket-Server-Control-Outputs-Arduino-IDE.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/99437","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=99437"}],"version-history":[{"count":1,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/99437\/revisions"}],"predecessor-version":[{"id":167947,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/99437\/revisions\/167947"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/99532"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=99437"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=99437"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=99437"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}