16 August 2015

Measuring Humidity and Temperature Using a Raspberry Pi

I have a collection of old books and a basement to store them in. But in fact, I don't do that yet, because I had a suspicion that storing them there would not be healthy to the books. Old books and too much humidity don't go well together, especially if you want to keep the books in a pristine condition.

I could, of course, just go to the nearest builders merchant and get a cheap hygrometer for something like €7-15. But I wanted to track the humidity level over a period of at least a week, to see if factors like day/night conditions and changing weather (not to mention the tumble dryer in the next room) have any measurable effect on the level of humidity in the basement room.

Therefore I decided to build a humidity and temperature meter with logging capability from a Raspberry Pi and a few bits of electronics.

The device logs temperature and relative humidity to a csv file which makes it easy to import the log file into a spreadsheet or similar, and in turn have nice graphs and charts with all the bells and whistles that I like to have.

The Parts and Pieces I Used

Most of the electronic parts I found on Ebay, but your local electronics store should also have most, if not all of them.

  • A Raspberry Pi – I used a Pi 1 B+ but any model will do – with a fresh install of Raspbian on it.
  • The DHT22 temperature and relative humidity sensor.
  • A single 10 ㏀ resistor ¼W, unless it comes with the sensor. They usually come in bulks of a LOT, so you might want to get an assortment kit with resistors of many different Ω values now that you're at it.
  • A 4×20 character LCD display with an I2C board attached to it. The I2C board is an extra, small printboard which is soldered onto the display's own printboard, and which lets you have only four connecting pins instead of the LCD board's own 16 pins.
  • A Bi-Directional Logic Level Converter to convert from 5V to 3.3V. Two channels are enough, although mine has four channels. They might also look slightly different, but they're essentially the same. Just make sure you get an assembled one, unless you feel like soldering the pins to the board yourself.
  • Some assorted jumper wires – get both some male-males, some male-females, and possibly some female-females. And save yourself some trouble and get the ones with square plugs, not round ones.
  • A breadboard – a small one will do fine.

The Raspberry Pi's GPIO pins

Pi 1 B+ and later models have more
GPIO pins than the older models,
but the first 26 pins are the same.

I hooked everything up via a breadboard so that I didn't have to solder anything, but if you want to make this into a more permanent solution, you might want to solder everything up and put it in a nice box.

We will need to use the Pi's GPIO pins. Raspberry Pi 1, rev A and B have a 26 pin GPIO, while Pi 1, rev B+ and Pi 2 have a larger 40 pin GPIO, both located at the long edge of the board with pin 1 and 2 towards the corner. The first 26 pins are exactly the same on all Pi boards, and since we don't use any of the "extra" pins, the setup is the same no matter which Pi you have.

Hooking up the DHT22 Sensor

The DHT22 is a very inexpensive sensor that can be attached to an Arduino or a Raspberry Pi. With it you can read the current temperature and relative humidity percentage from your own Python scripts.

Hooking it up to the Pi is quite simple. The DHT22 sensor have four pins. Pins 1, 2 and 4 are connected to pins on the Raspberry Pi's GPIO, while pin 3 is not used. You will need to put a 10 ㏀ resistor between pin 1 and 2 on the DHT22. Here are the details:

DHT22 Raspberry Pi
Pin 1 (3.3 V) Pin 1 (3.3 V)
Pin 2 (data) Pin 7 (GPIO4)
Pin 4 (GND) Pin 9 (GND)
Put a 10 ㏀ resistor between the data line and the 3.3 V line

Below is a diagram of how I hooked it up via a breadboard. You'll notice I connected the Pi's ground (GND) pin to the "minus" rail on the breadboard which will allow me to better connect the GND pins of more components later on without having more cables going to the Pi. Actually I didn't connect wires to the sensor and the resistor like the diagram suggests; I just plugged them directly into the breadboard.

Hooking up the LCD Display

The LCD display is capable of showing four rows of 20 characters and when connected to your Pi, you will be able to send text to it from your Python scripts. This particular one has an i2c board attached which means we can connect it to the Pi in a relatively simple manner.

In order to connect it to the Pi, we will have to use a logic level converter, because the Pi has 3.3 V logic while the display uses 5 V. The converter must go in between the Pi's GPIO and the LCD. Here are the details:

LCD display Converter Raspberry Pi
LV 3.3 V

Since the converter fits right onto the breadboard, the far easiest thing to do is to just plug it right on there. On the breadboard diagram below you will notice that again I use the minus rail for ground, so in this entire setup, I have only one wire going to a GND pin on the Pi.

Enlargements of the pins of the I2C board on the display (left) and the converter (right).

Installing APIs and Software

When you have everything connected, it's time to boot up your Raspberry Pi. With a running Raspbian, open a terminal window (or SHH into the Pi from another computer), as we will install the necessary software by text commands.

First up, we will install some dependencies:

sudo apt-get update
sudo apt-get install build-essential python-dev python-smbus i2c-tools

Then, we will download and install the Adafruit Python DHT library which will enable us to write Python code that reads temperatures and humidities from the DHT22 sensor:

git clone https://github.com/adafruit/Adafruit_Python_DHT.git
cd Adafruit_Python_DHT
sudo python setup.py install

As for preparing the display, the process is slightly longer. First, we will make sure that the required modules are read on system boot. We do that by loading the file /etc/modules in our favourite text editor. In this example it's the text based, but easy to use, editor nano, but if you have the Pi running with a graphical environment, you may want to change "nano" into "gedit" to get a graphical editor:

sudo nano /etc/modules

Add the following two lines, then save the file and exit the editor:


