ESP32 Arduino: Websocket client

The objective of this post is to explain how to create a simple websocket client on the ESP32, using the Arduino core. The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


Introduction

The objective of this post is to explain how to create a simple websocket client on the ESP32, using the Arduino core. We will use it to contact a remote testing websocket server.

The tests of this ESP32 tutorial were performed using a DFRobot’s ESP-WROOM-32 device integrated in a ESP32 FireBeetle board.


Installing the library

In order for us to not need to worry about the low level details of the websocket protocol, we will use an auxiliary library that will handle those details for us.

You can check the GitHub page of the library here. Please note that this is an ESP8266 library and at the time of writing there was no official support for the ESP32. Nonetheless, with some changes, we will be able to make it run on the ESP32.

Unfortunately, the library is not available at the Arduino IDE libraries manager. Thus, we will need to manually install it.

To do that, we will need to download the source code, which can be obtained at GitHub by clicking the “Clone or download” button on the top of the page, followed by clicking on the “Download ZIP” button. These buttons are highlighted in figure 1.

ESP8266 websocket library download.png

Figure 1 – Downloading the library from GitHub.

Inside the downloaded .zip file should be a folder called ESP8266-Websocket-master. Extract it and rename it to ESP8266-Websocket.

Now we need to manually place our extracted and renamed folder in the same directory of the other Arduino libraries. Usually, the libraries are located on a folder called Arduino on the Documents of the Windows user. For example, in my case, the libraries are located at C:\Users\MyUsername\Documents\Arduino\libraries.

After finding your Arduino libraries folder, simply paste the ESP8266-Websocket folder there.

Before we proceed to the actual coding, we will need to change the name of some functions of the files inside the ESP8266-Websocket folder. If these changes are not performed, when trying to compile the code for the ESP32, we will receive an error related to conflicts caused by the names of those functions.

So, in order to avoid that error, we need to follow the suggestion given in this ESP32 forum thread. As indicated, we need to open the MD5.c and MD5.h files from the ESP8266-Websocket folder and rename the following functions:

  • MD5Init to MD5InitXXX
  • MD5Update to MD5UpdateXXX
  • MD5Final to MD5FinalXXX

Note that the XXX appended at the end could be something else, as long as we did not use the original names, which are conflicting with other definitions. Nonetheless, we need to use the same new names in both the .c and .h files.

Finally, after saving the changes and opening the Arduino IDE, we should be able to find the examples from this library, as shown in figure 2.

ESP32 Arduino Websocket library examples.png

Figure 2 – Examples from the library available on the Arduino IDE.

The code we are going to analyse below for establishing the connection to the server using the ESP32 will be based on the WebSocletClient_Demo, which I really encourage you to check. The examples can also be obtained from the GitHub page here.

 

Global variables and includes

We will start our code by importing some libraries. First, we will need the WiFi.h library, which will allow us to connect to a WiFi network. Besides that, we will need to include the WebSocketClient.h library, so we can access all the functionalities needed for connecting to a server.

#include <WiFi.h>
#include <WebSocketClient.h>

Next we will put the credentials needed to connect to the WiFi network we want to use in two global variables. We will need both the network name (ssid) and the password.

const char* ssid = "YourNetworkName";
const char* password = "YourNetworkPassword";

Later we will need to specify the host to which we will connect, and the URL path to be used. For simplicity, we will use an online echo websocket server which will return to us the content we previously sent. This will allow us to test our client without the need for setting a websocket server ourselves.

So, our server host will be demos.kaazing.com and the URL path will be /echo. You can test this server here.

char path[] = "/echo";
char host[] = "demos.kaazing.com";

We will also need an object of class WebSocketClient, which will expose the functionality needed to interact with the server. Finally, we will need an object of class WiFiClient, which will be used by the WebSocketClient object under the hood.

WebSocketClient webSocketClient;
WiFiClient client;


The setup function

Now we will handle the initializations on the Arduino setup function. As usual, we will start by opening a serial connection, to output the results of our program. Next, we will connect the ESP32 to a WiFi network. You can check how to do it in more detail on this previous post.

Serial.begin(115200);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

delay(5000);

Once connected to the WiFi network, we will establish a TCP connection to the host by calling the connect method of our WiFiClient.

This method receives as first argument a string with the host we are trying to reach (which we previously declared as a global variable) and the port where it is listening. The test server we are using is listening on port 80, which is the default HTTP port.

