---
# System prepended metadata

title: Plant Environment Monitor
tags: [temperature, moisture, soil, humidity, plant]

---

**LNU-ID: dj222ny**
**Dino Juricic**


The goal of this Internet of Things (IoT) project is to create an IoT device which can collect sensor data, transfer the data to an external data storage and to visualize it. I choose to make an IoT device that could monitor the growth environment of an indoor plant using a set of different sensors.

With the help of this report and instructions the project shouldn't take more than 4-6 hours to complete.

This project was done as an assignment in the course "[Introduction to Applied Internet of Things (1DT305)](https://lnu.se/en/course/introduction-to-applied-internet-of-things/)" at [Linnæus University](https://lnu.se/en/).



### Objective

Purpose of this project is to monitor a plant's growth environment. To track current temperature, humidity, air pressure and soil moisture. It can help to maintain an optimal growth environment and to e.g. avoid overwatering or underwatering a plant to prolong its lifetime.

Why I choose to make this project started with me trying to figure out what I could do within the restrictions of what IoT equipment I had available and the time my full-time job and the course project deadlines would allow me.
The sensors I already had and which I thought could be useful was DHT11/DHT22 sensors and two BMP180 sensors. By adding soil moisture sensors I could go for a common and popular plant environment monitoring IoT idea. I was thinking how I could add some more complexity to this project which could hopefully lead to a higher grade in the IoT-course that this project was part of. My original idea was therefor to make use of an LCD1602A display and OLED SSD1306 display which I already had. Since I had two displays, two DHT22 sensors and two BMP180 sensors I thought I would make two devices where one could monitor a plant environment in a south facing window and the other could monitor a plant environment in a north facing window. I thought it could be interesting to compare and see if the plant in the south facing window would require more water. To add some more complexity to the project I thought adding a light measuring sensor would fit this project perfectly since we are going to monitor plant environment. So I ordered two TSL2591 sensors which seemed good sensors, high dymanic range and accurate. Once they arrived and I tried to use I couldn't find any good tsl2591 libraries to use with micropython. Due to the lack of time I realised that I had to remove them from the scope of my project. The lesson learned was to also look for suitable libraries before ordering sensors online. :)
In the original project plan I also had the idea to let one of the plant monitoring devices be connected through WiFi while the other device would be connected through LoRa. Since I already had a LoRa kit lying around I thought I would use that too to add some extra complexity to the project. But sadly due to the complications during the project and the time constraints the project scope got reduced even more. I realised I did not have time to make the seconds IoT device which was meant to use my OLED SSD1306 display and be connected through LoRa. So as you will see neither the SSD1306 or the LoRa-kit are part of the final solution of this project.

I think also it will be interesting to get an insight in and see how big the water usage actually is in an indoor plant over time as I never had any clue and neither could remember when was the last time a plant got watered. I constantly either overwatered or underwatered the few plants I have had. May they rest in peace.

### Material

In this project I have chosen to use the Raspberry Pico W as it was the recommended microcontroller.

List of materials.

| Picture | Component | Description | Can be bought from |
| -------------------------------------------------------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![Raspberry Pico WH](https://www.electrokit.com/uploads/productimage/41019/PICO-WH-HERO.jpg) | Raspberry Pico WH | Raspberry Pi Pico is a low-cost microcontroller board with flexible digital interfaces. This is the brain of the IoT device.| [Electrokit](https://www.electrokit.com/produkt/raspberry-pi-pico-wh/)<br/>109 SEK |
| ![Breadboard](https://www.electrokit.com/uploads/productimage/10160/10160840.jpg)| Breadbord (full-size)| Solderless Breadboard 840 tie-points. Used to simplify the connection of the sensors and LCD with the microcontroller. | [Electrokit](https://www.electrokit.com/en/product/solderless-breadboard-840-tie-points-2/)<br/>69 SEK |
| ![Jumper wires](https://www.electrokit.com/uploads/productimage/41003/41003181-600x450.jpg)     | Jumper wires | Jumper wires in assorted lengths and colors. Used to connect the sensors and LCD with the microcontroller. | [Electrokit](https://www.electrokit.com/en/product/hook-up-wires-w-pins-for-breadboard-smooth-65-pcs/) <br/>39 SEK |
| ![Soil moisture sensor](https://www.electrokit.com/uploads/productimage/41015/41015738.jpg) | Soil moisture sensor | Sensor for measuring the moisture level in soil. The sensor works by passing a current from one leg of the sensor to the other. If the soil is dry, the resistance is high and if the soil is wet, the resistance drops. | [Electrokit](https://www.electrokit.com/en/product/soil-hygrometer-module/)<br/> 29 SEK |
| ![DHT22](https://www.electrokit.com/uploads/productimage/41016/41016347-600x450.jpg)| DHT22 temperature and humidity sensor with 4,7K-10K pull-up resistor | The DHT22 is a basic, low-cost digital temperature and humidity sensor. It uses a capacitive humidity sensor and a thermistor to measure the surrounding air.| [Electrokit](https://www.electrokit.com/en/product/temp-fuktsensor-dht22/)<br/> 129 SEK|
| ![BMP180 barometer](https://cdn-shop.adafruit.com/970x728/1603-04.jpg) | BMP180 Barometric Pressure/Temperature/Altitude Sensor | A high precision barometer, with I2C interface. Used for measuring temperature and air pressure. | [Adafruit](https://www.adafruit.com/product/1603)<br/> $9.95|
| ![LCD display](https://cdn-shop.adafruit.com/970x728/181-06.jpg) | Standard LCD 16x2 | Standard HD44780 LCD. 16 characters wide, 2 rows. Used for letting the IoT device display the latest sensor readings. | [Adafruit](https://www.adafruit.com/product/181)<br/>$9.95|
| ![I2C interface for LCD](https://www.electrokit.com/uploads/productimage/41016/41016214-600x450.jpg) | I2C interface for LCD | Serial converter for alpha-numeric LCD modules with parallel interface. The module provides a simpler way to interface with the LCD. | [Electrokit](https://www.electrokit.com/en/product/i2c-interface-for-lcd-2/)<br/>39 SEK|

### Computer setup

The IoT device was developed on a PC with Windows 10 operating system. The main IDE  used was Visual Studio Code but also Thonny was occasionally used. VS Code has the Pymakr extension which is very useful when developing with Micropython. It has the automatic sync feature which is constantly used when doing changes in the program code. It automates the uploading of updated code to the Raspberry Pico which else would be a very repetitive manual task. Thonny IDE was used occasionally when I wanted to test some separate program code snippet in a separate environment. I found this to be a much smoother way of doing it than trying to have separate programs in VS Code Pymakr extension. Pymakr could be a little cumbersome to use and wasn't always very stable. But I think the advantages topped the disadvantages so I choose to use VS Code as the main IDE. It also got better over time as I got more used to the Pymakr extension.

To get started the following software needs to be installed:
* [Download and install Node.js (Link)](https://nodejs.org/en/)
* [Download and install Visual Studio Code IDE (Link)](https://code.visualstudio.com/Download)
* Add the Pymakr extension to VS Code IDE
    * In VS Code IDE open the Extensions manager from the left panel by clicking the "Extensions" icon or open it via the menu "View" > "Extensions".
    * Find the Pymakr extension and install it. Follow the numbered steps in the picture:
![](https://hackmd.io/_uploads/HkxG-ArU3.png)

The Raspberry Pico W microcontroller should first be updated with the latest firmware.
Latest firmware can be found and downloaded from [here (Link)](https://micropython.org/download/rp2-pico-w/).
The firmware is updated by first connecting the Raspberry Pico W to the PC with a USB-A to micro-USB cable. If the PC does not automatically detect the Raspberry Pico as a new USB storage device try to disconnect and reconnect the USB cable again while pressing the BOOTSEL button on the Pico board. This is normal and is required e.g. if the Pico already has a firmware applied.
Once detected by Windows the Raspberry Pico will show up in the file explorer as a new USB storage device named RPI-RP2. In the file explorer drag and drop the new uf2 firmware file to the RPI-RP2 USB storage device. Once the file is uploaded the Pico will automatically reboot and apply the new firmware. When the new firmware has been applied the Pico will no longer be detected by Windows as an USB storage device unless the BOOTSEL button is pressed when connecting the USB cable.

### Putting everything together

Pinout scheme for Raspberry Pico W can be found [here (Link).](https://datasheets.raspberrypi.com/picow/PicoW-A4-Pinout.pdf)

IoT Device Fritzing diagram:

![](https://hackmd.io/_uploads/rJxs-1MF3.png)

In the Fritzing diagram above all the connecting jumper wires can be seen.

Communication with the DHT22 sensor is done through digital GPIO pin 13. The DHT22 is powered by 3,3V. The DHT22 data pin is connected to 3,3V via a 4,7kΩ pull-up resistor. The recommended range for this resistor is from 4.7kΩ to 10kΩ.

Communication with the BMP180 sensor is done through I2C bus GPIO pins 14 and 15. The BMP180 is powered by 3,3V.

Communication with the soil moisture sensor is done through analogue GPIO pin 26. The sensor is powered by 3,3V.

Communication with the LCD1602 display is done through I2C bus GPIO pins 20 and 21. The LCD is powered by 5V.

#### Power consumption

The power usage of the components are approximately the following:

| Component            | Active power | Standby/Idle | Min (V) | Max (V)|
| -------------------- | ------------ | ------------ | ------- | ------ |
| [Raspberry Pico W](https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf)     | 91,6 mA      |              |   1,8   |   5,5  |
| [BMP180](https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf)               | 5 µA       | 0,1 µA       |   1,8   |   3,6  |
| [DHT22](https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf)                | 1,1 mA       | 40-50 µA       |   3,3   |   5,5  |
| [Soil moisture sensor](https://cdn.shopify.com/s/files/1/1509/1638/files/Bodenfeuchte_Sensor_Modul_Datenblatt.pdf) | 15 mA        | -            |   3,3   |   5    |
| [LCD 1602A](https://www.openhacks.com/uploadsproductos/eone-1602a1.pdf)              | 1,1 mA       | ??? µA       |   2,2   |   5    |

Total power usage for IoT device:
:::info
91,6 mA + 0,005 mA + 1,1 mA + 15 mA +  1,1 mA = approx. 110mA
:::
Powering the IoT device with a 2000 mAh battery the IoT device could run for:
:::info
2000 mAh / 110 mA = approx. 18,2 hours.
:::

### Platform

Initially my plan was to go for a self-hosted solution by the simple reason that I expected to learn more if I had full controll of the different parts. I started working quite late on this part of the project so things started to get stressful when things didn't go well. I tried both the TIG-stack route and the Eclipse Mosquitto & Node-Red route but ran into problems. For example, I installed Mosquitto and managed to connect to Mosquitto with MQTT Explorer. But even after a lot of troubleshooting I wasn't able to connect to Mosquitto with my Micropython code. In the end I had to scrap the self-hosted solution too from my project scope due to time constraints. In the final days of the project I decided to instead prioritize completing the mandatory requirements of the project to be able to finish the course in time. A little disappointing but there is a time after this course too when I will try to work on the missing pieces. :)
The final solution for the IoT device ended up connecting to Adafruit IO platform and using the MQTT protocol and Webhooks. The Adafruit IO is a low-code solution which I found was very useful to quickly get things integrated and up and running. I used the free subscription which was limited but good enough for this small project. The free version of Adafruit IO has a 1KB storage limit for each data feed and 10 feeds is allowed. One feed is needed for each sensor/data source.


### The code

The full complete code including the necessary sensor libraries can be found in [Github (Link)](https://github.com/FANTEN78/23st-1dt305-iot-project)

In my boot.py file I put the code for setting up the WiFi connection as the boot.py is the first code that gets executed. I wanted device to connect to the WiFi before main.py and the rest of the code gets executed. The WiFi hotspot SSID and the password is stored in the separate config file named secrets. It make it easier to change configuration if it is kept in a separate file.
```python=
def do_connect():
    wlan = network.WLAN(network.STA_IF)         # Put modem on Station mode
    if not wlan.isconnected():                  # Check if already connected
        print('Connecting to network...')
        wlan.active(True)                       # Activate network interface
        wlan.config(pm = 0xa11140)              # Set power mode to get WiFi power-saving off (if needed)
        wlan.connect(secrets["ssid"], secrets["password"])  # WiFi Credential
        print('Waiting for connection...', end='')
        # Check if it is connected otherwise wait
        while not wlan.isconnected() and wlan.status() >= 0:
            print('.', end='')
            sleep(1)
    elif wlan.isconnected():
        print("Already connected.")
    # Print the IP assigned by router
    ip = wlan.ifconfig()[0]
    print('\nConnected on {}'.format(ip))
    return ip 
```

In the following code from main.py file the MQTT connection to Adafruit IO is set up. Adafruit IO is where the IoT device later will send the sensor data.
```python=
# Use the MQTT protocol to connect to Adafruit IO
client = MQTTClient(secrets.AIO_CLIENT_ID, secrets.AIO_SERVER, secrets.AIO_PORT, secrets.AIO_USER, secrets.AIO_KEY)
client.connect()
print("Connected to %s" % (secrets.AIO_SERVER))
```

In the following code I initialize the LCD1602 display. The LCD is used to show the latest sensor readings. At program start the two line display will first show a start up text saying "IoT project" on the first line and "23ST-1DT305", which is the IoT course code, on the second line. The last line of code adds a 2 second sleep paus to give enough time read the display before it gets overwritten by the sensor data.
```python=
### Initialize LCD1602 display
lcd1602_i2c = I2C(0, sda=Pin(20), scl=Pin(21), freq=400000)
I2C_ADDR = lcd1602_i2c.scan()[0]
lcd = I2cLcd(lcd1602_i2c, I2C_ADDR, 2, 16)
# Empty the LCD display(in case there is something left from previous execution) and then display a start text
lcd.move_to(0,0)
lcd.putstr("                                ")
lcd.putstr("  IoT project  ")
lcd.move_to(0,1)
lcd.putstr("  23ST-1DT305  ")
utime.sleep(2)
```

The following code show the reading from the DHT22 sensor. The sensor data gets formated before it is published to Adafruit IO using the MQTT protocoll. Together with the DHT22 sensor data the MQTT topic is also transferred.
The same data is also printed to the terminal and the LCD display.

```python=
  # DHT22 sensor measurement
  DHT22_sensor.measure()
  DHT22_temp = "{:.1f}".format(DHT22_sensor.temperature())
  publish_data(DHT22_temp, "fanten/feeds/dht22_temperature")
  DHT22_humidity = "{:.1f}".format(DHT22_sensor.humidity())
  publish_data(DHT22_humidity, "fanten/feeds/dht22_humidity")
  print("DHT22: Temp: " + str(DHT22_temp) + "C, Humidity: " + str(DHT22_humidity) + "%")
  # Empty the LCD display and then display the new sensor values
  lcd.move_to(0,0)
  lcd.putstr("                                ")
  lcd.putstr("DHT22: " + DHT22_temp + "C")
  lcd.move_to(0,1)
  lcd.putstr("Humidity: " + DHT22_humidity + "%")
  utime.sleep(3)
```

### Transmitting the data / connectivity

The sensor data is read and published in a 60 second interval. I choose that interval based on that this was a development learning project but at the same time I don't want to spam the Adafruit IO with my data too often. They have some limit for how often data can be sent and there is a risk that my data transfer will be blocked if sending data too often. In a self-hosted platform this limit would not apply as it would be up to you to decide what you think is suitable. On the other hand there might still be good reasons for limiting the data transfer in a self-hosted platform too. E.g. some types of storage devices does not like to be written to too often as it will limit its lifespan. In a battery powered device you would like to keep the power usage to a minimum and one way of doing this would be to transfer data less often.
As this is an IoT device which can be used to monitor the environment of an indoor plant I think much less frequent sensor readings would be fine. Even as seldom as daily readings would be just fine as the changes in plant environment from day to day are so small and would not lead to any risk to the plant. If, as an example, it instead was an IoT device that was used for e.g. detecting a liquid overflow that could cause damages then it would of course be critical to have very frequent sensor readings to have as early detection as possible.

The device is using a WiFi connection to transfer the data and the MQTT transport protocol to send the data to Adafruit IO where it is stored and can be visualized. To get the alerts sent to the Discord channel once a threshold is exceeded I used Webhooks.


### Presenting the data

Adafruit IO wasn't my first choice of database. As mentioned earlier in the report my original plan was to run a self-hosted solution. Instead Adafruit came into the picture once I realized I would not be able to either complete my project in time or write the mandatory report if I continued with troubleshooting the problems I had with the self hosted solutions. Once I gave Adafruit a try it turned out to be a very simple and userfriendly solution to my project need. I could quickly and with almost no problem integrate my IoT device with Adafruit and decided to use it as the platform of project.

In Adafruit IO the sensor data can be visualized in different types of graphs. Data from different sensors is collected in separate feeds as seen in the picture below. I set up separate feeds for each sensor data. This is how the data is grouped and allows for visualising historical data in graphs.
![](https://hackmd.io/_uploads/SJTw7RzFn.png)


As I am using the free version of Adafruit IO there is a 1 KB data storage limit for each data feed and maximum 10 feeds can be used. I have one feed set up for each of my sensor readings which means that I use 5 feeds. In the case of the DHT22 sensor it measures both temperature and humidity. I have set up separate feeds for each of the temperature and humidity data readings.

As an example, the following picture shows how the temperature data from the DHT22 sensor can look as a graph in Adafruit IO. Note that this graph contains very frequent sensor readings in the beginning and it is easy to spot when I held my finger on the sensor to provoke a higher temperature reading.

![](https://hackmd.io/_uploads/r1S3rbzKh.png)
To send alerts when a certain threshold is exceeded I choose to set up a threshold for the DHT22 temperature data. Once the data exceeds 25 degrees Celsius an alarm is sent to my Discord channel using Webhooks.
![](https://hackmd.io/_uploads/HkKnEAzY2.png)




### Finalizing the design

![](https://hackmd.io/_uploads/r1TzIzGY3.jpg)

Now in the end I think the project went fine after all. I'm a little disappointed that I could not implement the features I had hoped to do in my original plan. But I feel that I have learned a lot and with the gathered insights, knowledge and experience it will be much easier to continue learning more about the IoT and to dig deeper into the different areas. Due to the many problems I have run into during the project it was easy to identify what areas I must learn more about and what possibilities and benefits that comes with them.
Just to mention two. Mastering how to use threads in Micropython would allow smooth usage of different functions in parallel. As an example, I found a cool feature online which I tried to implement into my project. The IoT device would listen to incoming HTTP connections and once connected it would respond with a generated webpage containing the latest sensor readings. I thought this would be useful in my project as my IoT device is using a WiFi connection. A PC or mobile phone on the same WiFi network would have been able to get the latest sensor readings just by opening the IoT device IP address in a web browser. But I was not able to make it work nicely as my program got stuck while listening to incoming connections and stopped doing the sensor readings while waiting. I tried to solve this by using threads but it didn't work well and I instead lost a lot of time. In the end I had to scrap this part too from the project scope as my focus shifted to prioritizing to complete the project before deadline.
I will also try again to get a self-hosted platform up and running as it allows you to customize things the way you want it. The low-code IoT platform solutions are good in the way that they get you up to speed fast. Very useful to make a early prototype of your data gathering device. But at the same time I think the low-code IoT platform solutions are also limited.


Demonstration video:

<iframe width="700" height="410" src="https://www.youtube.com/embed/py_4XojzwsA" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>