Now, reboot the Pi and then start up the terminal again:

sudo reboot

Load the following blacklist file in an editor. There is a line "blacklist i2c-bcm2708" -- put a # in front of that line, save the file and exit:

sudo nano /etc/modprobe.d/raspi-blacklist.conf

Again, reboot the Pi and then start up the terminal:

sudo reboot

Now, we need a couple of driver files for the display. I put them in a file archive which you can download for convenience. Create a directory that will contain this, change to it, download the archive file and decompress it like this:

mkdir ~/temperature
cd ~/temperature
wget http://pryds.eu/files/temperature.tar.gz
tar -zxvf temperature.tar.gz

You'll see that I also put my Python script called "temperature.py" -- which polls the sensor and writes its output to screen and to the display -- into the archive file. We're almost ready to run this script, but first we need to make sure that we use the correct I2C address for the display. Now you must run ONE of these two commands, depending on whether your Raspberry Pi is Rev 1 or Rev 2:

sudo i2cdetect -y 0 #if your Pi is Rev 1
sudo i2cdetect -y 1 #if your Pi is Rev 2

By doing this, you will get an output similar to this:

$ sudo i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 3f 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

From this you can see that I have a device with address 1b which is in use ("UU" denotes this), while the display is at address 3f. Your device might use another address. If in doubt, this should be noted in your display's spec listings.

We will need to tell the lcddriver at which address it can write to the display, so open up lcddriver.py in your favourite editor:

nano lcddriver.py

Then scroll just a bit down to the line that says "ADDRESS = 0x3f", and if you found that your display's address was anything else than 3f, you need to change "3f" into that address at this line. Then, save and exit the editor.

Now you should be able to run the Python script and let it query the sensor and give you the current temperature and relative humidity:

sudo ./temperature.py

You can stop the script by pressing Ctrl+C in the terminal.

Letting the script start automatically with the Pi

In order to make this a headless setup, we need to make sure that the script is started every time the Pi starts up. Also, if the script is to run automatically without a screen (other than the display) attached to the Pi, we would need a small "launcher" shell script that runs the Python script properly, while it redirects screen output to a file (templogs.csv) for you to grab later and feed into e.g. a spreadsheet for nice graphs, etc. Therefore, create such a shell script in your editor:

nano launcher.sh

And then paste the following lines into that new file (assuming your username is "pi" and the directory you created above was "temperature" as suggested):

cd /home/pi/temperature
sudo ./temperature.py >> templogs.csv

Now, mark the new script file as executable:

chmod a+x launcher.sh

Now we need to tell the operating system that this launcher file needs to be executed at every system startup. We will let cron handle this -- a system that runs on all Linux systems, letting users run programs and scripts at specific incidents or times. Add such a "crontab job" by executing the following command, which will in turn start up your default editor (probably nano):

sudo crontab -e

Scroll down to the end of the file and on a new line write the following:

@reboot sh /home/pi/temperature/launcher.sh >/home/pi/logs/cronlog 2>&1

Save and exit the editor, and you're ready to reboot the system and see your Pi automatically start logging temperature and relative humidity every time you boot it. For a quick reboot, do:

sudo reboot

The Log File

As mentioned, the launcher.sh script will redirect output to a csv file on the format "date/time;temperature;humidity", i.e. three fields separated by semicolons, each entry on a new line. Temperature is in degrees Celcius (°C).

As for my own basement, I discovered that relative humidity there might actually be slightly too high. Generally it sits in the high 50es percent, whereas apparently experts recommend 30-50% for storing books. So this means that I will probably have to do something about it, if I follow through on my plans on actually storing books there.

Future Add-ons

Although I think this project was fun to build, there is a lot of potential for future add-ons. Here are just a few that I thought of.

  • Put everything in a nice box and solder everything up.
  • Add a switch that would gracefully close down the system for headless systems without network connection.
  • Add a UV light sensor to the mix. Books can be really badly damaged by direct exposure to light, and especially by UV light. This is why sunlight, in particular, can easily fade book covers.

If you liked the tutorial, please consider donating an amount of your choice, to the Bitcoin address or using the PayPal button to the right.

Disclaimer: Use this guide at your own risk. The author of this guide is in no way responsible for any damage to you or your hardware that might occur from following this tutorial. Please note, that this is a description of what I did to make it work; not how it will work for you.


  1. Nice work! Have you found the DHT22 sensor to be accurate? I've noticed mine always shows higher humidity values than the 'official' weather stations in my area. An another question, why did you run your python script from an bash script like this, it is easy to make an init launcher and have your script run as a linux daemon.

    1. Remember that humidity can change a lot within relatively short distances. So if your nearest weather station is just a few km away, the actual humidity there can easily differ from where you are. That said, the DHT22 is NOT extremely accurate. I bought a few DHT22 units, and if I run one of them, then switch to another, both temperature and humidity can jump by a few degrees/percentage points. If you need a higher level of precision, what you can do is to build a setup with several sensors, and then calculate an average of the readings. Perhaps I should add that as a "future add-on" :-)

      And why did I run my python script from a bash script? Yes, it probably just makes things more complicated. I guess it was just an easy way to have the script print to screen while testing, and to a file while when run as headless. It should not be hard to have the python script write directly to file instead, which I should probably have it do in the future.

      Regarding init launcher/daemon or crontab, it is probably just a matter of taste. I like using cron in tutorials like this, because with Linux in general (not just on the Pi), there are different init systems that are handled differently, although different distributions do slowly seem to be headed in the same direction. With cron it's the same, no matter the distro.

  2. It’s amazing in support of me to truly have a web site that is valuable meant for my knowledge.