Examples 1: Web Server
micro:bit
 

 

Static Web site

A static web page contains HTML code and requires no server action other than returning the text as HTTP response. To simplify the file management, only a single page can be saved. The HTML text is transferred to the ESP32 using the saveHTML() command.

# SaveHTML1.py

from linkup import *

html = """<!DOCTYPE html>
<html>
  <head> 
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body> 
     <h2>Welcome to the micro:bit</h2>
     <p>Enjoy programming!</p>     
  </body>
</html>
"""

print("Saving HTML...")
saveHTML(html)
print("Done")

The LinkUp first logs in a existing access point with the SSID/Password with the function connectAP that returns the IP address that must be known as browser URL. It is displayed as scrollng text. startHTTPServer(onRequest) is a blocking function that starts the server and registers the callback function onRequest that is called when a HTTP GET request arrives. The parameters provides the information from the URL, e.g. the host (string), the path (string) and the query (dictionary). Only HTTP GET requests are supported.

# WebServer1.py

from linkup import *
from microbit import *

def onRequest(clientIP, filename, params):   
    return

ipAddress = connectAP(ssid = "myssid", password = "mypassword")
display.scroll(ipAddress, wait = False)
startHTTPServer(onRequest)

The browser shows:

ex1-1

If a terminal program (e.g. puTTY, 115200 baud) is connected to the ESP32, debug information is written there:

Wait for master command...
Got command: 5
Content from file linkup.html restored
Starting HTTPServer
-->blocking accept
Got a connection from: 192.168.0.100
Got url with filename: / params: {}
Got reply from master: []
Turnaround time Slave-Master-Slave: 0.26 s
Total response time: 0.33 s
-->blocking accept

The output shows that the ESP32 is waiting for a command from the micro:bit. Command ID 5 starts the HTTP server that is waiting on a blocking accept() for an incomming TCP connection. When this happens it extracts the URL from the HTTP GET request, sends the information to the micro:bit and waits for a reply that arrives after 0.26 s. Then it sends the HTTP response to the client and waits for the next connection. The whole process is hidden to the application programmer.

Instead of using an external WLAN router, an local access point can be started on the ESP32. This is useful for home automation and remote control.

# WebServer1a.py

from linkup import *

def onRequest(clientIP, filename, params):   
    return

createAP(ssid = "microbit", password = "")
startHTTPServer(onRequest) 

To access it, you must first log in to the access point microbit with no password and then select the URL 192.168.4.1in your browser.

 

Interactive (dynamic) Web site

An interactive Web page contains information as part of the URL or as query parameters that is used by the Webserver to perform particular actions. In this example the URL is supplemented with /on or /off. that is used to switch on or off a hardware device (for the demonstration here some pixels are lit on the micro:bit display).

First the website is downloaded. It uses two links to generate the URL <host>/on and <host>/off.

# SaveHTML2.py

from linkup import *

html = """<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body> 
     <h2>Welcome to the micro:bit</h2>
     <p><a href="on">Light On</a></p>
     <p><a href="off">Light Off</a></p>
</body>
</html>
"""   

print("Saving HTML...")
saveHTML(html)
print("Done")

The code to run the server that connects to an existing router is simple. The callback onRequest() uses the filename parameter to check if /on or /off has been sent.

# WebServer2.py

from linkup import *
from microbit import *

def onRequest(clientIP, filename, params):
    if filename == "/on":
        display.show(Image.HEART) 
    elif filename == "/off":
        display.clear()

ipAddress = connectAP(ssid = "myssid", password = "mypassword")
display.scroll(ipAddress, wait = False)
startHTTPServer(onRequest)

The browser shows:

ex1-2

Two buttons can be used to embellish the display:

# SaveHTML2a.py

from linkup import *

html = """<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body> 
    <h2>Welcome to the micro:bit</H2>
    <button style="font-size:22px; height:50px;width:130px" 
            onclick="window.location.href='on'">Light On</button>  
    <button style="font-size:22px; height:50px;width:130px" 
            onclick="window.location.href='off'">Light Off</button>
</body>
</html>
"""   

print("Saving HTML...")
saveHTML(html)
print("Done")   

The browser now shows:

ex1-3

 

Use of URL query parameters

Information can transferred using query parameters. The callback function onRequest() receives these as a Python dictionary. In this example the returned Web page contains a text entry that reports the current state of the system, namely the line

Current state: on        resp.        Current state: off

To do this, Python string format parameters are used in the HTML text: Current state: %s<br>

The HTML uses a HTTP form element to generate the query strings and is downloaded with:

# SaveHTML3.py

from linkup import *

html = """<!DOCTYPE html>
<html>
  <head> <title>MicroBit Switch</title> 
  <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>
  <body> 
    <h1>Microbit Switch</h1>
    <form method="get">
      <input type="submit" style="font-size:22px; height:50px;
           width:110px" name="btn" value="on"/>
      <input type="submit" style="font-size:22px; height:50px;
           width:110px" name="btn" value="off"/>
    </form><br>
    Current state: %s<br>
  </body>
</html>
"""

print("Saving HTML...")
saveHTML(html)
print("Done")  

The values of these format parameters are passed back to the ESP32 by the return value of the onRequest() callback. When it is returned as a list, the ESP32 recognizes the list elements as format parameters and inserts them in the HTML page before returning the page to the browser.

The code on the micro:bit is as follows:

# WebServer3.py 

from linkup import *
from microbit import *

def onRequest(clientIP, filename, params):
    global state
    if 'btn' in params:
        state = params['btn']
        if state == 'on':
            display.show(Image.HEART) 
        elif state == 'off':
            display.clear()
    return [state]

state = 'off'
ipAddress = connectAP(ssid = "myssid", password = "mypassword")
display.scroll(ipAddress, wait = False)
startHTTPServer(onRequest)

The dictionary params is either {'btn':'on'} or {'btn':'on'} When the Web client enters the first time, it does not send any query parameters and 'btn' is not found. In this case only the current state is returned and no switching action is perfomed. As seen the return value is a list with the format parameters, which are inserted into the the HTML page (respecting the given order if more than one element is in the list).

For home automation applications, a local access point on the micro:bit could be used.

In a terminal window of the ESP32 you can follow what is actually going on:

-->blocking accept
Got a connection from: 192.168.4.2
Got url with filename: / params: {'btn': 'on'}
Got reply from master: ('on',)
Turnaround time Slave-Master-Slave: 0.29 s
Total response time: 0.38 s
-->blocking accept
Got a connection from: 192.168.4.2
Close request with filename: /favicon.ico params: {}
-->blocking accept

The following actions take place:

  • The ESP32 is waiting for a client
  • The client from IP address 192.168.4.2 makes a GET request (this address was provided by the DHCP on the ESP32)
  • The client's URL is /?btn=on, so the filename is '/' and the query parameter btn = on
  • This information is transmitted to the micro:bit via I²C and after some time the micro:bit responds by sending ('on')
  • The ESP32 replaces the format string in the HTML page with 'on' and sends the HTTP response back to the client
  • The turnaround time from ESP32 to micro:bit and back is 0.29s, which gives a response time for the HTTP request of 0.38s
  • Then the client browser sends a request for the file favicon.ico (which is answered by the ESP32 with the HTTP response code 204 'no content').