ラズパイで温湿度を測定(DHT22)
Contents
ラズパイで温湿度を測定
各種センサー類をラズパイに接続してIoT化を目指しているシリーズの一つ、ラズベリーパイで温湿度を計るPythonのプログラムを作った時の備忘録。
尚、今回の記事中ではインターネットに接続をしていないのでIoT(Internet of Things)では無いがラズパイであればインターネットへは簡単に接続できる。
AWS IoT Coreへ値をアップロード(Publish)する記事を以前に書いているのでインターネットに接続する際には参考にして欲しい。
前回はRaspberryPi ZeroとRaspberryPi 3 B+でDHT11を試した。
今回はDHT11より高性能のDHT22を試したのでその時の事を備忘録として記事にしておく。
温湿度センサー(DHT22)のスペックは下記の通り。
上記の写真でも分かるがDHT22の温湿度を測定する部品(上記の白い部分)の部品番号はAM2302と表示されている。
DHT22で検索しても資料があまり出てこないのでAM2302で検索した方がより多くの情報がヒットする。
データシートはこちらを参考にした。
湿度測定範囲 |
参考までにDHT11は
となっている |
温度測定範囲 |
参考までにDHT11は
となっている |
動作電圧 | 3.3V~5V 「推奨する電圧は5Vです」とデータシートにあった |
ピン | AM2302からは4つのピンが出ている データシートによると左からVDD、SDA、NC、GND しかしDHT11と同様3つ目のNCはNot Connect(接続しない)と思われ実際モジュールからはコネクタは3つしか出ていない。 前述の画像をみても使用されている様子が無い またSDA(Serial data)はセンサーデータの読み込み、書き込み(I/O)の為のピンでRaspberryPiのGPIOに接続する |
購入について | アマゾンで899円で購入した(2019年8月) DHT11が3個で639円だったので値段は約4倍の価格だ |
dht22の制御について
DHT22(AM2302)の温度と湿度は40bitのLow(0)とHigh(1)で値を返すのでエラーチェックを行った後に温湿度へと変換をする必要がある。
このプログラミングはちょっと大変なのでDHT11と同様に誰かがPythonのモジュールをアップしてくれていないかを検索したのだがどうも見当たらない(検索の仕方が悪いのかも知れないが)
githubにDHT11、DHT22兼用のライブラリーを見つけたのだがソースがCだったので自分で色々といじる事が出来ないので(技術的にCの知識が不足しているので)見送った。
仕方が無いのでszaro氏がライブラリー化してGithubに載せてくれているDHT11向けのモジュールdht11.pyをデータシートを見ながらDHT22用に改造することにした。
変更内容
上記GithubのプロジェクトはMITライセンス(ソフトウェアを誰でも無償で無制限に扱って良い)と記載されているが元のソースコードの掲載は控えるので必要に応じてGithubを参照して欲しい。
また当初ファイル名がdht11.pyだったのだが今は__init__.pyに変更されている。
データシートを眺めた所、戻り値が40ビットの所やパリティチェックのやり方など大きな違いは見当たらなかった。
見つけた違いは、
- 最初のstart signalの秒数がDHT11のデータシートでは18ミリ秒(最大30ミリ秒以下)となっているがAM2303では0.8ミリ秒~20ミリ秒になっている
- 戻り値の先頭の32ビットの温湿度の計算方法が違う
ぐらいに思えたので、上記のgithubのdht11.pyをコピーしてdht22.pyにリネームして保存した後、以下の部分を変更した。
start signalの変更
39~40行目のstart signalでLOWをAM2303に送信する時間を0.8ミリ秒に変更した。
# pull down to low
self.__send_and_sleep(RPi.GPIO.LOW, 0.02)
# pull down to low DHT22用に調整
self.__send_and_sleep(RPi.GPIO.LOW, 0.0008)
温度、湿度の計算方法の変更
74~75行目の温度、湿度の計算方法をAM2302のデータシートの5ページ目の計算例を参考にして変更した。
湿度を例にとるとDHT11では最初の8ビットと次の8ビットを足して10進数に変換しているがDHT22では最初の8ビットを256倍した後(左に8ビットシフトしても良いと思う)、次の8ビットに加算した後で全体を10で割っている。
10で割るのは小数点以下の数字を表すため。
temperature = the_bytes[2] + float(the_bytes[3]) / 10
humidity = the_bytes[0] + float(the_bytes[1]) / 10
temperature = ((the_bytes[2]*256) + the_bytes[3]) / 10
humidity = ((the_bytes[0]*256) + the_bytes[1]) / 10
もし間違いがあれば指摘して貰えるとありがたいです。
また改造は当然だが自己責任の上で行った。
ディレクトリ構造
ディレクトリ構造は以下の通り。
プログラムと同じディレクトリ配下DHT22_Pythonディレクトリを作成してdht22.pyファイルを格納した。
├─DHT22_Python
│ __init__.py
│ dht22.py
接続について
DHT22(温湿度モジュール)とRaspberryPi 3 B+との接続は以下の通り。
プログラム
テスト用プログラムは以下の通り。
# -*- coding: utf-8 -*-
"""
Created on Sun Sep 29 09:17:11 2019
DHT22 RaspberryPi 3 B+
温度、湿度センサーのテスト
@author: Souichirou Kikuchi
"""
import RPi.GPIO as GPIO
from time import sleep
from DHT22_Python import dht22 # 温湿度センサーモジュール
TEMP_SENSOR_PIN = 4 # 温湿度センサーのピンの番号
INTERVAL = 10 # 監視間隔(秒)
RETRY_TIME = 3 # dht22から値が取得できなかった時のリトライまので秒数
MAX_RETRY = 20 # dht22から温湿度が取得できなかった時の最大リトライ回数
class EnvSensorClass: # 温湿度センサークラス
def GetTemp(self): # 温湿度を取得
instance = dht22.DHT22(pin=TEMP_SENSOR_PIN)
retry_count = 0
while True: # MAX_RETRY回まで繰り返す
retry_count += 1
result = instance.read()
if result.is_valid(): # 取得できたら温度と湿度を返す
return result.temperature, result.humidity
elif retry_count >= MAX_RETRY:
return 99.9, 99.9 # MAX_RETRYを過ぎても取得できなかった時に温湿度99.9を返す
sleep(RETRY_TIME)
GPIO.setwarnings(False) # GPIO.cleanup()をしなかった時のメッセージを非表示にする
GPIO.setmode(GPIO.BCM) # ピンをGPIOの番号で指定
#main
try:
if __name__ == "__main__":
env = EnvSensorClass()
while True:
temp, hum = env.GetTemp() # 温湿度を取得
print("温度 = ", temp, " 湿度 = ", hum, "%")
sleep(INTERVAL)
except KeyboardInterrupt:
pass
GPIO.cleanup()
実行結果
プログラムの実行結果は以下の通り。
10秒間隔で温湿度を取得してprintしているが温湿度共に0.1の単位まで表示している事が分かる。
湿度の誤差について
今回このモジュールを2つ購入したのが2つ共に温度は良いのだが湿度が若干高めに算出されるように思う。
SEIKO社、無印の温湿度計を2つ並べて比較したのだがDHT22モジュールの湿度が2つ共に常に高めに表示された。
自分のプログラムの不具合の可能性や個体差もあるのだろうが原因が分からなかったので算出後にSEIKO社の湿度計が合っているものとしてプログラム側で補正を行った。
以上で今回の記事は終了とする。
この記事が何処かで誰かの役に立つことを願っている。
尚、当記事中の商品へのリンクはAmazonアソシエイトへのリンクが含まれています。Amazonのアソシエイトとして、当メディアは適格販売により収入を得ていますのでご了承ください。
大変参考になりました。ありがとうございます。
ひねくれ草さん
コメントありがとうございます。
参考になったとのコメントを貰えると記事にしたかいがあったと思えます。良かったです。