Programming The ESP32 In C - Socket Web Client
Written by Harry Fairhead   
Tuesday, 22 October 2024
Article Index
Programming The ESP32 In C - Socket Web Client
A Web Client
HTTP

Using the functions connection becomes easy:

#include "esp_wifi.h"
#include "string.h"
#include "nvs_flash.h"
#include "wificonnect.h"
void app_main(void)
{    
    wifiConnect("CO", "ssid", "password");
        while (wifiStatus != 1010) {
        vTaskDelay(10 / portTICK_PERIOD_MS);
    };
//use WiFi connection
}

You can clearly customize the connection to include parameters to control the IP address, host name and authentication type. Also notice that the use of a status variable allows the wifiConnect function to return at once, but we can still wait in the main program for the connection to be made. The vTaskDelay in the while loop allows other tasks to run while waiting.

In the rest of this chapter it is assumed that the connection function is available as a header file.

In book but not in this extract:

  • Using esp_netif

ESP32Cebook180

A Web Client

Now that we have a WiFi connection we can start using it. The ESP32 makes use of the standard sockets interface to transfer data over an IP link. This works in terms of general IP packets, but usually we want to customize the packets to carry a particular protocol. In this case, a web client using HTTP, is required. It has to be admitted that a web client isn't as common a requirement as a web server, but it is simpler and illustrates most of the points of using sockets to implement an HTTP packet using a TCP/IP transaction.

The first thing we have to do is create a socket and the TCP needed for an HTTP transaction:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);

AF_INET defines the transaction as an internet connection and SOCK_STREAM means a two way communication – in this case TCP/IP.

To allow this to work you have to add:

#include “socket.h”

Next we need to get the address of the server we want to connect to. For the web this would usually be done using a DNS lookup on a domain name. To make things simple we will skip the lookup and use a known IP address, example.com, which is a domain name provided for use by examples. You can find its address by pinging it and, at the time of writing, it was hosted at:

93.184.215.14

This could change so check before concluding that "nothing works".

There are three fields in the address structure:

struct sockaddr_in addr;

sin_family is just set to:

addr.sin_family = AF_INET;

to indicate an internet IPv4 address. The next field is the port number of the IP address, but you can't simply use addr.sin_port = 80; because the bit order used on the Internet isn't the same as used on most processors. Instead, you have to use a utility function that will ensure the correct bit order:

addr.sin_port = htons(80);

The function name stands for “host to network short” and there are other similarly named functions.

The actual address is defined in the in_addr field. This is a struct with only one field that you need to know about, s_addr, a 32-bit representation of an IP address. The format is fairly simple. Regard the 32-bit value as four bytes with each byte coding one value of the "dotted" IP address.

That is, if the IP address is w.x.y.z then w, x, y and z are the bytes of s_addr. For example, the IP address of example.com is 93.184.215.14 and converting each value into its byte equivalent in hex gives 5d.b8.d7.0E, which would be the hex value we have to store in s_addr if it wasn't for the fact that the bytes are stored in reverse order. So, the hex equivalent of the IP address is 0x0Ed7b85d and this is used to initialize the address struct:

  addr.sin_addr.s_addr = 0x0Ed7b85d;

With the address worked out and safely stored we can now make the connection:

connect(sockfd, &addr, sizeof (addr));

This will return 0 if it successfully connects and we do need to test for this condition. You will also get a type warning because the pointer to the addr structure isn't as defined in the function. In fact there are many variations on the addr structure which you could pass and it is the standard idiom to cast them to the function's pointer type:

connect(sockfd, (struct sockaddr *) &addr, sizeof (addr)

Finally we need to check for an error:

if(connect(sockfd, (struct sockaddr *) &addr, 
sizeof(addr))<0) return;

As long as there is no error we can start to send and receive data.

But what data? The answer is that it all depends on the protocol you are using. There is nothing about a socket that tells you what to send. It is a completely general I/O mechanism. You can send anything, but if you don't send what the server is expecting, you won’t get very far.



Last Updated ( Friday, 08 November 2024 )