Adding WiFi To The Pico 2
Written by Harry Fairhead   
Monday, 19 August 2024
Article Index
Adding WiFi To The Pico 2
Connecting the ESP8266 ESP-01
Attention!
Some Utility Functions
Connecting to WiFi
Sending Data
A Web Server
Complete Listing Of Web Server

A Web Server

The most common use for an internet connection on a small device like the Pico is to allow another device to request data. It is fairly easy to create a web server running on the ESP8266, but don't expect Apache or anything advanced. All you can reasonably do is accept a connection and send a web page or two back to the client. 

The key differences between client and server mode is that in server mode the device is constantly "listening" for clients to make TCP connections on the port. When the device receives a connection it reads all of the data the client sends and passes it on via the serial port to the Pico. This means that in server mode the Pico has to be constantly on the lookout for new data from the ESP8266. You can do this using an interrupt, but for simplicity this example uses a polling loop.

There is another difference between client mode and server mode - there can be multiple TCP connections from as many clients as try to connect. The solution to this problem is that the ESP8266 assigns each TCP socket connection an id number and this is what you need to use to make sure you send the data to the right place.

Let's see how it all works. Assuming we are already connected to WiFi and have an IP address, we can set up a server quite easily. First we need to use the command CIPMUX=1 to set the device into multiple connection mode. You cannot start a server if CIPMUX=0, the default single connection mode. Once multiple connections are allowed you can create a server using CIPSERVER=1,port.

In this example we are using port 80. the standard HTTP port, but you can change this to anything you want:

int startServerWiFi(uint8_t buf[], int len)
{
    char temp[256];
    char id[10];
    uart_write_blocking(uart1, "AT+CIPMUX=1\r\n", 13);
    if (getBlocks(buf, len, 10, "OK") < 0)
        return -1;
    uart_write_blocking(uart1,
"AT+CIPSERVER=1,80\r\n", 19);
if (getBlocks(buf, len, 10, "OK") < 0) return -1; return 0; }

If you run just this part of the program you will see the response:

AT+CIPMUX=1
OK
AT+CIPSERVER=1,80
OK

Now we just have to wait for a client to make a connection and send some data. This is done simply by reading the serial input and checking for "+IPD" in an infinite polling loop:

for (;;) {
 if (getBlocks(1, "+IPD") < 0)continue;

If we don't get a block containing "+IPD" we simply move on to the next iteration, i.e. there is nothing to do.

If we have received a block containing "+IPD", the body of the loop processes it. Note that all of the following instructions are inside the loop and are repeated for each request for the web page. We need to remove the IPD information. As this is C, string processing it is not elegant. The received data has the format:

+IPD,id, rest of data 

We need to extract the ID, as a string, so we can use it to communicate with the client. This is just some standard string handling, but it is still messy:

char *b = strstr(buf, "+IPD");
b += 5;
strncpy(temp, b, sizeof (temp)); char *e = strstr(temp, ","); int d = e - temp; memset(id, '\0', sizeof (id)); strncpy(id, temp, d);

The algorithm is:

  1. Find "+IPD" and trim the string to remove it and the comma

  2. Find the next comma and extract the characters from the start of the string to the next comma. 

Now we have the ID we can communicate with the client, but first we need something to send. As with all HTTP transactions, we have to send some headers and then some data. There are a lot of possible headers you could send, but a reasonable minimum that works with most browsers is:

char data[] = "HTTP/1.0 200 OK\r\n
Server: Pico\r\nContent-type: text/html\r\n\r\n<html>
<head><title>Temperature</title>
</head>
<body>
<p>{\"humidity\":81%,\"airtemperature\":23.5C}</p>
</body></html>\r\n";

Note that this is a single string with no spaces between the elements that have been split over different lines for presentation.

Of course, in a real application, the HTML part of the data would be generated by the program or read from a file. You can include timestamps and lots of other useful information, but this is simple and it works. Remember to include a blank line at the end of the headers. This is vital as the browser will ignore everything sent to it if you don't.

Now we want to send the data to the client. This is just a matter of using the CIPSEND command again, only this time with id specified as the first parameter:

	CIPSEND=id,data length

and we wait for the response ">" before sending the data.

Notice that we don't have to open a TCP socket as we did in the case of acting as a client. The TCP socket has already been opened by the client connecting to the server and when the transaction is complete we can close it:


uint8_t command[128]; int count = snprintf(command, 128, "AT+CIPSEND=%s,%d\r\n", id, strlen(data)); uart_write_blocking(uart1, command, count);

Now, at last, we can send the data to the client:

 uart_write_blocking(uart1, data, strlen(data));
 if (getBlocks(buf, len,  10, "OK") < 0)
            return -1;

and wait for it to complete.

Finally we close the connection and complete the loop to wait for another connection:

 count = snprintf(command, 128,
"AT+CIPCLOSE=%s\r\n", id);
uart_write_blocking(uart1, command, count);
if (getBlocks(buf, len, 10, "OK") < 0)
return -1;
}

Try it out with a main program something like:

int main()
{
    stdio_init_all();
    uint8_t buf[512];
    initWiFi();
    modeWiFi(buf, 512, 1);
    connectWiFi(buf, 512, "SSID", "password");
    getIPWiFi(buf, 512);
    startServerWiFi(buf, 512);
    sleep_ms(1000);
}

You should now be able to connect to the IP address that is displayed and retrieve the web page that displays:

	{"humidity":81%,"airtemperature":23.5C}

There are a lot of WiFi commands that haven't been covered here, but now that you have seen examples of most of the basic types and encountered the typical problems that occur you should be able to implement any that you need. 

There is still going to be the occasional unexplained crash and in this case the best solution is to use the soft reset command introduced earlier. It is also worth mentioning that the server program as presented does not actually handle multiple simultaneous connections. It has to finish dealing with one connection before it can deal with a second. To make it deal with multiple connections would mean checking for another connection while processing the first.



Last Updated ( Saturday, 24 August 2024 )