ESP32 Web Server using WebSocket

Esp32 9 Th10 2021

The ESP32 controller is programmed as a WebSocket server to establish real-time communication with a client browser.

Why WebSocket

  • Real-time web application: Real-time web application uses a web socket to show the data at the client end, which is continuously being sent by the backend server. In WebSocket, data is continuously pushed/transmitted into the same connection which is already open, that is why web socket is faster and improves the application performance. For e.g. in the trading website or bitcoin trading, that is the most volatile thing which is happening over there, for displaying the price fluctuation and movement data is continuously pushed by the backend server to the client end by using the web socket channel.
  • Gaming application: In a Gaming application, you might focus on that, data is continuously receiving by the server and without refreshing the UI, it will take effect on the screen, UI gets automatically refreshed without even establishing the new connection, so it is very helpful in a Gaming application.
  • Chat application: Chat application uses WebSocket to stablish the connection only once for exchange, publishing and broadcasting the message among the subscriber. it reuses the same WebSocket connection, for sending and receiving the message and one to one message transfer.

What is WebSocket

WebSocket is a transport protocol defined by a persistent, bidirectional communication channel between server and client that takes place over a single TCP socket connection.

It was designed to overcome the limitations of HTTP's basic request/response mechanism (i.e. constant opening and closing of connections and header overhead), which is not suitable for real time applications that rely on sustained user interaction or continuously streamed updates.

How WebSocket Works

To initiate a WebSocket connection, the client and server must negotiate an Upgrade handshake from HTTP, and from that point onwards, asynchronous WebSocket rules apply. Specifically, bulky HTTP headers are replaced with message frames only a few bytes in size, and both the server and client can simultaneously send new data without the other asking for it.

ESP32 Web Server using WebSocket

Source Code

Arduino File

//==================================
//ESP32 WebSocket Server: Toggle LED
//by: Ulas Dikme
//==================================
#include <WiFi.h>
#include <WebServer.h>
#include <WebSocketsServer.h>
//-----------------------------------------------
const char* ssid = "network name";
const char* password = "password";
//-----------------------------------------------
#define LED 2
//-----------------------------------------------
WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);
//-----------------------------------------------
boolean LEDonoff=false; String JSONtxt;
//-----------------------------------------------
#include "html_page.h"
#include "functions.h"
//====================================================================
void setup()
{
  Serial.begin(115200); pinMode(LED, OUTPUT);
  //-----------------------------------------------
  WiFi.begin(ssid, password);
  while(WiFi.status() != WL_CONNECTED){Serial.print("."); delay(500);}
  WiFi.mode(WIFI_STA);
  Serial.println();
  Serial.print("Local IP: ");
  Serial.println(WiFi.localIP());
  //-----------------------------------------------
  server.on("/", webpage);
  //-----------------------------------------------
  server.begin(); webSocket.begin();
  webSocket.onEvent(webSocketEvent);
}
//====================================================================
void loop()
{
  webSocket.loop(); server.handleClient();
  //-----------------------------------------------
  if(LEDonoff == false) digitalWrite(LED, LOW);
  else digitalWrite(LED, HIGH);
  //-----------------------------------------------
  String LEDstatus = "OFF";
  if(LEDonoff == true) LEDstatus = "ON";
  JSONtxt = "{\"LEDonoff\":\""+LEDstatus+"\"}";
  webSocket.broadcastTXT(JSONtxt);
}

Header file "functions.h"

//=======================================
//handle function: send webpage to client
//=======================================
void webpage()
{
  server.send(200,"text/html", webpageCode);
}
//=====================================================
//function process event: new data received from client
//=====================================================
void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t welength)
{
  String payloadString = (const char *)payload;
  Serial.print("payloadString= ");
  Serial.println(payloadString);

  if(type == WStype_TEXT) //receive text from client
  {
    byte separator=payloadString.indexOf('=');
    String var = payloadString.substring(0,separator);
    Serial.print("var= ");
    Serial.println(var);
    String val = payloadString.substring(separator+1);
    Serial.print("val= ");
    Serial.println(val);
    Serial.println(" ");

    if(var == "LEDonoff")
    {
      LEDonoff = false;
      if(val == "ON") LEDonoff = true;
    }
  }
}

Header file "html_page.h"

=====================
//HTML code for webpage
//=====================
const char webpageCode[] PROGMEM =
R"=====(
<!DOCTYPE HTML>
<html>
<head>
  <title>ESP32 Web Server</title>
</head>
<!-------------------------------C S S------------------------------>
<style>
  #btn
  {
    display: inline-block;
    text-decoration: none;
    background: #8CD460;
    color: rgba(255,255,255, 0.80);
    font-weight: bold;
    font: 60px arial, sans-serif;
    width: 150px;
    height: 150px;
    line-height: 150px;
    border-radius: 50%;
    text-align: center;
    vertical-align: middle;
    overflow: hidden;
    box-shadow: 0px 0px 0px 8px #8CD460;
    border: solid 2px rgba(255,255,255, 0.47);
    transition: 0.5s;
  }
  body {text-align:center; font-family:"Calibri"; background-color:rgba(0, 3, 8, 0.26)}
  h1   {color: rgba(0, 0, 255, 0.87); font-size: 50px;}
</style>
<!------------------------------H T M L----------------------------->
<body>
   <h1>E S P 3 2<br>WebSocket Server</h1>
   <a href="#" id="btn" ONCLICK='button()'> </a>
<!-----------------------------JavaScript--------------------------->
  <script>
     InitWebSocket()
     function InitWebSocket()
     {
       websock = new WebSocket('ws://'+window.location.hostname+':81/'); 
       websock.onmessage = function(evt)
       {
          JSONobj = JSON.parse(evt.data);
          document.getElementById('btn').innerHTML = JSONobj.LEDonoff;
          if(JSONobj.LEDonoff == 'ON')
          {
            document.getElementById('btn').style.background='#FF0000';
            document.getElementById('btn').style["boxShadow"] = "0px 0px 0px 8px #FF0000";
          }
          else
          {
            document.getElementById('btn').style.background='#111111';
            document.getElementById('btn').style["boxShadow"] = "0px 0px 0px 8px #111111";
          }
       }
     }
     //-------------------------------------------------------------
     function button()
     {
        btn = 'LEDonoff=ON';
        if(document.getElementById('btn').innerHTML == 'ON')
        {
          btn = 'LEDonoff=OFF';
        }
        websock.send(btn);
     }
  </script>
</body>
</html>
)=====";

Tags

Tony Phạm

Là một người thích vọc vạch và tò mò với tất cả các lĩnh vực từ khoa học tự nhiên, lập trình, thiết kế đến ... triết học. Luôn mong muốn chia sẻ những điều thú vị mà bản thân khám phá được.