---
# System prepended metadata

title: Temperature reading and presenting

---

# Temperature reading and presenting
Oskar Lindén (user ol222md at LNU) 
Link to [GitHub](https://github.com/cephlot/IoT-lnu)

## Project overview
This project aims to utilize a microcontroller and a temperature sensor to measure the ambient temperature and send the measured values to a self-hosted MQTT+TIG stack which visualizes the measurements in a Grafana dashboard.

The project itself is not that large and should not take more than a week to complete, depending on previous experience.

## Objective
I chose this project because I did not have a prior plan to execute when I received the components I ordered and because they arrived with less than two three left of the course I decided to do something simple that should not take too much time.

The purpose of the project is to serve as a simple example of how to operate and connect components to a microcontroller with the help of a breadboard as well as programming a microcontroller in MicroPython and visualizing the data on a self-hosted platform.

I think that this project will introduce me to a specific mindset when programming for embedded devices in contrast to desktop or CLI applications, which I normally do.

## Material 
The following table describes the material used in this project as well as an explanation why and a link to the product.

| Component | Explanation | Cost | Link |
| --------  | -------- | ------- | ------- |
| Arduino Nano RP2040 Connect | This is the primary device for taking measurements from connected sensors and makes the data available on the network | 299.00 SEK | [electrokit](https://www.electrokit.com/produkt/arduino-nano-rp2040-connect-with-headers/) |
| MCP9700 TO-92 Temperature Sensor | This is the sensor of choice for taking temperature measurements. Note that other sensors work just fine. The only differences are the connections and the software conversion | 8.00 SEK | [elctrokit](https://www.electrokit.com/produkt/mcp9700-e-to-to-92-temperaturgivare/) |
| Breadboard | This is for connecting our different components | 69.00 SEK |[electrokit](https://www.electrokit.com/en/product/solderless-breadboard-840-tie-points-2/) |
| Jumper wires | For connecting components on the breadboard. I would recommend the 1-pin male-male wires | 29.00 SEK | [electrokit](https://www.electrokit.com/en/product/jumper-wires-1-pin-male-male-150mm-10-pack/) |

For this project, in addition to the MCU I also purchased the [LNU – 1DT305 Tillämpad IoT – Sensors only bundle](https://www.electrokit.com/en/product/lnu-1dt305-tillampad-iot-sensors-only-bundle/) which contains the temperature sensor, breadboard and jumper wires among other components. At the time of writing, the price of the bundle is 129.00 SEK.

<figure align="center">
    <img align="center" src="https://i.imgur.com/KaPCZam.jpg" style="width:80%">
    <figcaption align = "center"><b>Fig 1. Arduino Nano RP2040 Connect with headers</b></figcaption>
</figure>


## Computer setup
The chosen IDE for this project is the [OpenMV IDE](https://openmv.io/pages/download) since it comes with integrated support for connecting to and running code on microcontrollers. It also installs the necessary drivers during the installation process.

The code is uploaded to the microcontroller through the OpenMV IDE or copying and pasting the necessary files to the mass storage of the microcontroller.

The only software needed in addition to OpenMV IDE, the drivers and the project files is the [umqttsimple.py](https://raw.githubusercontent.com/RuiSantosdotme/ESP-MicroPython/master/code/MQTT/umqttsimple.py) code needed for the necessary MQTT functionality.

## Building
Figure 2 shows the circuit diagram of the project. It contains the Arduino microcontroller and the temperature sensor. 

<figure align="center">
    <img align="center" src="https://i.imgur.com/tB0hkMd.png" style="width:100%">
    <figcaption align = "center"><b>Fig 2. Arduino Nano RP2040 Connect with headers</b></figcaption>
</figure>

## Platform

As previously mentioned, this project utilizes a self-hosted MQTT+TIG-stack (Telegraf + Influxdb + Grafana) running in a Virtual Machine on a local server running [Proxmox](https://www.proxmox.com/en/). The stack is executed using Docker and all built with a single docker-compose script.

MQTT is a standard messaging protocol for IoT devices that uses a simple  and lightweight publish/subscribe message transport.

Telegraf is a server agent for collecting metrics from different sources and inserts it into a database, for instance.

Influxdb is a database for time series metrics. This is where Telegraf inserts its collected data.

Grafana is a visualization platform which allows you to query, visualize and alert on different metrics. The Grafana instance uses the Influxdb instance as a data source.

## Implementation
The implementation of the microntroller code can be divided into three parts: connection to WiFi, connection to MQTT broker, and temperature measurement and MQTT publishing.

The implementation consists of three files: `boot.py`, `secrets.py` and `umqttsimple.py`. All files have to be located in the mass storage of the microcontroller.

### Connection to WiFi
The function for connecting to a local WiFi network is boilerplate except for the SSID and KEY being located in a separate and local file called `secrets.py`. Since this code is uploaded to GitHub it is a good idea to not share private details such as your WiFi SSID and password with the whole world.

```[python]
def connect_wifi():
    """Connects to a WiFi network with specified SSID

    :return: WLAN object
    :rtype: WLAN object
    """
    SSID=secrets.SSID # Network SSID
    KEY=secrets.KEY  # Network key

    # Init wlan module and connect to network
    print("Trying to connect. Note this may take a while...")

    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(SSID, KEY)

    # We should have a valid IP now via DHCP
    print("Wi-Fi Connected ", wlan.ifconfig())

    return wlan
```

To use the variables located in `secrets.py`, simply import the file and omit the file type, i.e. `import secrets`. Note that this file has to be in mass storage with `boot.py`.

The variables included in `secrets.py` is the WiFi SSID, WiFi key and the IP address of the MQTT broker.

### Connection to MQTT broker
The function for connecting to the MQTT broker utilizes the MQTTClient class of the `umqttsimple.py` library code. The connected client is then returned from the function in order to use it for publishing.

```[python]
def connect_mqtt():
    """Connects to an MQTT broker

    :return: MQTT client class
    :rtype: MQTTClient
    """
    global client_id, mqtt_server

    client = MQTTClient(client_id, mqtt_server, port=1883, keepalive=30)
    client.connect()

    print(f'Connected to {mqtt_server} MQTT broker')

    return client
```

### Temperature measurement and publishing
The temperature is, as previously mentioned, measured with a MCP9700 temperature sensor and read from an Analog-to-Digital Converter (ADC) pin on the microcontroller. 

We start by creating the necessary objects and variables required to connect to WiFi and the MQTT broker. Then we enter the main loop of the program where we read from the ADC pin connected to the sensor and converts the read value to a voltage which we can use to calculate the ambient temperature. Each iteration we take 100 different samples and take the mean to get our final temperature.

Finally we publish the measurement to the MQTT broker on the specified topic and go to sleep for 15 minutes.

```[python]
while True:
    # Connect to WiFi specified in 'secrets.py'
    wlan = connect_wifi()

    # Create MQTT client connection
    try:
      client = connect_mqtt()
    except OSError as e:
      restart_and_reconnect()

    sum = 0

    # Collect samples
    for i in range(0,100):
        voltage = adc.read_u16()*CONV
        sum += (voltage - 0.5)/0.01

    # Take the mean of the samples
    temp = sum/100.0
    print(temp)

    try:
        # Publish the temperature measurement to the MQTT server
        client.publish(TOPIC, (b'{0:3.1f}'.format(temp)))
    except OSError as e:
        # Reset the MCU if error occurs
        restart_and_reconnect()

    # Turn off WiFi module
    disconnect_wifi(wlan)

    # Sleep for 15 minutes.
    time.sleep(15*60)
```


## Connectivity
The microcontroller used is connected to WiFi and sends a mean of the temperature samples every 15 minutes to to the MQTT broker that is connected to the same network.

## Presenting the data
As seen in Figure 3, the data is presented in a Grafana dashboard with two panels: one for the latest temperature measured and one for a time series of measured temperatures. The sorce of the data is an influxdb database that keeps the data for thirty days.

<figure align="center">
    <img align="center" src="https://i.imgur.com/OPpmE5j.png" style="width:80%">
    <figcaption align = "center"><b>Fig 3. Grafana dashboard with two panels</b></figcaption>
</figure>

## Results
Figure 4 shows the microcontroller and temperature sensor assembled on the breadboard which is the final product of this project.

<figure align="center">
    <img align="center" src="https://i.imgur.com/tHJSImM.jpg" style="width:80%">
    <figcaption align = "center"><b>Fig 4. Assembled MCU and temperature sensor</b></figcaption>
</figure>

This project has been very fun and I am happy with the result. I would have liked to expand the project even more to fill out the time a bit better and to gain more experience with different sensors.

One idea I had, that required more time, was to implement the application in different programming languages and compare different metrics to determine which would be the best choice for a battery-powered solution. I experimented a bit with the Rust programming language, but I could not get it to work and I stuck to my original plan.