We also include an error checking for this connection attempt. If it fails, a message will be printed to the serial port, but the program will continue running and eventually fail. We do this for simplicity, since we are on a controlled testing environment. For a resilient program to be used in real case applications, we should include more robust error checking and act accordingly when an error is detected.

if(client.connect(host, 80)) {
    Serial.println("Connected");
}else {
    Serial.println("Connection failed.");
}

Next we need to perform the websocket handshake. This is done by calling the handshake method of the WebSocketClient object we declared before. This method receives as input our WiFiClient and will use it to communicate with the server.

If you want to know more about what happens during this handshake fase, you can take a look at the source code here. But one of the most important parts is that it will send to the server the HTTP request to perform the upgrade of the connection to websocket.

This upgrade is needed since the websocket protocol was developed in such a way that the server can use the same port to talk with both HTTP and websocket clients [1]. Thus, the client needs to specify that it wants to use a websocket.

But before we proceed with the handshake method call, we need to assign to the path and host data members of our WebSocketClient the host and path of the URL that we defined early in global variables.

webSocketClient.path = path;
webSocketClient.host = host;
if (webSocketClient.handshake(client)) {
    Serial.println("Handshake successful");
} else {
    Serial.println("Handshake failed.");
}

You can check the full setup function below.

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  delay(5000);

  if (client.connect(host, 80)) {
    Serial.println("Connected");
  } else {
    Serial.println("Connection failed.");
  }

  webSocketClient.path = path;
  webSocketClient.host = host;
  if (webSocketClient.handshake(client)) {
    Serial.println("Handshake successful");
  } else {
    Serial.println("Handshake failed.");
  }
}


The main loop

Moving the to main loop, we will now handle the sending and receiving of data to the server. We will start by declaring a variable of type String that will be used as a data buffer for the content we will receive from the server.

String data;

Next we will check if the connection to the server is still established. Remember that we previously connected to the server using our WiFiClient object. Thus, we will check the connection by calling its connected method, which takes no arguments and will return true is the connection is still active or false otherwise.

It may seem weird that we are using the WiFiClient at this point after having initialized the WebSocketClient. Nonetheless, we can think of the WebSocketClient as a wrapper on top of the WiFiClient that handles the websocket protocol specific things. So, checking if the connection is still available is lower level functionality, and thus we go directly to the WiFiClient object.

So, if the client is still connected to the server, we will send some data to it. To do it, we simply call the sendData method of our WebSocketClient object, passing as input a string with the content we want to send. This function returns void.

webSocketClient.sendData("Info to be echoed back");

As said before, the server we are reaching will simply echo the data we send to it. Thus, we can then get data from the client and it should match precisely what we have sent before.

So, to get data from the server, we call the getData function and pass as input our string buffer, where the content returned by the server will be placed.

webSocketClient.getData(data);

After that, we can simply print the received data, if its length is greater than 0. You can check the full main loop function below, where this printing is already included. Note that we have also added a small delay before each iteration of the main loop function.

void loop() {
  String data;

  if (client.connected()) {

    webSocketClient.sendData("Info to be echoed back");

    webSocketClient.getData(data);
    if (data.length() > 0) {
      Serial.print("Received data: ");
      Serial.println(data);
    }

  } else {
    Serial.println("Client disconnected.");
  }

  delay(3000);

}


The final code

You can check the final source code below.

#include <WiFi.h>
#include <WebSocketClient.h>

const char* ssid     = "YourNetworkName";
const char* password = "YourNetworkPassword";

char path[] = "/echo";
char host[] = "demos.kaazing.com";

WebSocketClient webSocketClient;
WiFiClient client;

void setup() {
  Serial.begin(115200);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  delay(5000);

  if (client.connect(host, 80)) {
    Serial.println("Connected");
  } else {
    Serial.println("Connection failed.");
  }

  webSocketClient.path = path;
  webSocketClient.host = host;
  if (webSocketClient.handshake(client)) {
    Serial.println("Handshake successful");
  } else {
    Serial.println("Handshake failed.");
  }

}

void loop() {
  String data;

  if (client.connected()) {

    webSocketClient.sendData("Info to be echoed back");

    webSocketClient.getData(data);
    if (data.length() > 0) {
      Serial.print("Received data: ");
      Serial.println(data);
    }

  } else {
    Serial.println("Client disconnected.");
  }

  delay(3000);

}

 

Testing the code

