A simple WebServer with asyncio
In this exercise we want to create a simple webserver on our microcontroller.
Writing a Webserver for a microcontroller is a convenient way to create a graphical user interface for your application without dealing with additional hardware (like tft displays and buttons). It also allows you to conveniently configure and control you microcontroller application via a web brouse (e.g. on your phone), event from remote locations.
With the asyncio framework it is particularly easy to create a web server. The framework is very suitable for this since a webserver perfectly matches the asyncio programming model. The server waits for outside requests and once a request comes, it interpretes the request (i.e. decodes it) and afterwards takes some action (i.e. change some parameters for some task which is continuouly running: Example could be: change the station or the volume of a running web-radio)
During the exercise please use the documentation of the micropyton asyncio. It contains all the relevant networking co-routines which we need.
In order to understand the template for this exercise you need some minimal knowledge of the HTTP protocol.
HTTP rudimental basics
The HTTP protocol consists of requests (from the client) and responses (from the server). A request (and a response) have a header which is a sequence of ASCII lines, an empty line and then the some data might follow.
There are different categories of requests defined: GET, POST, PUT, DELETE, HEAD, CANCEL, CONNECT, OPTION, TRACE, PATCH. If you retrieve a web page frome a server your browser uses the "GET" request. This request specifies the resource (=the page) which you want to retrieve. A minimal get request could look like this:
The empty line at the end is part of the request. This request asks for the page index.html on the webserver at 192.168.200.1
A minimal response could look like this:
Here the first two lines form the response header, whereas the content is following the empty line (i.e. the web page to be retrieved)
As a real world example below is the the data exchange between a firefox browser requesting the web page and the microcontroller server for the webserver implemented in this exercise. As you can see the firefox browser adds a lot of lines to the header whereas our microcontroller answers with a simple reply.
GET /sensors.html HTTP/1.1
Host: 10.42.0.14:8888
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Priority: u=0, i
HTTP/1.0 200 OK
Content-type: text/html
<!DOCTYPE html>
<html lan='en'>
<head>
<title>A sensor simulation</title>
<link rel="stylesheet" href="mystyle.css">
</head>
<body>
<h1>Sensor values</h1>
<p></p>
<table class="sensor">
<thead>
</thead>
<tbody>
<tr><th>Temperature</th><th>:</th><td>29.6</td><td class="left">C</td></tr>
<tr><th>Pressure</th><th>:</th><td>1014.4</td><td class="left">mb</td></tr>
<tr><th>Humidity</th><th>:</th><td>42</td><td class="left">%</td></tr>
</tbody>
</table>
</body>
</html>
Our first server
The first web server should just display the values of our sensor on a webpage.
You can start very simple and in the first trial you can also use random numbers for the sensor values so that you do not need to deal with the sensor. We can plug the sensor into the application at a later point when we have the web server running.
Do create some nice looking page, you should format your simple webpage with a css style sheet.
Implementation
Re-use the class you used in previous exercises to connect to the wifi network.
Then work through the code template to implement the server. You will need the following functions of asyncio (look up the documentation for detailed info):
- asyncio.startserver(callback,host,port) : This starts a TCP/IP server on the specified port. If you specify 0.0.0.0 for the host parameter it means the server listens on all network interfaces (which is what we want). The callback is a co-routine you have to provide in order to implement code which analyses the incoming request and which sends the response back to the client. This callback is called with two parameters: reader and writer
- The reader shohuld be used to read the lines of the incoming request with reader.readline().
- The writer should be used to write the response back to the client. Use the co-routines writer.drain() after sending the data so that all data is pushed out and writer.wait_closed() after closing the writer to properly end the data exchange.
If you want to start very simple then build your first version without a css style sheet. In this case only the web page is transferred and the browser will not issue a second request for the style sheet. Hence you server does not need to deal with sending a file to the client.
Finally test the web server by requesting the page it serves from your laptop (using your browser). Remember that for this you have to also connect your laptop to the student14 wireless network!