Easy climate monitoring using a Raspberry Pi

Michael K
8 min readFeb 21, 2022

--

Raspberry Pi Zero WH with an AHT20 Sensor attached and hooked up
The final product assembled

One of my favorite things about the single-board computer scene is the abundance of boards, sensors, and devices available to do almost anything a hobbyist would ever want to do. This abundance came in handy when trying to determine what the actual climate was inside of my home versus what was reported by my thermostat. (And not at all to have evidence when complaining to my girlfriend it was too warm!)

Requirements

While these exact requirements aren’t necessary, they are very user-friendly especially for beginners as no soldering is required. Which operating system you choose is ultimately up to you, however, the default Raspbian works well and includes Python 3 out of the box.

Getting Started

Using nylon standoffs and nuts, or your method of choice, mount the sensor to the Raspberry Pi. I elected to put mine on the side furthest away from the processor for the most accurate readings.

An AHT20 sensor attached via a nylon standoff to the Raspberry Pi Zero WH

Once attached, we can connect the Qwiic cable to the sensor (either side) and then plug the female ends into the I2C pins on the GPIO. Arranging your Pi with the SD card at the top and referencing the diagram below should help you determine which ones to use.

  • Red / 3.3VDC: GPIO #1 (3.3V)
  • Blue / I2C SDA Data: GPIO #3 (GPIO 2)
  • Yellow / I2C SCL Clock: GPIO #5 (GPIO 3)
  • Black / Ground: GPIO #9
An image of a Raspberry Pi Zero WH from a top-down perspective. A digital representation of the 40-pin GPIO pin layout is presented next to the image of the Pi in the same arrangement of pins as the real image. Four red lines have been drawn highlighting pins #1, #3, #5 and #9 along with the label for each pin.
Pin layout with labels (via pinxout.xyz)

I don’t recommend using an I2C shim as they are not reliable from my experience. Once connected, I also used a twist-tie on the cable so it’ll stay secure. Finally, plug in the power adapter, SD card, and monitor. You can also enable SSH and connect to the Pi remotely to work off which is much easier in my opinion.

Qwiic to Dupont pin cable leading from an AHT20 sensor and into the I2C pins on a Raspberry PI Zero WH
I2C pins connected

Software Preparation

Before getting started on any code, first ensure that the I2C interface is enabled by following these instructions. This page also includes instructions for testing I2C and ensuring the sensor can be detected.

I’ve chosen to use Python as it is heavily supported in the hobbyist electronic scene and it’s one of my all-time favorite programming languages. Adafruit has some Python libraries prepared which will make interfacing with the sensor much easier as well. We can install those libraries via Pip for example:

$ python3 -m pip install Adafruit_Blinka adafruit-circuitpython-ahtx0

Once installed, we can test them out by importing the libraries and grabbing the temperature and humidity from our sensor. The sensor returns Celsius so if you are used to Fahrenheit, like me, a simple conversion function can be added inline which I’ve included in the script below.

In a terminal, we can now run our script and test out the sensor and ensure it is working before continuing onto the next steps.

$ python3 aht20.py
Temperature 69.97 F
Humidity 39.20 %

We can now collect our climate information as it happens, but wouldn’t historical data be a lot more useful? Let’s extend our script some more to handle this additional logic.

Script Improvements

First, we’ll add a new function to our existing file called save_entry . This method will use a local JSON file to read and write new climate entries as they occur. You could also substitute this out for a database, however, I decided to keep it simple for this guide.

Let’s also install the library Click via Pip to make building a CLI quicker and handle some logic for us. We’ll only use a small part of Click today, but it has a lot of other great features that come in handy quite often.

$ python3 -m pip install click

At the top of the file, with the other imports, add the imports needed for the new save_entry method and Click as shown below.

import click
import datetime
import json
import pathlib
import sys
import traceback

Finally, let’s integrate Click with our program and add an option for the location of our sensor. We can set it to required as well so it saves us from having to add additional logic to check that.

Testing The Script

With the script saved, and I2C enabled, we should be able to test the script now. In a terminal window, navigate to the same directory as your script. You can run the script as usual, except you will need to add --location to the parameters, if you left it as a required argument.

$ python3 aht20.py --location Garage
Entry saved: 73.32 F, 37.67 % H

