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
- Raspberry Pi Zero WH
- Adafruit AHT20 Sensor with Qwiic
- Qwiic to 4 female headers cable
- Micro-SD Card with Raspbian preinstalled
- Standoffs and other mounting hardware
- Power supply for the Pi Zero
- Python 3
- Some basic knowledge of Linux (editing files, moving files, etc.)
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.
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
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.
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
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.