Master The Pico WiFi: HTTP Server
Written by Mike James & Harry Fairhead   
Monday, 13 May 2024
Article Index
Master The Pico WiFi: HTTP Server
The Response
Content Length
A Simple Server

The Response

If you try this out and connect to the Pico using a browser you will see something like:

Buffer= GET / HTTP/1.1
Host: 192.168.11.164
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,
image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=9
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8,es;q=0.7

You have to parse at least the first line to discover that the request, in this case is a GET and the file required is the default. In this case we are going to send the same HTML file, no matter what the client asked for.

The HTML is easy enough:

char html[] =
"<html><head><title>Temperature</title></head>
<body>
{\"humidity\":81%, \"airtemperature\":23.5C}</p>
</body>
</html>\r\n";

This is a typical small page for a small server reporting back temperature and humidity. The HTML could be anything, as long as it is not too big. If this was real data from a sensor then the temperature and humidity would be dynamically added to the HTML string after reading. Also notice that the data takes the form of a JSON data object. In this case the JSON is wrapped by some simple HTML so that it can be displayed, but it is easy enough to change this so that we are transmitting raw JSON ready for processing, see later.

To send this HTML we need some HTTP headers defining what we are sending back. The simplest set of headers that work is something like:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Server:Picow
Date: Sat, 13 Jun 2020  6:23:15 GMT
Content-Length:113

Notice that we now have two headers, Date and Content-Length, that need to be generated dynamically and be set to the current date and the size of the data portion respectively. There is also a blank line to mark the end of the headers. If you drop back to HTTP 1.0 you can avoid the dynamic headers, but they aren’t difficult to construct.

It is easier to make the headers after you have created the HTML and know its length. The Status and Content-Type headers are static:

char headers[1024] = {0};
char Status[] = "HTTP/1.1 200 OK\r\n
Content-Type: text/html;
charset=UTF-8\r\nServer:Picow\r\n";

Date and Time

We have a small problem with the date header, however, as the Pico doesn’t have a Real Time Clock (RTC), that is set automatically or battery-backed up. Later we will look at using SNTP, Simple Network Time Protocol, to set the real time clock, but for now we will simply initialize it to a convenient date and convert it into a standard C tm struct.

It is unfortunate that the RTC datetime_t struct isn’t organized to be compatible with the C tm struct which is supported by many useful date and time functions. However, it is fairly easy to convert between the two and this allows us to use standard C functions.

It is fairly easy to create a temporary initialization function:

void setRTC()
{
datetime_t t = {
.year = 2023,
.month = 02,
.day = 03,
.dotw = 5,
.hour = 11,
.min = 10,
.sec = 00};
rtc_init();
rtc_set_datetime(&t);
}

This needs to be called when the program starts to set the RTC which will then run and keep the current time until the program is restarted. To allow us to use the standard C date and time functions we can write a function that converts an RTC datetime_t struct into a tm struct:

void getDateNow(struct tm *t)
{
datetime_t rtc;
rtc_get_datetime(&rtc);
t->tm_sec = rtc.sec;
t->tm_min = rtc.min;
t->tm_hour = rtc.hour;
t->tm_mday = rtc.day;
t->tm_mon = rtc.month - 1;
t->tm_year = rtc.year - 1900;
t->tm_wday = rtc.dotw;
t->tm_yday = 0;
t->tm_isdst = -1;
}

Notice that the yday, the number of days since the start of the year, isn’t filled in correctly. This isn’t important as we don’t make use of it, but you can easily add an expression to compute it.

To use the RTC you have to change the target_link_libraries in the CmakeLists.txt file to read:

target_link_libraries(main pico_stdlib
pico_cyw43_arch_lwip_threadsafe_background hardware_rtc)

i.e. add hardware_rtc. We also need to add:

#include "hardware/rtc.h"

With these two functions we can now construct a Date header:

struct tm t;
getDateNow(&t);
char Date[100];
strftime(Date, sizeof(Date),
"Date: %a, %d %b %Y %k:%M:%S %Z\r\n", &t);



Last Updated ( Monday, 13 May 2024 )