Checking out the entries.json file created by the script, we can see logs for every time the script has been run.

Automating The Script

Now that we have our script ready to go, we should automate the data collection so that it is done on a regular schedule automatically for us. There are a few different methods you can use to achieve this, I’ll cover the two I use most often. If you just want to follow along, I have some sample data linked in the next section if you want to skip automation.

Systemd (Recommended)

Though it takes more effort to set up, Systemd is quite a bit more robust when compared to Cronjobs. You can configure services that never end and automatically restart when crashed, or in our case, we’ll use a timer to automatically run our service at a predefined interval.

Download both files below, and move them into /etc/systemd/system . Within climate-monitor.service , edit line 7 to be the file system path where you have the script saved, such as /home/pi . If you are unsure what the exact path is, you can run pwd in the terminal to see your present working directory. Also, you’ll want to add the location label you desire to line 9. I have preconfigured the timer to run every 15 minutes, but this can be changed by modifying line 7 in climate-monitor.timer and replacing15 with the number of minutes you would prefer it to run at.

Once this is complete, run sudo systemctl daemon-reload . This will have Systemd reload and now see your newly added service and timer. You can then run sudo systemctl enable climate-monitor.timer , which will enable the timer. Once enabled, this timer will run until you disable it by running sudo systemctl disable climate-monitor.timer .

With it enabled, you can monitor the logs by running journalctl -u climate-monitor.service .

CronJob (Easier)

Take note of where you have the script saved, such as /home/pi . If you are unsure of the exact path, you can run pwd in the terminal to see your present working directory.

In your terminal, type crontab -e . This will open an interactive session where you can edit the cronjobs configured on your Pi. Skip to the end of the file, and on a blank line, add the line below which will automatically run the script every 15 minutes. You’ll want to swap out the path to the aht20.py script for the correct one as described above.

*/15 * * * * python3 /home/pi/aht20.py --id Garage &> /tmp/climate.log

At the end of this command is &> /tmp/climate.log . This statement redirects the output (and errors) to a log file which you could check to see if there were any issues.

Charting Climate History

For the final step, let’s take a look at what our climate information would look like when plotted on a graph. You can let the script run automatically for a while to collect some data before moving on to this step. Or, if you want to see lots of data, I’ve uploaded a sample entries file with 5,000 data points collected from my garage climate sensor here. We can go ahead and install the two libraries we’ll need for this section.

$ python3 -m pip install matplotlib pandas

I’ve chosen to use Matplotlib and Pandas for this task as it does not require any additional setup or packages like others. Matplotlib will provide us with an easy-to-use method to generate charts, while Pandas gives us access to straightforward and quick data analysis tools. First, let’s add the new imports we’ll need to the top of the script.

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import os
import pandas as pd

With these added, we can go ahead and add three new methods we’ll use to make charting the data easier and to handle the heavy lifting outside of our Click command. The get_entries method will retrieve all of the results based on our specified location and then average the climate per day before converting it to a DataFrame. The plot_data method is a utility function to help us plot the data without repeating too much code.

We’ll also need to rework our command structure to allow for a secondary command. Click makes this easy by using groups and this will also allow us to have separate options for each command. We’ll add a new group and assign our previous collect command to it as well as add a new command to export the chart information. Switch the function being called at the end of the script from collect() to cli() and change click.command() to cli.command() in the decorators before the collect command is instantiated, as shown below.

After making this change, we’ll have to add collect to the command anywhere we were previously using the script, like in a Systemd service or Cronjob as detailed earlier.

# New command structure
$ python3 aht20.py collect --location Garage

You can now run the export command and see a chart produced of the average temperature and humidity for each day reported in your data. If you are using my dataset, be sure to pass the location ‘Garage’.

$ python3 aht20.py export --chart-path test.png --location Garage
Chart saved to: test.png
A line graph with one axis showing the temperature in Fahrenheit and another axis showing the humidity percentage charted over the course of a month.
Chart of data collected by a climate sensor in my garage

I hope you enjoyed this guide, feel free to comment with any questions you may have!

You can find the complete script on GitHub here if you want to see the final result.

--

--

Michael K

Software Engineer with a passion for helping spread technical knowledge about my favorite hobbies from microcontrollers to automotive and much more.