温度湿度センサDHT11・DHT22をArduino・ESP32・ラズパイで使う

つかうもの

はじめに、この記事で「つかうもの」をご紹介します。

温度湿度センサDHT11・DHT22

DHT11とDHT22は、空気中の温度と湿度を同時に測定することができるデジタルセンサです。通信方法はSPIやI2Cでもなく、1-wireで行う独自の通信になってます。Arduinoやラズパイではライブラリがありますので簡単に扱える様になってます。

DHT11よりDHT22のほうが、測定範囲が広く、測定精度も良いです。DHT22の扱い方も、DHT11とほとんど変わりありません。DHT22のほうがお値段が若干高めですが、長い目で見るとDHT22をおすすめしておきます。実際に仕事ではDHT22をメインに使ってます。

項目DHT11DHT22
電源3V~5V3V~5V
湿度20~80%(5%)0~100%(2.5%)
温度0~50℃(±2℃)-40~80℃(±0.5℃)
測定レート毎秒1回毎秒2回

▼ DHT11、DHT22のデータシート DHT11 Product Manual - 秋月電子通商 DHT22(AM2302)Product Manual - 秋月電子通商

DHT22センサは色々売られてますが、こちらの製品はセンサとプルアップ抵抗が基板にはんだ付けされており、ピン端子が出ているので使いやすかったです。

マイコンボード

この記事では、Arduino Uno・ESP32・Raspberry PiでDHT22やDHT11を扱う方法をそれぞれ解説いたします。お好きなマイコンボードをお使いください。

もしもまだArduinoをお持ちでないようでしたら、こちらの記事をご覧ください。

その他の電子部品

4.7kΩの固定抵抗を使いますので、あわせて用意してください。また、ブレッドボードやジャンプワイヤをお持ちでない方は、揃えてください。

開発環境

項目バージョン
Arduino IDE1.8.10
パソコンmacOS Big Sur 11.0.1

Arduino UnoでDHT11を使う

Arduino UnoでDHT11を使う
Arduino UnoでDHT11を使う

Arduino UnoでDHT11を使う方法を解説してきます。

Arduino IDEにDHT11ライブラリをインストール

Arduino IDEでDHT11ライブラリをインストールします。次の手順にしたがって、Adafruitの DHT sensor libraryAdafruit Unified Sensor をインストールします。

Arduino IDESketchInclude Library へ進み「dht」および「Adafruit Unified Sensor」で検索してライブラリをインストール。

DHT sensor libraryのインストール
DHT sensor libraryのインストール
Adafruit Unified Sensorのインストール
Adafruit Unified Sensorのインストール

▼ Adafruitのライブラリの詳細はこちらから。 Using a DHTxx Sensor | DHT11, DHT22

DHT11のピン端子役割

DHT11のピン端子役割
DHT11のピン端子役割

DHT11から湿度や温度を読み取るには、DATAピンでデータのやりとりを行います。VDDは3V〜5Vの範囲で使用できます。また、NCピンは使いませんので何も接続しません。

DHT11とArduinoの配線

DHT11とArduinoの配線の配線図です。VDDは5Vと3.3Vのどちらでも構いません。また、NCには何もつなぎません。

DHT11とArduinoの配線図
DHT11とArduinoの配線図

DHT11Arduino Uno
VDD5V
DATAD2
NC--
GNDGND

プルアップ抵抗

配線図のようにDHT11のDATAピンを、4.7kΩの抵抗を介してVDDと同じ電圧につないでください。これをプルアップと呼びます。

ソースコード

次のプログラムは、DHT11で湿度と温度のデータを読み取り、シリアルモニターに表示させる内容となっております。温度の単位は摂氏温度です。

cpp
#include "DHT.h"
#define DATA_PIN 2 // D2

DHT dht(DATA_PIN, DHT11);

void setup() {
    Serial.begin(9600);
    dht.begin();
}

