---
# System prepended metadata

title: Applied IOT - prototype of a temperature monitoring device

---

# Applied IOT - prototype of a temperature monitoring device and an attempt to find a design pattern for an IoT application

Ingvar Larsson
Course 1DT305 - Introduction to Applied IoT summer 2023
Linnaeus University

LNU id: gl222if
New discord id: ilarsson
Old discord id: ILarsson#2898 

The course was full-time and covered 7.5 hp. To complete the course, I have spent about 20-30 hours a week. Some of the time was spent watching video lessons and online-sessions. But also looking for documentation and browsing aroundon Canvas, Discord and the internet to find specific information. Of the time spent, I have spent about 60% on design, writing, and testing code.

If you set up the project by rewriting all of the code, I guess it will take about 40 hours. Otherwise, you will do it in about an hour.


# Project overview
Very simple prototype to measure the indoor temperature in my home office and display the results on a dashboard provided by Adafruit. Data is transferred via a WiFi connection. and the MQTT protocol. I have also tried to develop a design pattern suitable for an IoT application that can be reused and facilitates maintenance and high availability IoT devices.

# Objective
One of the goals of the course was to setup an IoT device and display the results, preferably on a dashboard, by applying the techniques described in the lessons. 

However, the main objective of the project has not been to build a IoT device that delivers any really useful functionality. The main objective has been to learn the basics about how an IoT device should be built and learn how the software should be designed to achieve high reliability and availability, which should be very important issues for IoT applications.


# Materials
Before the course, it was recommended to acquire a starter kit with the materials needed to be able to complete the course. There was 1 main starter kit and two optional packages, and I ordered them all. See the table below. However, I only needed a few components for my project so the starter kit was enough. But it is impossible to know in advance what you need if you don't know what kind of IoT you want to do.