To test the code, simply compile it and upload it to your ESP32. You should get an output similar to figure 1, which shows the message sent to the server being echoed back and printed to the serial console.

Please note that if you did not perform the renaming of the library functions indicated on the “Installing the library” section, you will not be able to compile the code for the ESP32.

ESP32 Arduino Websocket Client

Figure 1 – Output of the program.

 

References

[1] https://tools.ietf.org/html/rfc6455#section-1.3

Advertisements
This entry was posted in ESP32 and tagged , , , , , , , , . Bookmark the permalink.

24 Responses to ESP32 Arduino: Websocket client

  1. Pingback: ESP32 Arduino: Websocket server | techtutorialsx

  2. Pingback: ESP32 Arduino: Websocket server over soft AP | techtutorialsx

  3. Pingback: ESP32 Arduino Websocket server: Receiving and parsing JSON content | techtutorialsx

  4. Pingback: ESP32 Arduino: Websocket client – Arduino Boards News

  5. vindolin says:

    Thanks for the tutorial!

    There’s a little typo in the final code:

    const char* ssid = “YourNetworkName”;
    const char* password = “YourNetworkPassword;

    Missing quotation marks behind YourNetworkPassword

    Liked by 1 person

  6. Aidan Taylor says:

    Is it possible to make a soft client to connect to a soft AP like you have shown in your other tutorials?

    Liked by 1 person

    • Aidan Taylor says:

      I think I am nearly there but I don’t know how to set the host (at the moment I have just set the target IP) and path (I’m trying to use “/” but no idea if this will work) – trying to basically do the same thing as you do with the Python client – at the moment the sketch fails at the handshake stage.

      It’s opens up a lot of exciting possibilities if this can work! Any tips would be very welcome!

      Liked by 1 person

      • antepher says:

        Hi!

        Just to confirm, you are trying to have the ESP32 working as server and the Python program working as client?

        If so, here is a tutorial 🙂
        https://techtutorialsx.com/2017/11/03/esp32-arduino-websocket-server-over-soft-ap/

        Note that the websocket related code in both sides is agnostic of whether you are operating with the ESP32 as soft AP or as station connected to a WiFi network.

        So in theory, any code that works fine with the ESP32 connected to the WiFi network should work the same with the ESP32 operating as soft AP, without needing to change any of that application layer. The only thing you need to change is the initialization of the WiFi interface on the setup function. 🙂

        Let me know if you have succeeded or still need help.

        Best regards,
        Nuno Santos

        Like

        • Aidan Taylor says:

          Hey Nuno, sorry I realise I didn’t ask the question properly, I want to connect an ESP32 client to an ESP32 server using websockets over a soft network.

          I can get the network set up no problem but I can’t get the socket to work. I think that as described in the last comment, the client has the wrong path. The Python client you demonstrated is very minimal (but works!) But I can’t figure out how it manages to point correctly to the ESP32 server – do you have a pair of boards you can test with? I will send you the sketches I have but they are pretty much the examples that you provided!

          Thanks for your replies and awesome tutorials!

          Liked by 1 person

          • antepher says:

            Hi!

            I’ve been doing some tests with two ESP32 boards and I indeed get the same problem of handshake failing, even without using soft AP (both ESP32s were connected to the WiFi network hosted by my router).

            This seems to be library related and not related with the WiFi interface used.

            I’ve activated the debugging on both the socket client and server.

            You can do it by going to the websocketserver.cpp and websocketclient.cpp source files of the library and uncomment the #define DEBUGGING lines at the top.

            From what I’ve seen, the issue seems to be on the server side, which seems to be failing on parsing the headers (it prints the “header mismatch” line when debugging is activated).

            This causes the handshake to fail because the answer is not returned to the client, although it seemed to be a client problem.

            I think it is related with the parsing of the headers that may not be much robust on the ESP32 server side and by some reason the format in which the ESP32 client sends the HTTP upgrade request cannot be correctly processed, whereas the Python client one can.

            Probably, servers implemented in other languages are more robust when parsing this upgrade request and this is most likely why we can use the web socket ESP32 client code to contact other servers, such as the one in this tutorial.

            For instance, not only the code on this tutorial works, but I’ve been also been able to use it to established a websocket connection with a C# .NET core websocket server.

            So, it is may be some missing newline, the order of the headers or some other thing such as a char case problem on some string, in the headers send by the ESP32 web socket client?

            The websocket server parsing code is quite dense and unfortunately I did not have time to go through all of it.

            I’ve caught the request from the Python client using wireshark and this is what it sends to the ESP32 with success on the handshake and further communicatin:

            GET / HTTP/1.1\r\n
            Upgrade: websocket\r\n
            Connection: Upgrade\r\n
            Host: 192.168.1.93\r\n
            Origin: http://192.168.1.93\r\n
            Sec-WebSocket-Key: xJ63aPvnqPIn5fmv3ZcG+A==\r\n
            Sec-WebSocket-Version: 13\r\n
            \r\n

            I’ve tried to hardcode some of the fields on the client library to make sure that it was sending everything in the correct format, but still with no luck so far.

            Unfortunately I cannot dedicate much more time for now to debugging this, but I may be able to get back to it in the future.

            Nonetheless, my suggestion is that you share the issue on the GitHub page of the web socket libraries detailing your code and what you experience.
            https://github.com/morrissinger/ESP8266-Websocket/tree/master

            If you do, please share here, I would really like to follow the evolution of this issue since this will most likely be useful for more readers 🙂

            Another option that you can explore is trying another implementation of the web socket server.

            The async web server libraries for the ESP32 / ESP8266 support websockets:
            https://github.com/me-no-dev/ESPAsyncWebServer

            Unfortunately I haven’t yet had the chance to play with them, but maybe they are more robust and can work with the ESP32 websocket client from this tutorial.

            Furthermore, I think the websockets library used in the tutorial have not been having much attention (the last commit dates from April 2016), so most likely the async web socket server is a better long term choice, since it seems to have quite good support.

            Unfortunately I haven’t yet found an alternative for the websocket client library, but if someone does let us know 🙂

            You’re welcome, I’m very glad you are finding them useful 🙂 Sorry for not being able to help more on this particular issue, but hope this initial investigation can help you getting in the right track 🙂

            Best regards,
            Nuno Santos

            Like

            • Aidan Taylor says:

              Hey no problem, thank you for taking the time to reply in this detail. I think I will spend some more time with asyncwebserver library next – I will share details if I get some good results!

              Liked by 1 person

              • antepher says:

                You’re welcome 🙂

                Looking forward to know if you have succeeded, it will be useful to know if the asyncwebserver library works well with websockets!

                Best regards,
                Nuno Santos

                Like

    • antepher says:

      Hi!

      Yes! Here is a tutorial of the ESP32 operating as websocket server and a Python client connecting to it, all over soft.

      The “websocket code” should be agnostic regarding if the ESP32 is operating as soft AP or is connected to WiFi.

      Let me know if you have the chance to test it and if it works for you 🙂

      Best regards,
      Nuno Santos

      Like

  7. DocM says:

    There are in the c code some more init, update and final to rename. Perhaps I have another newer version! Otherwise it wont work

    Liked by 2 people

  8. I need a client libray for WSS. Is there any websocket library for ESP32 ?
    Thanks

    Liked by 1 person

    • antepher says:

      Hi!

      Unfortunately I haven’t yet found any that supports wss.

      Let me know if you happen to find any working one, it would be very useful 🙂

      Best regards,
      Nuno Santos

      Like

  9. Pingback: ESP32 Socket Server: Connecting from a Putty socket Client | techtutorialsx

  10. Ayoub Elmouddene says:

    Hi,
    Your tutorial saved me after one week of research so thank you million times.
    Although, I have an issue. I want so send float data instead of string and receive it back, but, I can’t seem to find any function that send a float type.
    Thank you.

    Liked by 1 person

    • antepher says:

      Hi! You are welcome, I’m very happy to know the tutorial helped you 🙂

      Unfortunately I think the library only has functions to send data as a string, at least I have also not found any other option.

      One easy way to handle different types of data is using JSON to serialize your content and send it over the websocket.

      Then on the other side you can simply deserialize the content and get the original data types.

      Not sure if it is an option for your application, but I think for this library it is the best approach.

      I have an example tutorial for using json and the ESP32 acting as a websocket server, but it should be easy to adapt for a client:
      https://techtutorialsx.com/2017/11/05/esp32-arduino-websocket-server-receiving-and-parsing-json-content/

      Hope this helps 🙂

      Best regards,
      Nuno Santos

      Like

  11. Pingback: ESP8266 Arduino: Socket Client | techtutorialsx

  12. Pingback: ESP8266 Arduino: Socket Server | techtutorialsx

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s