void loop() {

    delay(3000);

    float humid = dht.readHumidity();
    float temp = dht.readTemperature();

    if (isnan(humid) || isnan(temp)) {
        Serial.println("Failed...");
        return;
    }
//    Serial.println(humid);
//    Serial.println(temp);

    char humidFloatString[10];
    char tempFloatString[10];
    
    dtostrf(humid,4,2,humidFloatString);
    dtostrf(temp,4,2,tempFloatString);

    char bufHumid[20];
    char bufTemp[20];

    sprintf(bufHumid, "Humidity: %s", humidFloatString);
    sprintf(bufTemp, "Temperature: %s", tempFloatString);

    Serial.println(bufHumid);
    Serial.println(bufTemp);
}

ソースコードの解説

DHT

DHT22を使用する場合は、DHT dht(DATA_PIN, DHT22)へ書き換えれば動作するはずです。DHT11は毎秒1回の速度でしかデータを取得できません。一方で、DHT22は毎秒2回となります。用途によって使い分けてみてください。

floatを文字列に変換する

Arduinoでは、floatを文字列へ変換するには一筋縄ではいきませdtostrf関数を使って、floatから文字列へ変換し、sprintf関数でchar配列へ格納してます。

cpp
float pi = 3.14159265;
char floatString[10];
dtostrf(pi,4,2,floatString);
char buf[20];
sprintf(buf, "pi is %s", floatString);
Serial.println(buf);
dtostrfは、小数点を含む数値を文字列に変換します。
dtostrf(変換する値, 小数点や符号を含んだ変換後の文字数, 小数点以下の桁数, 変換後の文字列を格納する変数)

ここら辺は、OLEDなどで文字表示するときに役立ちます。

ESP32でDHT22を使う

ESP32でDHT22を使う
ESP32でDHT22を使う

ESP32でDHT22を使う方法を解説してきます。

ESP32とDHT22の配線

下図はESP32とDHT22の配線の例です。

ESP32とDHT22の配線図
ESP32とDHT22の配線図

上の図ではプルアップ抵抗(4.7kΩ)を繋いでいますが、下記商品ですとプルアップ抵抗が内蔵されてますのでその必要はありません。

DHT22のライブラリインストール

DHT22は一本線でデータのやり取りをする1-wire通信が採用されてます。ゼロからプログラミングするのは大変ですのでライブラリを使いましょう。Adafruitさんが公開しているライブラリを使うと便利です。

GitHub-adafruit / DHT-sensor-library : Arduino library for DHT11, DHT22

Arduino IDEのライブラリマネージャーかインストールしてもらっても構いません。私はPlatformIO IDEを使ってますので、上記サイトから、DHT.hDHT.cppだけダウンロードして、次のようなディレクトリ構造でテストしました。

.
├── include
│   └── README
├── lib
│   ├── DHT22
│   │   ├── DHT.cpp
│   │   ├── DHT.h
│   │   └── examples
│   │       └── demo
│   │           └── demo.ino
│   └── README
├── platformio.ini
├── src
│   └── main.cpp
└── test
    └── README

ソースコード

DHT22から気温・湿度をシリアルモニタへ表示する demo.ino のスケッチ内容です。

demo.ino
/**
 * @date 2022-11-23
 * @author Toshihiko Arai
 * @copyright https://101010.fun
*/
#include <Arduino.h>
#include <DHT.h>

/**
 * @brief DHT22  <-->  ESP32  の配線
 *        VCC    <-->  3.3V
 *        DATA   <-->  GPIO13
 *        GND    <-->  GND
*/
#define DHT_PIN 13
#define DHT_TYPE DHT22

DHT dht(DHT_PIN, DHT_TYPE);

void setup() {
    Serial.begin(115200);
    dht.begin();
    delay(100);
}

void loop() {
    float humidity = dht.readHumidity();
    float temperature = dht.readTemperature();
    float apparentTemperature =
        dht.computeHeatIndex(temperature, humidity, false);

    Serial.print("      Humidity: ");
    Serial.println(humidity);
    Serial.print("   Temperature: ");
    Serial.println(temperature);
    Serial.print("  Compute Heat: ");
    Serial.println(apparentTemperature);
    delay(1000);  // 読み取りデータがNANにならないように十分に待つ必要があるかも
}

