9. Adding a web server to EMIT - ControlBits/EMIT GitHub Wiki
Until now, we've been developing firmware to measure environmental data such as temperature and humidity and transmit it to a web application (such as the EMIT LIVE dashboard) using the MQTT protocol.
Sometimes, however we just need to remotely access the data from the sensor itself. This can be easily achieved by adding a simple Web Server to EMIT.
As a starting point for this section, we're going to go back to our firmware as it was at the end of section: 4. Connecting EMIT to the Internet and build it up from there.
The first thing we need to do is import the 'usocket' module into boot.py. This module provides the basic functionality we need to create and use the HTTP socket we'll need for our web server.
import usocket
With usocket imported, we can then create a function to create our HTTP socket:
# create 'HTTP' socket for web server
def create_HTTP_socket():
HTTPsock = usocket.socket() # create the socket object for our web server
HTTPsock.bind(('',80)) # bind the socket to port 80 (HTTP)
HTTPsock.listen(1) # start listening for a request (on port 80)
print('HTTP Socket created .. listening to port 80')
return HTTPsock
The first line uses the 'usocket.socket()' function to create the HTTP socket. Next we 'bind' our socket to our localhost on port 80 (HTTP). Finally we start the socket listening for an incoming HTTP request. Once set up, we print a success message to the Shell and return the HTTPsock object.
All that is left to do now is create the HTML web page and define a 'emit_web_page()' function to return the page when requested. An example web page 'wrapped' in the 'emit_web_page()' function is shown below.
Notice how the variables 'tempC' and 'humidity' are converted into strings and concatenated into the HTML!
def emit_web_page():
html = """<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {background-color: #258ECD; font-family: Arial; display: inline-block; margin: 0px auto; text-align: center; color: #333333;}
h1 {font-size: 1.8rem; }
p {font-size: 2.4rem; }
sup {font-size: 1.2rem; }
a:link, a:visited {text-decoration: none; color: #666666;}
a:hover {text-decoration: underline;}
.container { background-color: rgba(255,255,255,0.90); margin: 20px 20px 0px 20px; padding: 10px; border: 2px solid #ffffff; border-radius: 6px;}
.label {font-size: 1.2rem;}
.tiny {font-size: 0.8rem;}
</style>
</head>
<body>
<div class="container">
<div>
<img src="http://controlbits.com/images/ControlBits-logo.png" alt="ControlBits.com logo" style="width: 150px;">
</div>
<hr><br>
<h1>EMIT Web Sensor</h1>
<p>
<span class="label">Temperature:</span>
<i class="fas fa-thermometer-three-quarters" style="color:#059e8a;"></i>
<span>"""+str(tempC)+"""<sup>°C</sup></span>
</p>
<p>
<span class="label">Humidity: </span>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span>"""+str(humidity)+"""<sup>%RH</sup></span>
</p>
<br><hr>
<a class="tiny" href="https://ControlBits.com">Find out more at: https://ControlBits.com</a>
</div>
</body>
</html>"""
return html
The finished boot.py with 'create_web_socket()' and 'emit_web_page()' added is shown below:
# general board setup
import machine, time, dht
import network
import usocket
# configure GPIO pins
RedLED = machine.Pin(16, machine.Pin.OUT)
RedLED.value(0)
GreenLED = machine.Pin(17, machine.Pin.OUT)
GreenLED.value(0)
AM2302 = dht.DHT22(machine.Pin(14))
# define Wi-Fi settings
wifiSSID = 'your-WiFi-SSID-goes-here'
wifiPasswd = 'your-WiFi-password-goes-here'
# define function for setting up Wi-Fi network
def wifi_connect():
wifi = network.WLAN(network.STA_IF) # create our 'wifi' network object
wifi.active(True) # turn on the Wi-Fi hardware
# if not connected ...
while wifi.isconnected() == False:
GreenLED.value(1) # turn Green LED ON
print('trying WiFi connection ', wifiSSID) # print 'trying..' message to Shell
wifi.connect(wifiSSID, wifiPasswd) # try connecting to wifi
time.sleep(1) # wait 1 second
GreenLED.value(0) # turn Green LED OFF
time.sleep(2) # wait 2 second
# if connected ...
GreenLED.value(1) # turn Green LED ON
print('WiFi connection successful') # print 'WiFi connection successful' message to Shell
print(wifi.ifconfig()) # print WiFi network settings (inc. IP Address) to Shell
# create 'HTTP' socket for web server
def create_HTTP_socket():
HTTPsock = usocket.socket() # create the socket object for our web server
HTTPsock.bind(('',80)) # bind the socket to port 80 (HTTP)
HTTPsock.listen(1) # start listening for a request (on port 80)
print('HTTP Socket created .. listening to port 80')
return HTTPsock
# return our HTML to the web server
def emit_web_page():
html = """<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
<style>
html {background-color: #258ECD; font-family: Arial; display: inline-block; margin: 0px auto; text-align: center; color: #333333;}
h1 {font-size: 1.8rem; }
p {font-size: 2.4rem; }
sup {font-size: 1.2rem; }
a:link, a:visited {text-decoration: none; color: #666666;}
a:hover {text-decoration: underline;}
.container { background-color: rgba(255,255,255,0.90); margin: 20px 20px 0px 20px; padding: 10px; border: 2px solid #ffffff; border-radius: 6px;}
.label {font-size: 1.2rem;}
.tiny {font-size: 0.8rem;}
</style>
</head>
<body>
<div class="container">
<div>
<img src="http://controlbits.com/images/ControlBits-logo.png" alt="ControlBits.com logo" style="width: 150px;">
</div>
<hr><br>
<h1>EMIT Web Sensor</h1>
<p>
<span class="label">Temperature:</span>
<i class="fas fa-thermometer-three-quarters" style="color:#059e8a;"></i>
<span>"""+str(tempC)+"""<sup>°C</sup></span>
</p>
<p>
<span class="label">Humidity: </span>
<i class="fas fa-tint" style="color:#00add6;"></i>
<span>"""+str(humidity)+"""<sup>%RH</sup></span>
</p>
<br><hr>
<a class="tiny" href="https://ControlBits.com">Find out more at: https://ControlBits.com</a>
</div>
</body>
</html>"""
return html
To use our new web server in our main.py, the first thing we need to do is create an 'HTTP socket' object for our web server using the 'create_HTTP_socket()' function we've just created.
This function call should be inserted just after we have successfully connected to the Wi-Fi network:
HTTPsock = create_HTTP_socket()
As a web server waits for and responds to an incoming HTTP request, we no longer need the 5 second delay at the start of our main loop. As a result, this line ...
time.sleep(5) # wait 5 seconds
... should be deleted and replaced by:
conn, addr = HTTPsock.accept() # wait for an HTTP request to be received
print("Web request received from :" + str(addr)) # print a debug message to Shell
The first of these lines, creates an HTTP socket and starts waiting for an incoming HTTP request. The second line, prints a message to the Shell when a new request is received.
Once an incoming request has been received, our main loop will continue through the measurement process we created in part 3 of this guide.
Once that has been completed, we create a 'response' by returning the HTML page we created above, using:
response = emit_web_page() # create a response and return EMIT's web page
We then send a 'success' header:
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') # send 'success' header
... and the HTML response to the requester:
conn.send(response) # send our response over the HTTP connection
Finally, we close the HTTP connection and wait 2 seconds before returning to the beginning of our main loop (ready for the next request). It's important to add the delay to ensure that the minimum timing requirements of the AM2320 (maximum read frequency is once every 2 seconds) are not violated:
conn.close() # close our HTTP connection
time.sleep(2) # wait 2 seconds (max read frequency of AM2302 is once every 2 seconds)
Our finished main.py should look like this:
# connect to wifi
wifi_connect()
# wait 5 seconds for network to settle
time.sleep(5)
# create 'HTTP' for web server
HTTPsock = create_HTTP_socket()
# this is the main program loop
while True:
conn, addr = HTTPsock.accept() # wait for an HTTP request to be received
print("Web request received from :" + str(addr)) # print a debug message to Shell
RedLED.value(1) # turn RedLED ON
print("Reading AM2302 ...")
AM2302.measure() # start AM2302 measurement
RedLED.value(0) # turn RedLED OFF
tempC = AM2302.temperature() # get temperature (Celsius) from AM2302
humidity = AM2302.humidity() # get humidity from AM2302
tempF = (tempC * 9/5) + 32.0 # convert Celcius result into Fahrenheit
print("Temperature (C): " + str(tempC))
print("Temperature (F): " + str(tempF))
print("Humidity (%RH): " + str(humidity))
response = emit_web_page() # create a response and return EMIT's web page
conn.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n') # send 'success' header
conn.send(response) # send our response over the HTTP connection
conn.close() # close our HTTP connection
time.sleep(2) # wait 2 seconds (max read frequency of AM2302 is once every 2 seconds)
After you've uploaded the boot.py and main.py files created above and rebooted your EMIT, it should boot up and start listening for messages over your network. The Shell should display the reassuring message:
HTTP Socket created .. listening to port 80
In order to view EMIT's web page, all you need to do is enter your EMIT's IP address into the browser of any device connected to the same Wi-Fi network as your EMIT.
EMIT's IP address is the first IP address shown after the 'WiFi connection successful' message - shown here circled in red.
If everything works, you should now see EMIT's web page!