MqttSensor with WebServer (Exercise)
MQTT Sensor with Web Server
##################################################################################
import network # mqtt needs network connection #
import framebuf # we also connect a display #
from umqtt.simple import MQTTClient # MQTT library #
from SH1107_OLED import OLED # our driver for the OLED display #
from BME280 import BME280 # our library for the BME280 sensor (T,P)
from utils import Config # to read a configurattion file #
from machine import Pin, I2C # API for the I2C interfaces #
import time # standard package for timing #
import json # we publish our data in json format #
import uasyncio
from random import uniform
##################################################################################
##################################################################################
def wifi_connect(oled):
##################################################################################
# this code you can reuse from a previous exercise.
fb = oled.getFramebuffer()
fb.fill(0)
# get a "station interface" (opposed to access point interface) from the
# netwrok library. This object has the magic methods to connect to the
# wireless network and then to the LAN on the IP level.
sta_if = network.WLAN( network.STA_IF )
# If it is already active de-activate it first so that we always start
# from the same base state.
if sta_if.active():
sta_if.active(False)
# Now try to connect to the WIFI
sta_if.active( True )
fb.text( "Connecting...", 0, 10 )
oled.copyFramebuf()
sta_if.connect( config.get("ssid"), config.get("password") )
# Poll to know when the connection succeeds
connected = sta_if.isconnected()
# create some dotted lines on the display to
# indicate the process which takes time.
x = 0
col = 1
while not connected:
fb.pixel( x, 0, col)
fb.pixel( x, 1, col)
fb.pixel( x+1, 0, col)
fb.pixel( x+1, 1, col)
oled.copyFramebuf()
x += 4
if x > 122:
x=0
col = (col+1)%2
connected = sta_if.isconnected()
time.sleep(0.1) # this is 100ms
# If we arrive here we should be connected
fb.text( "Success !", 0, 25 )
oled.copyFramebuf()
mac = sta_if.config('mac')
# Show the IP address we got from the DHCP server
ifparm = sta_if.ifconfig()
iptxt = "IP:%s" % ifparm[0]
fb.text( iptxt, 0,40 )
oled.copyFramebuf()
print ("IP : %s" % ifparm[0] )
print ("SUB: %s" % ifparm[1] )
print ("GAT: %s" % ifparm[2] )
print ("DNS: %s" % ifparm[3] )
# short break to read the display before we move on
time.sleep(2)
##################################################################################
##################################################################################
def mqtt_connect(client_id, mqtt_server, oled):
##################################################################################
# Also this routine can be reused from the previous exercise.
# Now set up the connection to the MQTT Broker
print("connecting to %s" % mqtt_server)
fb = oled.getFramebuffer()
client = MQTTClient(client_id, mqtt_server, keepalive=3600)
if oled:
fb.fill(0)
fb.text( "mqtt connect...", 0,10 )
oled.copyFramebuf()
try:
client.connect()
except Exception as e:
print(e)
if oled:
fb.text("...failed...", 0,20 )
fb.text("check broker!", 0,30 )
fb.text("cont. wo MQTT!", 0,45 )
oled.copyFramebuf()
time.sleep(5)
fb.fill(0)
return False
else:
return False
if oled:
fb.text("mqtt broker :", 0,30 )
fb.text(mqtt_server, 0,40 )
oled.copyFramebuf()
time.sleep( 4 )
return client
##################################################################################
##################################################################################
def webpage( temp, pressure, humidity ):
# this can be the same webpage as in our webserver example
html = f"""<!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>{temp:.1f}</td><td class="left">C</td></tr>
<tr><th>Pressure</th><th>:</th><td>{pressure:.1f}</td><td class="left">mb</td></tr>
<tr><th>Humidity</th><th>:</th><td>{humidity:.0f}</td><td class="left">%</td></tr>
</tbody>
</table>
</body>
</html>
"""
return html
##################################################################################
##################################################################################
# also recycled from the webserver exercise
async def sendfile( fn, writer, ctype ):
# read the file
content = open( fn, 'r' ).read()
# send the header to the HTTP client
writer.write( ('HTTP/1.0 200 OK\r\nContent-type: ' + ctype + '\r\n\r\n').encode() )
# send the contents to the HTTP client
writer.write(content.encode())
# Now wait until everything is written
await writer.drain()
# Finally close the stream and wait until it is closed
writer.close()
await writer.wait_closed()
##################################################################################
##################################################################################
async def handle_request(reader, writer):
# read the header from the reader
request_line = await reader.readline()
# skip all other header lines (until the empty line)
stop = False
while not stop:
li = await reader.readline()
if li != b"\r\n":
pass
else:
stop=True
request = str(request_line, 'utf-8').split()[1]
print("request: %s" % request )
if request[-3:] == "css":
await sendfile( request[1:], writer, "text/css" )
elif request[-4:] == "html":
# Here is a small difference to the webserver example:
# instead of random values we need to use the sensor values which we
# have obtained from a sensor in another task. They are saved in global
# variables...
response = ???
writer.write( 'HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n'.encode())
writer.write(response.encode())
await writer.drain()
writer.close()
await writer.wait_closed()
else:
writer.write( 'HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n'.encode())
writer.write(("<html><body><h2>Unknown request : %s</h2></body></html>" % request).encode())
await writer.drain()
writer.close()
await writer.wait_closed()
##################################################################################
##################################################################################
# Now comes a small difference to our previous MQRR sensor example without web server:
# We want to use the asyncio based webserver which will run in a separate task. The
# main task instead will contain the loop for the sensor measurement. This was in the
# main program of the Network Sensor example. However now we need to declare this routine
# as a coroutine and we need to yield when we wait for one second between two sensor
# measurements.
# Hence I recommend to start with the code from the main programm of the MQTT Sensor
# program. Convert this main program into a co-routine. Then before the endless loop
# for the sensor measurements start, also create a new task for the web server. You
# can call this routine "main()" (but this is not required of course)
# Remember to change the sleep statement into the asyncio form of the sleep so that
# the webserver gets also some CPU time !
#################################################################################
####################### Here the main programme starts ###########################
# We use global variables for the three sensor values:
temp = 0
p0 = 0
hum = 0
# read the configuration file. We want "config" to be in the global scope
# therefore we create it here and not in the "main()" function.
config = Config( "config_mqttSensor.json" )
# Put here the command to start the EventLoop with the main co-routine