気温や湿度データがでたらめな値だったり、nanが表示されてしまう場合は dht.begin() の宣言を忘れているかも知れません。setup() 内で宣言すること、忘れないようにしてください。

気温と湿度から体感温度を取得する

プログラム中にある computeHeatIndex 関数は、体感温度を計算してくれます。

cpp
float apparentTemperature = dht.computeHeatIndex(temperature, humidity, false);

DHTライブラリのソースコードを除くと、下記のアルゴリズムによって気温と湿度から体感温度を計算しているようです。 Heat Index Equation

M5StickC PLUSでDHT11を使う

M5StickC PLUSとDHT11センサ
M5StickC PLUSとDHT11センサ

ESP32が搭載されているM5StickC PLUSを使って、DHT11をHAT化して組み合わせてみました。

M5StickC PLUSとDHT11の配線

M5StickC PLUSとDHT11の配線は図の通りです。4.7kΩの抵抗をデジタルピンにつなげ、5V電源にプルアップします。

M5StickC PLUSとDHT11の配線図
M5StickC PLUSとDHT11の配線図
NC端子には何もつなぎません。VDDは3.3Vまたは5Vのどちらでも構いません。 今回は5Vにつなぎました。

ソースコード

湿度と温度を、M5StickC PLUSのLCDに表示するソースコードです。

cpp
#include <M5StickCPlus.h>
#include "DHT.h"

#define DATA_PIN 0 // G0

DHT dht(DATA_PIN, DHT11);

void setup() {
    M5.begin();
    M5.Axp.ScreenBreath(9);
    M5.Lcd.setTextColor(BLACK);

    Serial.begin(9600);
    dht.begin();
}

void loop() {

    delay(3000);
    M5.Lcd.fillScreen(WHITE);

    float h = dht.readHumidity();
    float t = dht.readTemperature();

    if (isnan(h) || isnan(t)) {
        Serial.println("Failed...");
        return;
    }

    M5.Lcd.setCursor(5, 10);
    M5.Lcd.setTextSize(2);
    M5.Lcd.println("Humid");

    M5.Lcd.setCursor(5, 33);
    M5.Lcd.setTextSize(4);
    M5.Lcd.printf("%.1f\n", h);

    M5.Lcd.setCursor(5, 80);
    M5.Lcd.setTextSize(2);
    M5.Lcd.println("Temp");

    M5.Lcd.setCursor(5, 103);
    M5.Lcd.setTextSize(4);
    M5.Lcd.printf("%.1f\n", t);
    
}

プログラムを実行すると、冒頭の写真のように湿度と温度が同時に表示されます。HATだといろいろなセンサを付け替えられるので便利ですね。

Raspberry PiでDHT11を使う

Raspberry PiでDHT11を使う
Raspberry PiでDHT11を使う

ここからは、Raspberry PiとDHT11センサで温度と湿度を測る方法を解説します。なお、Raspberry Piとの通信はmacOSからSSHで行いました。

\Raspberry PiでSSH設定/

開発環境

開発環境はこちら。

項目バージョン
ラズパイRaspberry Pi zero WH
温度湿度センサDHT11
Python2.7.16/3.7.3

Raspberry Piで1-Wireを有効化

DHT11は1-Wire通信を使いますので、Raspberry Piの設定で1-Wireを有効化しておく必要があります。Raspberry Piでは、1-Wireデータを読み取れるドライバーが内蔵されてます。ただしデフォルトでは無効になってますので、それを使えるように有効化しましょう。

$ sudo vi /boot/config.txt を実行し、下記内容を追加してください。
dtoverlay=w1-gpio,gpiopin=4,pullup=y

その後Raspberry Piを再起動します。 $ lsmod | grep w1を実行し、次のような表示されれば1-Wireの有効化に成功です。

shell
w1_therm                7330  0
w1_gpio                 3171  0
wire                   32947  2 w1_gpio,w1_therm

DHT11ライブラリのインストール

