ESP32 Arduino WebSocket Server

WebSockets is an incredibly useful protocol that lets you send data to and from a server over TCP without the need for HTTP. Importantly, it lets you push data from the server to a client (e.g. a browser) without needing to make a request. This can be very handy for things like browser-based multiplayer games. I wanted to play around with it for embedded systems to see if I could get low-latency communication between a microcontroller and a computer. Specifically, I wanted the microcontroller to act as a server that supported a connection from a browser (e.g. PC or phone).

Thankfully, GitHub user Links2004 has created an Arduino WebSockets library, which makes testing WebSockets easy. To show it in action, I put together a video where I test the WebSockets library by creating an echo server and test it with a Python script.

For this test, I’m using an Adafruit HUZZAH32 Feather Board, but any ESP32 supported by the Arduino IDE should work. In the Arduino IDE, navigate to File > Preferences and add the following URL to Additional Boards Manager URLs:
https://dl.espressif.com/dl/package_esp32_index.json
Then in Tools > Board > Boards Manager, search for and install the esp32 package by Espressif Systems. Go to Sketch > Include Library > Manage Library. Search for and install the websockets library by Markus Sattler (Links2004). In a new Arduino sketch, enter the code below. Change the ssid  and password variables to match your WiFi network credentials.
#include <WiFi.h>
#include <WebSocketsServer.h>

// Constants
const char* ssid = "MySSID";
const char* password = "MyPassword";

// Globals
WebSocketsServer webSocket = WebSocketsServer(80);

// Called when receiving any WebSocket message
void onWebSocketEvent(uint8_t num,
                      WStype_t type,
                      uint8_t * payload,
                      size_t length) {

  // Figure out the type of WebSocket event
  switch(type) {

    // Client has disconnected
    case WStype_DISCONNECTED:
      Serial.printf("[%u] Disconnected!\n", num);
      break;

    // New client has connected
    case WStype_CONNECTED:
      {
        IPAddress ip = webSocket.remoteIP(num);
        Serial.printf("[%u] Connection from ", num);
        Serial.println(ip.toString());
      }
      break;

    // Echo text message back to client
    case WStype_TEXT:
      Serial.printf("[%u] Text: %s\n", num, payload);
      webSocket.sendTXT(num, payload);
      break;

    // For everything else: do nothing
    case WStype_BIN:
    case WStype_ERROR:
    case WStype_FRAGMENT_TEXT_START:
    case WStype_FRAGMENT_BIN_START:
    case WStype_FRAGMENT:
    case WStype_FRAGMENT_FIN:
    default:
      break;
  }
}

void setup() {

  // Start Serial port
  Serial.begin(115200);

  // Connect to access point
  Serial.println("Connecting");
  WiFi.begin(ssid, password);
  while ( WiFi.status() != WL_CONNECTED ) {
    delay(500);
    Serial.print(".");
  }

  // Print our IP address
  Serial.println("Connected!");
  Serial.print("My IP address: ");
  Serial.println(WiFi.localIP());

  // Start WebSocket server and assign callback
  webSocket.begin();
  webSocket.onEvent(onWebSocketEvent);
}

void loop() {

  // Look for and handle WebSocket data
  webSocket.loop();
}

Select your ESP32 board and COM port. Upload the program, and open a serial monitor. Your ESP32 should connect to your wireless network and print out its IP address. Copy down the IP address, as we’ll need it in the next part.

Arduino WebSocket Server serial output

Make sure you have Python installed on your computer. Open a terminal and enter the following command:

pip install websocket-client

This will install a WebSocket client package that we can use to test our server with. In a new text document, enter the following Python code (change the IP address to match the address obtained from the Arduino serial console):

import websocket

# Connect to WebSocket server
ws = websocket.WebSocket()
ws.connect("ws://192.168.1.123")
print("Connected to WebSocket server")

# Ask the user for some input and transmit it
str = input("Say something: ")
ws.send(str)

# Wait for server to respond and print it
result = ws.recv()
print("Received: " + result)

# Gracefully close WebSocket connection
ws.close()

Make sure your computer is on the same network as your ESP32. With the WebSocket server still running, run your Python script:

python ws_test.py

This should connect to the WebSocket server and ask for some input. Enter in some text, press enter, and you should see your message echoed back to you.

WebSocket test Python script

If you look at the Arduino serial console, you should see that a WebSocket client has connected, sent a message, and then disconnected.

Arduino ESP32 WebSockets test server

I’m hoping to use WebSockets as a way to transmit data between a browser and an Arduino in an upcoming project. Hopefully, the latency is low enough that controls and displays can be updated quickly enough (for human needs).

[Update 9/9/2019] I’ve taken this a step further and turned the ESP32 into a full web server while still using WebSockets to control hardware. You can see the tutorial for that here: How to Create a Web Server (with WebSockets) Using an ESP32 in Arduino