| Item| Price<br> VAT excluded |
| ---------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------:|
| [Start Kit – Applied IoT at Linnaeus University (2023)](https://www.electrokit.com/produkt/start-kit-applied-iot-at-linnaeus-university-2023/) |               319.20 SEK |
|[Addon Kit (optional) – Applied IoT at Linnaeus University (2023)](https://www.electrokit.com/produkt/addon-kit-applied-iot-at-linnaeus-university-2023/)|279.20 SEK|
|[Sensor Kit – 25 modules (optional)](https://www.electrokit.com/produkt/sensor-kit-25-moduler/)|239.20 SEK|

The total price (VAT and shipping included) was SEK 1076. If you are a beginner and do not know in advance that you will need the two optional kits, my recommendation is not to order them. If the need arises, you can probably buy the item you need directly from a store nearby. This is a basic course to start learning about IoT and as a beginner there won't be much time to build extra features if you don't know what you want to do in advance.


## List of materials

This is the material I used in my project. Prices fetched from the shop the kit was bought from. The item text is clickable links and will take you to the item page in the webshop.

|                                                             Item                                                             | Description     | Price<br> VAT excluded |
|:----------------------------------------------------------------------------------------------------------------------------:|:--------------- | -----------------:|
| [Raspberry Pi Pico W](https://www.electrokit.com/produkt/raspberry-pi-pico-w/)<br> ![](https://hackmd.io/_uploads/rJEFQJyF2.jpg)| Raspberry Pi Pico W microcontroller | 98 SEK|
|[LED mm Blue](https://www.electrokit.com/produkt/led-5mm-bla-diffus-1500mcd/) <br>![](https://hackmd.io/_uploads/SkjeNkytn.jpg)|LED 5mm blue diffuse 1500mcd|5 SEK|
|[Breadboard](https://www.electrokit.com/produkt/kopplingsdack-400-anslutningar/)<br>![](https://hackmd.io/_uploads/HkOJL11Fh.jpg)|Clutch deck (breadboard) 400 connections|49 SEK|
|[Lab cables](https://www.electrokit.com/produkt/labbsladd-20-pin-15cm-hane-hane/)<br>![](https://hackmd.io/_uploads/By2mvyJK3.jpg)|Lab cable 20-pin 15cm male/male|29 SEK|
|[DHt11](https://www.electrokit.com/produkt/digital-temperatur-och-fuktsensor-dht11/)<br>![](https://hackmd.io/_uploads/S10lOkkK3.jpg)|Digital temperature and humidity sensor DHT11|49 SEk|
|[Resistor](https://www.electrokit.com/produkt/motstand-kolfilm-0-25w-330ohm-330r/)<br>![](https://hackmd.io/_uploads/rkbMvG1Yh.png)|Resistor carbon film 0.25W 330ohm (330R). *Reduces the current to the LED.*|1 SEK|


# Computer setup

The first recommendation was to use Visual Studio Code with the Pico-W Go plugin. That recommendation changed later to use the Pymakr plugin instead. However, I had already installed Pico-W Go, and it worked good enough for me. I also installed Pymakr but I had problems to get it to work so I continue with Pico-W Go.

One problem with Pico-W is that the plugin seems to be somewhat unstable in keeping the connection to the Raspberry Pico device. But I also installed Thonny who seems to be more stable concerning the connection with the Pico device, and used Thonny to reconnect and get control over the unit.

I run Visual Studio Code in Windows 10 and connect to the Pico with an USB-cable. So the code is uploaded from the Pico-W Go REPL terminal by applying one of the upload commands:
![](https://hackmd.io/_uploads/ByXBgm1Kn.png)

Steps to install the development environment:
1. Download Visual Studio Code.
2. Activate the Pico-W-GO extension and follow the instruction provided by the to install pylance and pyserial.
3. Mount the microcontroller on the breadboard and follow the instructions provided at [https://micropython.org/download/rp2-pico-w/](https://micropython.org/download/rp2-pico-w/)
4. Create a new project and activate the project by the Pico-W-Go > Configure project command (you can bring the menu up with CTRL-SHIFT-P)
5. Watch the status row at the bottom of the VS Code window, and you should see a status text like Pico Connected. Otherwise, try to restart VS Code.



# Putting everything together

![](https://hackmd.io/_uploads/HytvIEJYn.png)

Simple sketch over the layout of the breadboard. When the microcontroller starts up the main program tries to connect to the WiFi. The LED starts to blink until the network is connected and when connection is done it remains in a steady blue light.

The DHT11 (temperature and humidity sensor) is connected, to PIN 28 and the measured temperature is reported to the Adafruit MQTT server over the MQTT protocol.


# Platform

The built solution measures temperature in my home office and sends the measured values to a free service provided by Adafruit (adafruit.com): [Test feed for inhouse temperature, IoT Course IDT305 at LNU](https://io.adafruit.com/Ilarsson/feeds/idt305)).

WiFi is used to connect to the internet, and data is sent over the MQTT-protocol. I considered using LoraWan as the network connection, but unfortunately there were no LoraWan gateways nearby, so I was not able to establish any connection. 



### The Code


Code published and available at GitHub: https://github.com/GeoLar/idt305

I have made efforts to find a design of the code that matches, as I think, common requirements of an IoT application.

Those requirements are:
1. Reliability - the IoT application should deliver reliable data. 
2. Availability - The IoT application should be available when it is supposed to be.
3. Low footprint - The code should be compact and not consume more system resources than needed.
4. The IoT application should be possible to monitor.

| Description| Source file  |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
|`appconfig.py`     | Parameters to the application, easy to maintain in one place     | 
|`applog.py`     | Log messages from the application. Important module in the solution. Saves messages about crashes in a file on the microcontroller helping the developer to find the reason.     | 
|`boot.py`|Not used, it is empty but present since the `boot.py` is the first module to execute when the microcontroller is started.|
|`dht11.py`|Code to read measurements from the DHT11 sensor. Based on code downloaded from https://www.instructables.com/DHT11-With-Raspberry-Pi-Pico/|
|`main.py`|Runs directly after the `boot.py` is done. `main.py` contains the orchestration logic to perform the provided functionality.|
|`mqtt_client.py`|Code to connect to the MQTT-server (adafruit.com) and send data to it by using the MQTT protocol.|
|`netconn.py`|Code to connect to the WiFi network|
|`Simple2.py`|The MQTT-Client. Based on code downloaded from https://github.com/fizista/micropython-umqtt.simple2|
|`webserver.py`|A dimple webserver providing a simple monitoring features over the microcontroller. Based on code downloaded from Source: https://projects.raspberrypi.org/en/projects/get-started-pico-w/1| 


Develop high reliability and availability systems may be cumbersome. Unanticipated events will occur, and to have a chance to understand what happened, one needs information about the event. This should be a common need in IoT applications. Information helping to answer questions like "Why did my device stop doing the thing it was supposed to do? 

So I have tried to design a solution that supports the capture and permanent storage of information about such events. The excerpt from `applog.py` shows the method log-msg that does the work of handling log messages and storing the important ones in a file on the microcontroller.

I also think that another important requirement on an IoT application is the possibility of monitor its behavior. Therefore, I built a very, very simple webserver allowing the user to watch the 30 last written log messages and possibility to stop or restart the IoT-application. 

But if the power consumption is to be as small as possible, one must also assess whether the webpage can be allowed to be available all the time. In this application, data is sent once a minute, and the device could then be in sleep-mode between the transmissions.

The page looks like this:
![](https://hackmd.io/_uploads/Sy2pZfet2.png)


---

The main application logic is in `main.py`, and the trick to both handle web requests and perform the measure readings was to use non blocking socket IO in the web server.

```
'''
'''
main.py
 Main logic to start up the PICO Microcontroller application. 

 When the PICO is started, the bootloader executes main.py after boot.py.
'''
import machine
from machine import Pin
import time
import ntptime
import utime

from applog import APPLOG
import appconfig as params
import dht11
from mqtt_client import MQTT_CLIENT
from netconn import NETCONN
from webserver import WEBSERVER


# Allocate objects
log = APPLOG(log_level=APPLOG.DEBUG)
conn = NETCONN(log)
dht11_pin = Pin(params.dht11_pin, Pin.OUT, Pin.PULL_DOWN)
dht11 = dht11.DHT11(dht11_pin, log)
mqtt = MQTT_CLIENT(log, dht11=dht11)
webserver = WEBSERVER(log=log, conn=conn, dht11=dht11)

try:
    conn.wifi_connect() # Connect to a network

    # loop for ever,
    #   handle request to the webserver  
    #   and send measured values to the MQTT-service
    while True:
        time.sleep(0.5)
        webserver.serve() # Non blocking 
        mqtt.mqtt_publish() # Read mesaures and publish them in Adafruit
except KeyboardInterrupt as e: # Handles the ctrl+c command.
    log.log_msg(APPLOG.INFO, "Keyboard interupt: " + str(e))
except Exception as e: 
    log.log_msg(APPLOG.FATAL, "Exception main: " + str(e))
    log.log_msg(APPLOG.FATAL, str(type(e)))
    machine.reset() 
finally:
    try:
        webserver.close()
    except Exception as e:
        log.log_msg(APPLOG.ERROR, str(e))

    try:
        conn.wifi_disconnect()
    except Exception as e:
        log.log_msg(APPLOG.ERROR, str(e))

log.log_msg(log.DEBUG, "main done!")
```
---


`applog.py` (excerpt):

```
def log_msg(self, severity:int, msg, permanent= False):
        '''
        Writes the log message on standard output. The last
        30 messages are stored in a buffer and can be fetched
        for viewing in a webpage. Messages with a fatal severity
        or  messages with the parameter permanent set to True will
        be written to permanent storage on the device into
        the file named app.log.
        '''
        try:
            if (severity >= 0 and severity <= self.log_level):
                ts  = time.localtime()
                t = "{0:4d}-{1:02d}-{2:02d}T{3:02d}:{4:02d}:{5:02d}.{6}"\
                    .format(ts[0], ts[1], ts[2], ts[3], ts[4], ts[5], ts[6])
                
                m = (t, severity, str(msg))
                if (severity < self.TRACE): # Don't push trace messages on the messsage stack
                    self._msgtab.insert(0, m)

                    # Only keep the last self._msgstack_size messages
                    while (len(self._msgtab) > self._msgstack_size):
                        self._msgtab.pop()

                # A fatal event or permanent is saved so the event can be 
                # found after the device has been rebooted. 
                if (severity == self.FATAL or permanent):
                    try:
                        m = (t, severity, str(msg))
                        f  = io.open(params.APPLOG_LOGFILE, "a+")
                        f.write(m[0] + "\t"+ self.severity_text(m[1]) + "\t" + m[2] + "\n")
                        f.close()
                    except Exception as e:
                        print("Error writing {}: ".format(params.APPLOG_LOGFILE) + str(e))

                print(m[0], self.severity_text(m[1]), m[2])
        except Exception as e:
            print("applog error writing log message " + str(msg))
```


---


# Transmitting data

The data is transmitted over the MQTT protocol and on a WiFi connection.

The data sent is a single integer value  converted to text and sent once in a minute.

The module mqtt_client.py handles the measuring of temperatures and than send the measured values to Adafruit.

# Presenting data

The used feature in Adafruit is called IO and the collected data is configured in what is called a feed.

I have not done anything special with the dashboard, it is shown as the default layout. The period is between 2023-06-29 04:00 and 2023-07-02 12:00. At least one can see that the temperature was not so comfortable at the beginning of the measurement period.

According to information at the Adafruit site, data is stored for 30 days. You can read about it at this link: [Data Policies](https://learn.adafruit.com/adafruit-io/data-policies).

The dashboard show measured temperatures between 2023-29- 04:00 and 2023-07-02 20:00. As you can see, the temperature was not so comfortable in the beginning.

![Dashboard in Adafruit](https://hackmd.io/_uploads/ry_XGHJYn.png)


# Finalizing the design

Besides the microcontroller, I only used 2 components. But look at it... what a tangle!

Sure, one can add more componentsto the board, but I think the number is limited. However, I don’t think an IoT device should have many components attached since I think it should be specialized in doing one or two “things”.

![](https://hackmd.io/_uploads/BkMzfHJYh.png)


# Final words

It was fun to see the graph over the data measures show up in Adafruit. It is always a relief to see the results of the painful efforts made.  

But to me, the code and the design of the source modules are the real results. Now I have a base to start from and a start of design principles that should be possible to apply to other IoT applications. But, although a monitoring feature should be present, I also think that a webserver might not be the best solution. To save enery, a device may, by design, go to sleep periodically, and in that case, another design of the monitoring feature is needed.  

The next challenge will be how to make a real product of an IoT application. How should the "packaging" be designed, and how should power be supplied? 

**One thing is for sure, I will not stop with this, this was too fun to just stop doing the "IoT" thing :)**