gitコマンドを使って、DHT11のライブラリをインストールします。 こちら のDHT11ライブラリをインストールしました。
shell
$ git clone https://github.com/szazo/DHT11_Python.git
gitコマンドがない場合は、先にインストールしておいてください。
shell
$ sudo apt-get install git

ライブラリのインストール完了後、現在のディレクトリにDHT11_Pythonディレクトリが作成されます。 DHT11_Pythonは、次のような階層になってます。

shell
$ tree
.
|-- LICENSE.md
|-- README.md
|-- dht11
|   |-- __init__.py
|   `-- __pycache__
|       `-- __init__.cpython-37.pyc
|-- dht11-test.py
|-- example.py
`-- setup.py

2 directories, 7 files

Raspberry PiとDHT11の配線

次ように、Raspberry PiとDHT11を配線します。

Raspberry PiとDHT11の配線図
Raspberry PiとDHT11の配線図

DHT11ラズパイ
VDD3.3V
DATAGPIO14⭐︎
NC--
GNDGND

⭐DHT11のDATAピンは4.7kΩの抵抗でプルアップします。

ソースコード

DHT11から温度と湿度データの取得するプログラムがこちらです。6秒おきに、温度と湿度が標準出力されます。

py
import RPi.GPIO as GPIO
import dht11
import time
import datetime

# initialize GPIO
GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)

# read data using pin 14
instance = dht11.DHT11(pin=14)

try:
    while True:
        result = instance.read()
        if result.is_valid():
            print("Last valid input: " + str(datetime.datetime.now()))

            print("Temperature: %-3.1f C" % result.temperature)
            print("Humidity: %-3.1f %%" % result.humidity)

        time.sleep(6)

except KeyboardInterrupt:
    print("Cleanup")
    GPIO.cleanup()

解説

次のようにしてプログラムを実行します。プログラムを止めたい場合は、control + Cで止めます。

shell
$ python3 example.py 
Last valid input: 2020-12-27 03:45:31.272394
Temperature: 24.5 C
Humidity: 47.0 %

「BCM」と「BOARD」の違い

プログラム中のGPIO.setmodeについて解説します。GPIO.BCMをセットすると、図のGPIOの番号でピンが指定されます。また、GPIO.BOARDをセットする、ピンの配列順の番号で指定されます。 ここらへんは間違えやすいので注意しましょう。

ラズパイGPIO役割図
ラズパイGPIO役割図

Raspberry PiとDHT22で温度ロガーの製作(Node.js・Chart.js)

温度ロガーの制作
温度ロガーの制作

最後に集大成として、こんなことやります。

  • Raspberry PiでDHT22を使う
  • 一定時間おきに温度・湿度を測定してCSV保存する
  • Node.jsでWebサーバーを立ち上げる
  • Chart.jsでデータをグラフ化

AdafruitのDHTライブラリをインストール

ここではAdafruitのDHTライブラリを使ってみます。

まずは、ライブラリをインストールする前やる「おまじない」です。パッケージリストやインストールされているパッケージ類を最新状態にします。

shell
$ sudo apt-get update
$ sudo apt-get upgrade

python3とpipを使えるようにします。

shell
$ sudo apt-get install python3-dev python3-pip

setuptoolsとwheelとpipを最新状態にしておきます。

shell
$ sudo python3 -m pip install --upgrade pip setuptools wheel

こちらのAdafruitのDHTライブラリを使えば、Raspberry Piで簡単に温度と湿度が取得できるようになります。

sh
$ sudo pip3 install Adafruit_DHT

GitHub-adafruit / DHT-sensor-library : Arduino library for DHT11, DHT22

配線

Raspberry PiとDHT22の配線は次のとおりです。

Raspberry PiとDHT22の配線
Raspberry PiとDHT22の配線

DATAピンは、4.7kΩの抵抗でプルアップする必要があります。また、センサのDATAピンは、Raspberry PiのGPIO14(物理番号8番)へつなぎました。DHT22の電源電圧は3V3へつなぎます。

▼ こちらの図のように、DHT22センサをステレオミニでRaspberry Piへ配線できるようにしてみました。

センサとステレオミニ
センサとステレオミニ

PythonとDHT22で温度・湿度の表示

Vimなどで次のPythonプログラムを新規作成します。ここではdht22_test.pyとして、ホームディレクトリへ保存しました。

5秒おきに温度と湿度を取得します。

py
import Adafruit_DHT
from time import sleep

DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 14

while True:
    humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)

    if humidity is not None and temperature is not None:
        print("Temp: {0:0.1f}C  Humidity: {1:0.1f}%".format(temperature, humidity))
        sleep(5)
    else:
        print("Failed.")

次のようにして、Python3でプログラムを実行します。

shell
$ python3 dht22_test.py 
Temp: 19.8C  Humidity: 46.6%
Temp: 19.5C  Humidity: 46.4%
Temp: 19.5C  Humidity: 46.5%

このように、5秒おきに温度が出力できれば成功です。プログラムを終了する際は、control + Cを押します。

Pythonで温度・湿度データをCSVファイルに保存する

先ほどのプログラムを改良して、Pythonで温度・湿度データをCSVファイルに保存します。

py
import Adafruit_DHT
from time import sleep
import datetime

DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 14

file_path = "./dat/data.csv"
with open(file_path, mode='a+'):
    pass

def put_data(humid, temp):
    print("{} / {}".format(humid, temp))
    dt_now = datetime.datetime.now()
    # dt_today = datetime.date.today()
    count = 0
    datas = []
    
    with open(file_path, mode='r') as f:
        
        for l in f.readlines():
            l = l.replace("\n", "")
            datas.append(l)

        tmp_str = "{0:0.1f},{1:0.1f}".format(temp, humid)
        datas.append("{},{}".format(dt_now, tmp_str))
        datas = datas[max(0, len(datas)-3000):]

    with open(file_path, mode="w") as f:
        contents = ""
        for d in datas:
            contents += "{}\n".format(d)
        # print(contents)
        f.write(contents)

while True:
    humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)

    if humidity is not None and temperature is not None:
        put_data(humidity, temperature)
        sleep(60)
    else:
        print("Failed.")

仕様は次のとおりです。

  • 1分おきにデータを取得し、追記する
  • 3000件溜まったら、過去のデータを切り捨てる

ちなみに1分おきにデータを書き加えていくと、1日あたり1440件になります。ですから約2日分のデータを確認できます。

バックグラウンドジョブで実行する

バックグラウンドかつ、SSHをログアウトしてもプログラムを継続させるために、nohup&を使って次のようにプログラムを実行させます。

shell
$ nohup python3 logger.py &
[1] 18117

プログラムを停止したい場合はpsコマンドでプロセスIDを調べてkillします

shell
$ ps x
  PID TTY      STAT   TIME COMMAND
  319 ?        Ssl    1:09 /home/pi/oprint/bin/python3 /home/pi/oprint/bin/octoprint serve --h
  949 ?        Ss     0:00 /lib/systemd/systemd --user
  950 ?        S      0:00 (sd-pam)
  963 ?        S      0:03 sshd: pi@pts/0
  965 pts/0    Ss     0:03 -bash
18117 pts/0    S      0:01 python3 logger.py
19299 pts/0    R+     0:00 ps x

$ kill 18117

これでデータファイルの準備はできました。

Node.jsのインストール

ここからはデータを見やすくするために、Node.jsでWebサーバーを立ち上げ、Chart.jsで数値をグラフ化する設定を行います。

まずはNode.jsとパッケージ管理ツールのnpmをインストールします。

shell
$ sudo apt-get install -y nodejs npm
shell
$ npm -v
5.8.0

$ node -v
v10.24.0

次に、WebアプリケーションフレームワークのExpressをインストールします。

shell
$ npm install --save express

Node.jsでWebサーバーの起動

次の内容の app.js ファイルを作ります。

shell
var express = require('express');
var app = express();

app.use(express.static('www'));

var port = 8888;
app.listen(port,function(){
    console.log("Starting with port:%d mode:%s", port, app.settings.env)
});
www ディレクトリを作成します。ここでHTMLファイルを管理します。
shell
$ mkdir www
www ディレクトリ内にindex.html ファイルをつくりましょう。
html
<!DOCTYPE html>
<html><head></head><body>
Hello world!
</body></html>

Node.jsでWebサーバーを起動します。

shell
$ node app.js

ブラウザからhttp://<Raspberry PiのIPアドレス>:8888/へアクセスしてみましょう。「Hello world!」が表示されれば成功です。

SSHログアウト後も継続させるには、$ nohup node app.js &で実行しましょう。

ディレクトリツリー

ここまでで、ディレクトリツリーは次のような構成になってます。

shell
$ tree
.
|-- app.js
|-- dat
|   `-- data.csv
|-- logger.py
|-- nohup.out
`-- www
    |-- dat -> /home/pi/dht22/dat
    `-- index.html

