ArticlesEmbedded C & MCUIoT

All About ESP32 – Part 3

TCP and HTTP via WiFi

So far, the series has covered a good background to start digging for more in-depth details about ESP32. After the last part which was an introduction to the ESP-IDF WiFi driver, including application to scan for available APs and connect to one. This time, we will employee the established WiFi connection to make an HTTP request and TCP connection. However, a major part of programming WiFi as you’re going to see is related to socket programming in C using LwIP stack. To make life simpler, Espressif introduced a library to handle HTTP requests as a client in ESP-IDF.

 

LwIP Stack

 

ESP32 uses LwIP stack, thus the first way to make an HTTP connection or even pure TCP/UDP data transaction is to use LwIP API directly, where one of the LwIP ‘s application API layers is socket API which compatible with standard BSD-sockets. BSD socket programming in C is a broader topic, and this article will show the basics only.

I will borrow some parts of a very handy explanation of TCP/IP socket programming in C from BinaryTides website. The BinaryTides defined Sockets as “virtual” endpoints of any kind of network communications done between 2 hosts over a network. For example, when you type www.google.com in your web browser, it opens a socket and connects to google.com to fetch the page and show it to you. So the first thing to do is socket creation using socket() API method :

  • domain argument selects the protocol family used for communication (.i.e AF_INET6  for IPv6 Internet protocols).
  • type argument could take SOCK_STREAM for TCP  or SOCK_DGRAM for UDP.
  • protocol argument according to Linux documentation: “specifies a particular protocol to be used with the socket. Normally only a single protocol exists to support a particular socket type within a given protocol family, in which case protocol can be specified as 0”.

Calling this function returns a number which is a file descriptor for the new socket and will be used in other functions.

So the first part of socket programming is:

 

Server Side

 

Sockets need to be bound to an address and a port. The address could be a specific IP or not specific IP using INADDR_ANY option. The address and port can be specified using a struct sockaddr_in variable type.

The sockaddr_in struct from LwIP is:

The final initialization step to do is to call listen() API method to start listening for connections on the selected socket. This method takes 2 arguments, the first one is the socket descriptor and the second one specifies the maximum number of queued connections.

Later, the accept() API method checks the queue for pending connections related to the socket with the specified file descriptor and returns a new file descriptor referring to that socket. The argument addr is a pointer to a sockaddr structure. This structure is filled in with the address of the peer socket.

You may later read or write data from/to that connection using read() or write() functions.

Putting all together:

 

Client Side

 

If the socket is used to connect to a remote address (.i.e to connect to a website), the connect() API method is then used instead of bind() with the same arguments with no need to call listen() nor accept(). The following diagram associated with an answer on Stackoverflow clarify it:
ESP32 BSD Socket Creation

 

Software Access Point (SoftAP)

 

Here is another thing we need in this part’s applications, where one of the application will make ESP32 as an AP and a client will make a TCP connection via telnet/PuTTY.

To configure the ESP32 as an AP, the same functions used last time to access to an AP as a station will be used this time only with another wifi_config_t variable:

Where wifi_config_t has 2 parts:

Last time we used sta part from wifi_config_t, and this time we will use ap one. The initialization process of a SoftAP ESP32 will look like:

Now, let’s have a look at the event_handler(). Events related to SoftAP could be one of the following:

And this is an example handler. Check the previous part of this series to know how event_handler() works:

system_event_t variable has information related to the connected/disconnected stations to ESP32 AP using event_info.sta_disconnected.mac for example.

Another thing to mention is tcpip_adapter_get_ip_info() API method which is used to get the network IP (or SoftAP IP). Finally, inet_ntoa() is a macro used to convert the numeric IP address into decimal dotted ASCII representation.

 

First App: HTTP Request

 

This example application will configure ESP32 as a station to get an internet access through the AP. After a successful connection to the AP, ESP32 will establish a socket and connect to the server. Keep in mind that this is a client-side connection so there is no need to use accept() nor listen() API methods.  

As the HTTP request will be for a specific website then we need a DNS to convert the domain name to an IP address. This is done by calling getaddrinfo() which will store the address information in a variable passed to it.

The last thing to talk about before giving the complete code is the way to make add some special configurations from menuconfig menu, which is covered in the next section.

 

Special Configuration from Menuconfig

 

WiFi code, for instance, should be altered to use the right SSID/PWD for example which is mostly changed by defines from the source file. Another way to change these values is to enter them from menuconfig. A file in the source file directory named “Kconfig.projbuild” must be created with the following example content written in Kconfig language:

Kconfig ESP32

Kconfig ESP32

In the code you should have defines in the same pattern like these:

Where the macro name could be anything but the value should be CONFIG_*** according to the name used in Kconfig.projbuild.

 

The Code

 

Now, it’s time to show the full code, and actually, it’s a modified and simplified version of original HTTP Request example from ESP-IDF:

Second App: ESP HTTP Client (Another HTTP Request)

 

Dealing with HTTP is not as simple as the example discussed earlier. There are different operations involved, like authentication (both username/password or HTTPS), redirection, streaming, the GET/POST/DELETE/…etc requests. That’s why ESP-IDF presents an  API for making HTTP/S requests from ESP-IDF programs. Using ESP HTTP client API methods has 3 main steps:

1- define a variable with esp_http_client_config_t type and fill it with the required information including url. Examples:

  • Normal GET/POST requests:
  • Authentication by username and password:
2- Calling the esp_http_client_init() API method:
3- Calling esp_http_client_perform(), which actually “performs all operations of the esp_http_client, from opening the connection, sending data, downloading data and closing the connection if necessary” according to the official documentation.

Other functions are called according to the required operation. For example, for POST operation a call to esp_http_client_set_post_field(client, post_data, strlen(post_data)) is needed.

Here is the response to GET request to an online API for random quotes (http://random-quote-generator.herokuapp.com/api/quotes/random)

ESP32 Random qoute API

Another attempt to get the response to GET request to an online API for ASCII art. (http://artii.herokuapp.com/make?text=ASCII+art).

ESP32 ASCII ART API

To see other use-cases of ESP HTTP client, see the full example from ESP-IDF.

 

Third App: TCP Server

 

In this last application for this part, we will make a TCP server listen to TCP requests and answer it with a welcome message. In this application, we will print the connected stations IP to ESP32. The ESP32 will be a SoftAP and we will make the TCP connection using telnet on port 8888.

We already described in a past section how to make ESP32 in SoftAP mode, and in order to make the telnet connection we should know the network IP, thus we will print the network IP by calling tcpip_adapter_get_ip_info() which is also described previously.

Remember, as ESP32 here acts like a server then Socket creating will include calling bind() and listen() API methods.

Lastly, to print the IP address of connected stations, you can use this code:

The full code:

ESP32 TCP server response

AD Space

Yahya Tawil

Embedded Hardware Engineer interested in open hardware and was born in the same year as Linux. Yahya is the editor-in-chief of Atadiat and believes in the importance of sharing free, practical, spam-free and high quality written content with others. His experience with Embedded Systems includes developing firmware with bare-metal C and Arduino, designing PCB&schematic and content creation.

2 Comments

  1. Thanks for these examples.
    Please be aware that the HTTP client sample lacks code (as do the examples in the ESP-IDF documentation).
    When your query has a large reply (e.g. 2500 bytes), the sample will only print the last part of the reply.
    Either speficy .buffer_size in the esp_http_client_config_t initialisation, or avoid use of esp_http_client_perform().
    This can easily be demonstrated with a query on wunderground.org .

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.