WebSockets on the ESP32

Sending data between an embedded device and something like an PC sometime can be frustrating. Usually communication standards like UART/RS232 are used to establish an easy to use connection, while other standards like USB are difficult to handle and tend to be very complicated. I was playing with the ESP32 and wrote a basic WebSocket server. The advantage of websockets is the flexibility, combined with high data rates, low latency and the availability of webSocket client modules as well in modern browsers but also in .net or java.

This software is a PROTOTYPE version and is not designed or intended for use in production, especially not for safety-critical applications! The user represents and warrants that it will NOT use or redistribute the Software for such purposes. This prototype is for research purposes only. This software is provided "AS IS," without a warranty of any kind.

WebSocket?

WebSockets are similar to HTTP connections. When you request a webpage from a server, a TCP connection is established and closed as soon as the content has been transferred from the server to the client (e.g. browser). The difference between HTTP and websockets is that a websocket connection remains established and bidirectional communication becomes possible. The advantage over e.g. AJAX is, that there is no overhead for the handshake, as the connection is already open and thus the latency is lower.

Learn more about WebSockets:

WebSocket Handshake on the ESP32

The first thing we need is a WebSocket Task. It is very similar to a HTTP Server but might listen to another port. However, you also can listen to port 80 for websocket connections but then need to distinguish between HTTP and websocket request. I choose to listen to a dedicated port, in order to reduce complexity.

This snippet creates a new TCP listener at port 9998. If we receive a connection request,  ws_server_netconn_serve is called.

The WebSocket Handshake is a little tricky 🙁 .The client (e.g. a browser) sends a request which looks like this:

The server has to read Sec-WebSocket-Key, concatinate the magic string "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" to it, take the SHA1 of it, and return the base64 encoded result to the client:

Yep... I know... but no worries, we will go trough it step by step. Maybe its now time to get a coffee or a bottle of wine 😉

We need the following strings:

First, there is the Argument we are looking for, our magic string and finally the handshake response with a wildcard for our calculated hash.

Next we need to allocate some memory for the SHA1 input and the SHA1 result

We copy the static "private" key into the SHA1 input and try to get the parameter start from the request:

If we have found the Sec-Key, we load in into the SHA1 input, get the hash from the ESP32 SHA1 engine and base64 encoding:

Now that we have the SHA1 result, we can send the handshake response:

The connection is now open and we can wait for incoming messages:

 

Receive WebSocket frames

The format of Websocket frames can be found here. I created a structure to help "parsing" WebSocket frames:

For my application, a frame size with 2^7 bytes is sufficient, thus only frames with a length <126 are handled.

The received framed will be casted to the frame header structure. We check if the client wants to close the connection and then we extract the payload mask and unmask the payload. Once we have the payload, I call a function  WS_process_in_data , which (in this example) will loop back the Frame

Send WebSocket frames

Once the connection is established, I save the connection reference in a static variable

In order to send WebSocket Frames, we simply need to send a WebSocket Header, followed by the (luckily no masking etc here) payload. Again, this demo is limited to 2^7 bytes, but can be easily extended.

An example project with a WebSocket receive task can be found here:

GitHub

Download

3 thoughts on “WebSockets on the ESP32

  1. timmy

    Hello Thomas, Thanks for this detailed guide. But I really lost myself in concepts of websocket communication and library exceptions with the GNU or kinda C90 C89 standarts. 🙂

    Can you tell me what IDE you are using to develop for ESP32 examples you publish ;What compiler mingw or any other gnu you are using for it ?
    I was using Arduino ide with https://github.com/espressif/arduino-esp32 .
    i downloaded your example project but cant figure out what i need to do to make it run on arduino ide.

    Esp32 and microcontroller programming is so new for me. Thanks again. 🙂

  2. timmy

    Hey thomas,
    I managed to set the environment up for ESP-IDF development with eclipse and for a second setup ATOM IDE with platformIO..
    I build your example project on github. and trying to make it work. but when i send a request from chrom browser for the first time, i only getting these messages from serial monitor .
    W (54134) wifi: noTIM!!
    I (54134) wifi: n:11 0, o:11 2, ap:255 255, sta:11 0, prof:1
    I (54254) wifi: n:11 2, o:11 0, ap:255 255, sta:11 2, prof:1
    W (54904) wifi: noTIM!!
    I (54904) wifi: n:11 0, o:11 2, ap:255 255, sta:11 0, prof:1
    I (54964) wifi: n:11 2, o:11 0, ap:255 255, sta:11 2, prof:1

    Cant find out what is the problem.
    Thanks.

  3. timmy

    Hi Thomas,
    It was my bad. nothing was wrong. just i have writtin another c# aplication to test the ws . "wrong port" was the key for it 🙂
    Thanks for sample . Do you mind adding it a softAP mode ?

    Best Regards.

Leave a Reply

Thomas

About Thomas Barth

Thomas Barth, born 1986, is a german teaching fellow and Ph.D. student. He studied electrical engineering in Darmstadt, Frankfurt and Helsinki and worked 7 years in industry automation before he switched to embedded systems and microelectronics. To read more about him, click here.