3 directories, 5 files
index.htmlにJavaScriptを実装しますが、JavaScriptからdata.csvへアクセスできるようにするため、シンボリックリンクを作成してます。
shell
$ ln -s "$(pwd)/dat" www/dat

Chart.jsのインストール

あとは、温度・湿度データをWebページに表現すれば良いだけです。XMLHttpRequestを使ってCSVファイルを読み込み、Chart.jsでグラフ化します。

先ほどのindex.htmlを次のように書き換えて、データをグラフ化してみました。

html
<!DOCTYPE html>
<html>
<head><title>DHT22 Logger</title></head>
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<script
  src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.2.0/chart.min.js"
  integrity="sha512-VMsZqo0ar06BMtg0tPsdgRADvl0kDHpTbugCBBrL55KmucH6hP9zWdLIWY//OTfMnzz6xWQRxQqsUFefwHuHyg=="
  crossorigin="anonymous"></script>
<script
  src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns@next/dist/chartjs-adapter-date-fns.bundle.min.js"></script>
<body>
    <div style="width:100%">
        <canvas id="tempChart"></canvas>
        <canvas id="humidChart"></canvas>
      </div>
<script>
var date_datas = [];
var humidity_datas = [];
var temperature_datas = [];
    
function getCSV(){
    var req = new XMLHttpRequest();
    req.open("get", "./dat/data.csv", true);
    req.send(null);	
    req.onload = function(){

        var lines = req.responseText.split("\n");
        // console.log(req.responseText);

        for(var i=0; i<lines.length; i++){
            // console.log(lines[i]);
            var arr = lines[i].split(',');
            date_datas.push(arr[0]);
            temperature_datas.push(arr[1]);
            humidity_datas.push(arr[2]);
        }
        showChart();
    }
}

