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.

EMIT's web page

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.

9.1 Setting up our web server

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>&deg;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>&deg;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

9.2 Using our web server

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)

9.3 Connecting to the web server

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.

EMITs IP Address

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!

EMIT's web page

⚠️ **GitHub.com Fallback** ⚠️