Table of Contents
1. Introduction
1.1 Meet the DHT22: a humidity & temperature sensor
1.2 What you will learn
2. Interface your Raspberry Pi with the DHT22 sensor
2.1 DHT22: Basic circuit
2.1.1 BOM
2.1.2 Power up!
2.2 DHT22 Computer Room Environment Controller
2.2.1 BOM
2.2.2 Power up!
exentia – stock.adobe.com
The ability to EASILY sense ambient humidity in an arbitrary environment is highly prized because humidity affects the operation of innumerable human contraptions, not to mention human comfort. The dual-mode sensor we’ll work with in this article makes it perfect for Maker projects like a better HVAC, weather stations and IoT thermostats, especially when combined with the staggering amount of quality software packages available on Raspbian alone. Try this in your Pi (or Linux terminal):
1 2 3 4 5 |
wget \ http://archive.raspbian.org/raspbian/dists/stable/main/binary-armhf/Packages.xz \ -O - 2>/dev/null | xz -dfc | grep -c '^Package: ' \ | cut -d ' ' -f 2 |
… And give it a moment. It will output the number of software packages you have at your fingertips. At the time of writing, 61.487 packages are in that repository. More are added daily.
Whatever your desire, you’re most likely covered. You’ll only need to provide sensed environment data yourself, which will be easy with the examples in Section 2.
Relative humidity is best explained in the Wikipedia article on the subject. Keep in mind that RH and real humidity are two different things, as RH is dependent on temperature.
What we’re popularly interested in is the threshold values for humans and electronics. You’ll start feeling some discomfort at 35-40% RH if you exert yourself at an ambient temperature of around 25C/77F. Your electronics, especially computer systems, are more sensitive and function best between 20C/68F and 24C/75F at 45-55% RH. Too low, and ESD becomes a problem. Too high, and there’s a risk of local condensation.
An often neglected problem in some cooling philosophies is the simple fact that water molecules are perfect little buckets for thermal energy, and an air-cooled system in a 45-55% RH environment is going to be cooled considerably better than one operating in 20% RH. Humidity helps. Now you know, and you alone.
With these things in mind, let’s proceed to the hardware.
What about the hardware? Sure, an SHT85 humidity sensor rated for IP67 and margin of error at only ±1.5% RH is great, but I think we can settle for a device whose humidity sensor has a ±2-5% RH margin of
error.
The DHT22 has an onboard analog-to-digital converter, so the signals from the humidity sensor and thermistor come across nice and clean. If they don’t, the checksum will let you know. The temperature sensing is perfectly fine for Makers, with only a ±0.5C margin of error.
I bought half a dozen of these five years ago, and each has performed admirably, even outdoors (though shielded from the UV of sunlight, rainwater, and so on). The DHT22 is single-bus, neither I2C nor SPI, and while it has a voltage range of 3.3 to 6 volts, the only no-no is powering it from >3V3, which causes it to heat up and show a temperature reading that is wrong. Too high a local temperature will also shoo away moisture, so the local humidity goes off too. But that’s entirely avoidable: use 3V3, straight from your Raspberry Pi’s 3V3 pin. Its number is one.
The current draw when inactive, ~40uA, is so low that no power-saving features are strictly necessary, though if you add a DHT22 power-off during MCU sleep states, for instance, you’ll need to allow about a one second wake-up time before reading from it. When actively measuring its environment, the DHT22 draws 1.5-2.5mA of current, so it will not load up to the recommended maximum 50mA current draw from the 3V3 pin.
The minimum polling interval is defined as two seconds, though this is slightly bogus; I can poll just fine at ~350ms intervals, with a heat-up penalty after about 10 seconds — but if you need to do 10 readings quickly for some reason (median?), you can do so in just 3.5 seconds. Sweet.
The pinout, from left to right, is 1:VCC(3V3), 2:SIGNAL, 3:NC(not connected), 4:GND. You’ll want a 10kOhm pull-up resistor from Pin 2 to Pin 1.
If, and only if, you’re experiencing jitter (typically on long cable runs), add a 100nF capacitor between VCC and GND.
After reading this article, you will be capable of easily sensing relative humidity and temperature. I’ve added some helper functions to make handling the celsius-to-fahrenheit a no-googler. Having to convert these manually is always a minor pain. For your convenience, two tiny helper functions:
1 2 3 4 5 6 7 8 9 10 11 |
# Celsius to fahrenheit: F = ( C * 1.8 ) + 32 def celsius2fahrenheit( _celsius ): _fahrenheit = ( "%.2f" % (( _celsius * 1.8 ) + 32) ) return float( _fahrenheit ) # Fahrenheit to celsius: C = ( F - 32 ) * 5/9 def fahrenheit2celsius( _fahrenheit ): _celsius = ( "%.2f" % (( _fahrenheit - 32 ) * 5/9 )) return float( _celsius ) |
They’re also available in dht22_simple.py and dht22_actionable.py in Section 2.
When we’re through the simple DHT22 stuff, we’ll delve into building and operating the “DHT22 Computer Room Environment Controller” or DCREC, which is fully capable of acting on sensor data. You can use dht22_actionable.py as a template for humidity projects (based on the DHT22) and do pretty much anything if you’ve got the hardware and installation skill sets. Once you’re done reading through the python script, you’ll be well versed in GPIO output control as well.
The DHT22 is easy to please. There’s no need to deal with an I2C bus here, it’s one data pin for I/O, half-duplex if you prefer that terminology.
The datasheet tells you all you need to know about pulse lengths, intervals and so on, but if you’re more interested in getting started, first ensure your Pi is ready by following this Raspberry Pi setup guide.
When you’re ready to go, copy-paste the script below into your Raspberry Pi GUI editor (I hear good things about Pluma) and save the file as ‘rpi_prepare.sh’.
[ begin rpi_prepare.sh ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#! /usr/bin/env bash set -eu -o pipefail DEBIAN_FRONTEND="noninteractive" DEBIAN_PRIORITY="critical" DEBCONF_NOWARNINGS="yes" export DEBIAN_FRONTEND DEBIAN_PRIORITY DEBCONF_NOWARNINGS _pkg_list="pigpio wiringpi python-rpi.gpio python3-rpi.gpio rpi.gpio-common git python-gpiozero python-gpiozero-doc python3-gpiozero python-setuptools-git python3-setuptools-git python3-dev python3-pip" # Upgrade system and installed packages - uncomment where # relevant sudo apt update || echo failed to update index list #sudo dpkg --configure -a || echo failed to fix interrupted \ upgrades #sudo apt --fix-broken --fix-missing install || echo failed \ to fix conflicts #sudo apt -y --allow-downgrades --fix-broken --fix-missing \ #dist-upgrade # Install $_pkg_list sudo apt update sudo apt-get -y install $_pkg_list # Make 'pip3' bigly fresh? Yes. sudo python3 -m pip --upgrade pip setuptools wheel # Get Adafruit_DHT Python library sudo pip3 install Adafruit_DHT read -p "[?] Reboot? y/N: " _foo if [ X"$_foo" = X"y" -o X"$_foo" = X"Y" ] then echo "[!] Rebooting in 5 seconds, CTRL+C to abort ..." for i in $( seq 1 5 ) ; do echo -n . ; sleep 1 ; done ; echo sudo reboot fi |
[ end rpi_prepare.sh ]
This will install Python3’s “pip3” utility, ensure it is updated, and also ensure you’re pampered with a smattering of useful GPIO software. When you’ve copied it to your Pi, simply run it with:
1 2 3 |
bash rpi_prepare.sh |
Raspberry Pi 4 | https://www.newark.com/raspberry-pi/rpi4-modbp-4gb/raspberry-pi-4-model-b-4gb-rohs/dp/02AH3164 |
DHT22 sensor | https://www.newark.com/mcm/83-17985/dht22-temp-humidity-sensor/dp/32AC9951 |
10kOhm resistor | https://www.newark.com/multicomp-pro/mccfr0w4j0103a50/carbon-film-resistor-10kohm-250mw/dp/58K5002 |
Dupont wires | https://www.newark.com/adafruit/824/wire-gauge-28awg/dp/88W2794 |
Breadboard | https://www.newark.com/mcm/21-19082/breadboardjumper-kit-with-binding/dp/79X3995 |
Hooking it all up is straightforward. Follow the pictorial diagram below.
First, place the DHT22 on your breadboard and add the 10kOhm pull-up between Pins 1 and 2. Then wire BOARD1/3V3 to the red rail on your breadboard, BOARD6/GND, to the black rail, and BCM24/BOARD18 to Pin 2 on the DHT22. Now pull a wire from the red rail to Pin 1 on the DHT22 and another wire from the black rail to Pin 4. Then copy-paste this script into your Pi’s terminal:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
#! /usr/bin/env python3 # Demonstrate reading DHT22 sensor using the # Adafruit_DHT library # DHT22 pinout (left to right): # 1: VCC(3.3-6V) # 2: SIGNAL # 3: UNUSED # 4: GND # Notes: # - 10kOhm pull-up resistor from SIG to VCC. # - Use 3V3 for VCC, or the DHT22 will heat up. # - Indentation: 2 whitespaces per level, no tabs. import Adafruit_DHT from time import sleep p=print # Alias # Note: Use >=2000ms polling intervals _poll_interval = 2 # Seconds _dht_pin = 24 # BCM24/BOARD18 _dht = Adafruit_DHT.DHT22 def celsius2fahrenheit( _celsius ): _fahrenheit = ( "%.1f" % (( _celsius * 1.8 ) + 32) ) return float( _fahrenheit ) def fahrenheit2celsius( _fahrenheit ): _celsius = ( "%.1f" % (( _fahrenheit - 32 ) * 5/9 )) return float( _celsius ) if __name__ == '__main__': while True: ( _humidity, _celsius ) = Adafruit_DHT.read_retry( _dht, _dht_pin ) p( "Humidity => %.1f%% RH" % _humidity ) p( "Temperature => %.2fF" % celsius2fahrenheit( _celsius ), end='/' ) p( "%.2fC" % _celsius ) sleep( _poll_interval ) |
[ end dht22_simple.py ]
The output should look like the following. If there’s no output at all, you’re most likely experiencing a timeout of forever. That happens sometimes, but it’s not supposed to happen. Just press CTRL+C to break out of execution. Did you connect everything correctly?
In the screenshot, I tenderly approached my DHT22 with the nozzle of my hot air gun whilst also measuring the DHT22 with my infrared thermometer. The readings of the first affirmed the readings of the other, and vice versa. For science!
Now we’ll do something more interesting than merely observing the world through a humidity sensor and a thermistor — enter the DHT22 Computer Room Environment Controller. Its operation merits a short explanation before reading through dht22_actionable.py below. We set up two Raspberry Pi GPIO pins as outputs (BCM25/BOARD22 and BCM23/BOARD16), set up the connection to the DHT22 sensor, and then we loop through several conditions to check if our local environment meets the requirements of the universally recognized BEST HUMIDITY AND TEMPERATURE CONDITIONS FOR COMPUTING. Indeed.
Whenever either humidity or temperature is out of bounds, _humidity_led or _temperature_led will light up. But it might as well drive, for example, an IRLZ24N MOSFET or a relay driver circuit. Anything goes, use what you have.
Gather your parts, and if there’s something you don’t have, visit the links in the BOM below.
Connect everything as shown in the pictorial diagram below. Save the connections to your Raspberry Pi GPIO BCM25/BOARD22 and BCM23/BOARD16 pins for last, and the same applies to 3V3/BOARD1 and GND/BOARD6. Do not power up the circuit until your Pi is ready to run the program, and double-check your connections. When you’re confident they’re OK, supply power and execute dht22_actionable.py thus:
1 2 3 |
python3 dht22_actionable.py |
[ begin dht22_actionable.py ]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 |
#! /usr/bin/env python3 # Install prerequisite packages & Adafruit_DHT library """ #! /bin/sh _pkg_list='python3-setuptools python3-pip python3-dev python3-rpi.gpio' sudo apt-get -y install $_pkg_list sudo python3 -m pip --upgrade pip setuptools wheel sudo pip3 install Adafruit_DHT """ # # Ensure operating conditions in a # datacenter (your basement) are # within SAFE OPERATING HUMIDITY- AND # TEMPERATURE THRESHOLDS FOR OPTIMAL # COMPUTING CONDITIONS. # # Will fire BCM25/BOARD22 if humidity is # out of bounds, and BCM23/BOARD16 if # temperature is out of bounds. # # Uses RPi.GPIO Adafruit_DHT library, # tested on Raspbian, Dec. 2019 # # DHT22 pinout (left to right): # 1: VCC(3.3-6V) # 2: SIGNAL # 3: UNUSED # 4: GND # Notes: # - 10kOhm pull-up resistor from SIG to VCC. # - 330ohm resistors in series with RPi # GPIO pins and ROHM SLR343BC4TT32 # 3mm LEDs. # - Use 3V3 for VCC, or the DHT22 will # heat up. # - Indentation: 2 whitespaces per level, no # tabs. import Adafruit_DHT from time import sleep import RPi.GPIO as GPIO import atexit GPIO.setwarnings( True ) # Use BCM pin numbering instead of BOARD GPIO.setmode( GPIO.BCM ) _humidity_led = 25 # BCM25/BOARD22 _humidity_lower_threshold = 45.0 _humidity_upper_threshold = 55.0 _temperature_led = 23 # BCM23/BOARD16 _temperature_lower_threshold = 20.0 # 20C/68F _temperature_upper_threshold = 24.0 # 24C/75F _poll_interval = 2 # Use intervals >=2secs _dht_pin = 24 # BCM24/BOARD18 _dht = Adafruit_DHT.DHT22 _debug = True p=print # Alias if _debug: p( "[!] Setting up pin BCM_%i as OUTPUT for humidity LED ..." % _humidity_led ) p( "[!] Setting up pin BCM_%i as OUTPUT for temperature LED ..." % _temperature_led ) GPIO.setup( _humidity_led, GPIO.OUT ) GPIO.setup( _temperature_led, GPIO.OUT ) def exit_cleanly(): print( "[!] Cleaning up and exiting ..." ) GPIO.setwarnings( False ) GPIO.cleanup() exit() def celsius2fahrenheit( _celsius ): _fahrenheit = ( "%.1f" % (( _celsius * 1.8 ) + 32) ) return float( _fahrenheit ) def fahrenheit2celsius( _fahrenheit ): _celsius = ( "%.1f" % (( _fahrenheit - 32 ) * 5/9 )) return float( _celsius ) # Call exit_cleanly on normal exit and CTRL+C/KeyboardInterrupt/foo atexit.register( exit_cleanly ) if __name__ == '__main__': while True: ( _humidity, _celsius ) = Adafruit_DHT.read_retry( _dht, _dht_pin ) if _debug: p( "[+] Humidity => %.1f%% RH" % _humidity ) p( "[+] Temperature => %.1fC" % _celsius, end='/' ) p( "%.1fF" % celsius2fahrenheit( _celsius ) ) # Let's be neat _humidity = float( "%.1f" % _humidity ) _celsius = float( "%.1f" % _celsius ) # Humidity too high? if _humidity > _humidity_upper_threshold: p( "[!] Humidity %.1f%% RH exceeds upper threshold value of %.1f%% RH" % ( _humidity, _humidity_upper_threshold ) ) # Take decisive action! GPIO.output( _humidity_led, 1 ) # Humidity too low? elif _humidity < _humidity_lower_threshold: p( "[!] Humidity %.1f%% RH is below lower threshold value of %.1f%% RH" % ( _humidity, _humidity_lower_threshold ) ) # Take decisive action! GPIO.output( _humidity_led, 1 ) # Safe operating humidity? elif _humidity <= _humidity_upper_threshold and _humidity >= _humidity_lower_threshold: GPIO.output( _humidity_led, 0 ) # Safe! # Temperature too high? if _celsius > _temperature_upper_threshold: p( "[!] Temperature %.1fC/%.1fF exceeds upper threshold value of %.1fC/%.1fF" % ( _celsius, celsius2fahrenheit( _celsius ), _temperature_upper_threshold, celsius2fahrenheit( _temperature_upper_threshold ) ) ) # Take decisive action! GPIO.output( _temperature_led, 1 ) # Temperature too low? elif _celsius < _temperature_lower_threshold: p( "[!] Temperature %1.fC/%.1fF is below lower threshold value of %.1fC/%.1fF" % ( _celsius, celsius2fahrenheit( _celsius ), _temperature_lower_threshold, celsius2fahrenheit( _temperature_lower_threshold ) ) ) # Take decisive action! GPIO.output( _temperature_led, 1 ) # Safe operating temperature? elif _celsius <= _temperature_upper_threshold and _celsius >= _temperature_lower_threshold: GPIO.output( _temperature_led, 0 ) # Safe! sleep( _poll_interval ) |
[ end dht22_actionable.py ]
Your output should not look like the output in my terminal below. Blowing a hot air gun at 450C/842F across a small metal bowl full of water proves the DHT22 Computer Room Environment Controller (DCREC) ready for neatly correct behavior. For your applications, make sure the GPIO pins are connected to something great, like MOSFETs driving relays or dual bullhorns. Take action!
Below you can see my breadboard. On the bottom right, the DHT22 performs dutifully, reporting in digitally to my Raspberry Pi. On the top middle, the two LEDs are warning me that my desktop computing is not within the bounds of optimal operation.
I am shocked and astounded.