getCSV();

function showChart() {
    // console.log(date_datas);
    // console.log(humidity_datas);
    // console.log(temperature_datas);

    var ctx1 = document.getElementById('tempChart');
    var ctx2 = document.getElementById('humidChart');

    var tempChart = new Chart(ctx1, {
        type: 'line',
        data: {
        labels: date_datas,
        datasets: [{
            label: '温度',
            data: temperature_datas,
            borderColor: '#f88',
        }],
        },
        options: {
        scales: {
    y: {
      min: 0,
      max: 50,
    },
  }
      },
    });
    var humidChart = new Chart(ctx2, {
        type: 'line',
        data: {
        labels: date_datas,
        datasets: [{
            label: '湿度',
            data: humidity_datas,
            borderColor: '#48f',
        }],
        },
        options: {
        scales: {
    y: {
      min: 0,
      max: 100,
    },
  }
      },
    });
}

</script>
</body>
</html>

ブラウザからhttp://<Raspberry PiのIPアドレス>:8888/へアクセスすると、温度・湿度の観測データをグラフで閲覧することができるようになりました。

温度ロガーでグラフ
温度ロガーでグラフ

\おすすめ記事/

関連記事

 
最後までご覧いただきありがとうございます!

▼ 記事に関するご質問やお仕事のご相談は以下よりお願いいたします。
お問い合わせフォーム

スマート農業(スマートアグリ)で使えるセンサー
水耕栽培はじめよう!
関連記事