32 thoughts on “Arduino WebSocket Server Using an ESP32

  1. Civilduino on November 4, 2018 at 10:45 am Reply

    Great tutorial and love your work! I am starting to learn about web sockets. I will like to use them to send the data of my temperature sensor live to my phone in a simple webpage. Will you make a following tutorial with a webpage? Thanks!

    1. ShawnHymel on November 5, 2018 at 8:02 pm Reply

      Thank you! I’m working on exactly that: the ESP32 hosts a webpage that allows for direct control of connected hardware 🙂

  2. Rafael Nunes on February 28, 2019 at 8:09 am Reply

    Really very good !
    Could you give us an example where we have web pages hosted on SPPIF of ESP32 and HTML files containing SVG graphics? These graphic elements would do both reading and recording on digital, analog and DAC ports.

    It would be something like this, with your didactics the material would look much better 🙂

    https://www.youtube.com/watch?v=PWacko54V-c

    1. ShawnHymel on March 1, 2019 at 6:00 pm Reply

      Whoa, that’s really cool. I haven’t been working with the ESP32 for a while (this project is on hold as I make something else with the ATtiny85), but I’ll definitely keep the SVG hosting idea in mind. Thank you!

    2. ShawnHymel on March 4, 2019 at 12:52 am Reply

      I just uploaded this example to a gist: https://gist.github.com/ShawnHymel/3d124f79aee95fb274876f491a91dcf4 No full write-up yet, but it does use SPIFFS to load an HTML file to the ESP32, which acts as an access point. Hopefully, it can work as a starting point for you.

      1. wim verlinden on May 5, 2019 at 10:38 am Reply

        Hi, interesting example but where is the css file?

        1. ShawnHymel on May 5, 2019 at 4:58 pm Reply

          CSS is not needed for basic HTML (you only need it if you want to organize your page or site’s formatting).

  3. Danish Vasta on March 2, 2019 at 12:33 pm Reply

    Awesome,
    How can i create an HTML5 webpage & append the received data ?

    1. ShawnHymel on March 3, 2019 at 10:27 pm Reply

      I have not gotten around to doing a write-up for it, but here is an example of using the ESP32 as an access point to host a simple webpage (index.html): https://gist.github.com/ShawnHymel/3d124f79aee95fb274876f491a91dcf4. Note that you will need to install SPIFFS and use it to upload index.html to the filesystem on the ESP32.

      I know it’s not HTML5 nor appending data, but it should hopefully work as a starting point for you. You can use WebSockets to send data from the Arduino to the browser and update variables in the HTML, which append to a log, update a graph, etc.

  4. Clinton on April 2, 2019 at 6:50 pm Reply

    How do i make my server to stay connected. Why does it disconnect after receiving a text! Pls help

    1. ShawnHymel on April 4, 2019 at 9:26 pm Reply

      The WebSocket should stay connected (in theory) so long as you don’t call ws.close() from the client or exit the Python program. If you put

      # Ask the user for some input and transmit it
      str = input("Say something: ")
      ws.send(str)
      result = ws.recv()
      print("Received: " + result)

      in a loop, does the websocket stay open?

  5. daniel on July 4, 2019 at 11:33 pm Reply

    Hi Shawn,

    Could you please update the sketch example from the top the page? It doesn’t compile with WebSocket Library version 2.1.4 :(.

    T

    1. ShawnHymel on July 8, 2019 at 5:10 pm Reply

      It worked for me with 2.1.4. What error are you getting?

  6. Felix on July 7, 2019 at 8:29 am Reply

    Hi, I love this vid!
    Unfortunately, i have been working with a D1 and could not get it running.
    (error compiling for the d1)
    Do you have an idea how to get that running on a D1?
    Anyway, a esp32 is ordered;-)

    Keep going!

    1. ShawnHymel on July 8, 2019 at 5:12 pm Reply

      I don’t have any experience with the D1, sorry! Can you get it running a simple blink program first?

  7. Ludo Kustermans on July 10, 2019 at 11:58 am Reply

    Hi,
    Have implemented your files, but it seems they are not complete..
    I get following error :
    ws = websocket.WebSocket()
    TypeError: __init__() takes exactly 4 arguments (1 given)
    How can this be solved ?
    best regards
    Ludo

    1. ShawnHymel on July 16, 2019 at 5:36 pm Reply

      I just checked–it still works for me. What version of Python and websockets are you using? I’m on Python 3.7.1 and WebSocket 0.56.0.

    2. Pete on August 25, 2019 at 6:25 pm Reply

      Yes, same here, running Linux
      corv-pete: cat ./wh3080_recvr.py
      import websocket

      # Connect to WebSocket server
      ws = websocket.WebSocket()
      ws.connect(“ws://192.168.1.123”)
      print(“Connected to WebSocket server”)

      # Ask the user for some input and transmit it
      str = input(“Say something: “)
      ws.send(str)

      # Wait for server to respond and print it
      result = ws.recv()
      print(“Received: ” + result)

      # Gracefully close WebSocket connection
      ws.close()
      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      corv-pete: python ./wh3080_recvr.py <<<<<< —- python 2.7.13
      Traceback (most recent call last):
      File "./wh3080_recvr.py", line 4, in
      ws = websocket.WebSocket()
      TypeError: __init__() takes exactly 4 arguments (1 given)

      or:
      corv-pete: python3 ./wh3080_recvr.py <<<—— note python3
      Traceback (most recent call last):
      File "./wh3080_recvr.py", line 4, in
      ws = websocket.WebSocket()
      TypeError: __init__() missing 3 required positional arguments: ‘environ’, ‘socket’, and ‘rfile’

      1. ShawnHymel on August 26, 2019 at 4:14 pm Reply

        What version of WebSockets are you using? It worked for me with v0.56.0.

    3. Steve on October 30, 2019 at 8:31 pm Reply

      I had this same issue with a different project and found that I had the wrong websocket library installed. I had used pip install websocket, which didn’t work with code similar to this example. I uninstalled it and then used pip install websocket-client which is the same as instructed in this post, and it worked. Hopefully this helps someone.

      1. ShawnHymel on October 30, 2019 at 11:10 pm Reply

        Good to know, thank you!

  8. don on July 29, 2019 at 4:39 am Reply

    Hi Shawn,

    Thanks for the great tutorial. Can you please help me send sensor data other than the simple text response, like digital or analog inputs, etc.

    1. ShawnHymel on July 29, 2019 at 7:58 pm Reply

      I’m not sure what kind of sensor data you are planning to use. Most data is sent in string or binary form, so it’s on you to program the receiver to interpret, store, or display that data.

  9. dede64 on August 30, 2019 at 9:22 pm Reply

    HI, thanks for the tutorial, can I ask how to connect to ESP32 websocket server outside the local nettwork?

    1. ShawnHymel on September 2, 2019 at 5:40 pm Reply

      It should work outside of your network, but you’ll need to use the right IP address (your public IP address) and set up your router to do port forwarding to get to the correct device within your local network.

  10. fra on April 10, 2020 at 9:01 am Reply
    1. ShawnHymel on April 12, 2020 at 2:15 pm Reply

      Awesome, thanks for sharing that!

  11. Barry on February 25, 2021 at 1:00 am Reply

    Hi Shawn – I’ve got this demo sketch to compile and load. I can conn to the AP and in my browser goto 192.168.4.1 but only get a white screen on my Android phone.
    There is a /data/index.html file.

    In Ard IDE, Tools, ESP Data Upload I get:
    esptool.py v2.6
    Serial port COM4
    Traceback (most recent call last):
    File “esptool.py”, line 2959, in
    File “esptool.py”, line 2952, in _main
    File “esptool.py”, line 2652, in main
    File “esptool.py”, line 222, in __init__
    File “site-packages\serial\__init__.py”, line 88, in serial_for_url
    File “site-packages\serial\serialwin32.py”, line 62, in open
    serial.serialutil.SerialException: could not open port ‘COM4’: WindowsError(5, ‘Access is denied.’)
    Failed to execute script esptool
    SPIFFS Upload failed!

    My target is a ESP32 Dev module which requires that I exerecise the Boot and EN buttons to upload, but that doesn’t seem to work for SPIFFS.
    I did try a SPIFFS test prog from another site and it ran ok, but I’ve still got something screwed up.
    Thanks
    Barry

  12. Barry on February 25, 2021 at 1:12 am Reply

    additional:

    The IDE Serial Monitor shows:
    [192.168.4.2] HTTP GET request of /
    [192.168.4.2] HTTP GET request of /
    [192.168.4.2] HTTP GET request of /index.html
    [192.168.4.2] HTTP GET request of /index.html

    My phone shows “Not found”

  13. Barry on February 25, 2021 at 1:16 am Reply

    SOLVED – I had to close the Serial Monitor and then it uploaded!!!

  14. Wael Al Sayegh on March 5, 2022 at 7:34 pm Reply

    HI SHAWN!!
    Thank you for this tutorial!
    I just want to ask if you updated the part of a simple webpage that receives and sends data to the esp. I am working on that but I am facing some problems in the Java Script (I:e how to receive and save data from the webpage to esp (on click)).

  15. Kurisu on February 13, 2024 at 2:26 am Reply

    this causes my esp to just keep boot looping

Leave a Comment

Your email address will not be published. Marked fields are required.