温度湿度センサDHT11・DHT22をArduino・ESP32・ラズパイで使う
つかうもの
はじめに、この記事で「つかうもの」をご紹介します。
温度湿度センサDHT11・DHT22
DHT11とDHT22は、空気中の温度と湿度を同時に測定することができるデジタルセンサです。通信方法はSPIやI2Cでもなく、1-wireで行う独自の通信になってます。Arduinoやラズパイではライブラリがありますので簡単に扱える様になってます。
DHT11よりDHT22のほうが、測定範囲が広く、測定精度も良いです。DHT22の扱い方も、DHT11とほとんど変わりありません。DHT22のほうがお値段が若干高めですが、長い目で見るとDHT22をおすすめしておきます。実際に仕事ではDHT22をメインに使ってます。
項目 | DHT11 | DHT22 |
---|---|---|
電源 | 3V~5V | 3V~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 IDE | 1.8.10 |
パソコン | macOS Big Sur 11.0.1 |
Arduino UnoでDHT11を使う
Arduino UnoでDHT11を使う方法を解説してきます。
Arduino IDEにDHT11ライブラリをインストール
Arduino IDEでDHT11ライブラリをインストールします。次の手順にしたがって、Adafruitの DHT sensor library と Adafruit Unified Sensor をインストールします。
▼ Adafruitのライブラリの詳細はこちらから。 Using a DHTxx Sensor | DHT11, DHT22
DHT11のピン端子役割
DHT11から湿度や温度を読み取るには、DATAピンでデータのやりとりを行います。VDDは3V〜5Vの範囲で使用できます。また、NCピンは使いませんので何も接続しません。
DHT11とArduinoの配線
DHT11とArduinoの配線の配線図です。VDDは5Vと3.3Vのどちらでも構いません。また、NCには何もつなぎません。
DHT11 | Arduino Uno |
---|---|
VDD | 5V |
DATA | D2 |
NC | -- |
GND | GND |
プルアップ抵抗
配線図のようにDHT11のDATAピンを、4.7kΩの抵抗を介してVDDと同じ電圧につないでください。これをプルアップと呼びます。
ソースコード
次のプログラムは、DHT11で湿度と温度のデータを読み取り、シリアルモニターに表示させる内容となっております。温度の単位は摂氏温度です。
#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配列へ格納してます。
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(変換する値, 小数点や符号を含んだ変換後の文字数, 小数点以下の桁数, 変換後の文字列を格納する変数)
ここら辺は、OLEDなどで文字表示するときに役立ちます。
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.hとDHT.cppだけダウンロードして、次のようなディレクトリ構造でテストしました。
.
├── include
│ └── README
├── lib
│ ├── DHT22
│ │ ├── DHT.cpp
│ │ ├── DHT.h
│ │ └── examples
│ │ └── demo
│ │ └── demo.ino
│ └── README
├── platformio.ini
├── src
│ └── main.cpp
└── test
└── README
ソースコード
DHT22から気温・湿度をシリアルモニタへ表示する 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 関数は、体感温度を計算してくれます。
float apparentTemperature = dht.computeHeatIndex(temperature, humidity, false);
DHTライブラリのソースコードを除くと、下記のアルゴリズムによって気温と湿度から体感温度を計算しているようです。 Heat Index Equation
M5StickC PLUSでDHT11を使う
ESP32が搭載されているM5StickC PLUSを使って、DHT11をHAT化して組み合わせてみました。
M5StickC PLUSとDHT11の配線
M5StickC PLUSとDHT11の配線は図の通りです。4.7kΩの抵抗をデジタルピンにつなげ、5V電源にプルアップします。 NC端子には何もつなぎません。VDDは3.3Vまたは5Vのどちらでも構いません。 今回は5Vにつなぎました。
ソースコード
湿度と温度を、M5StickC PLUSのLCDに表示するソースコードです。
#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との通信はmacOSからSSHで行いました。
\Raspberry PiでSSH設定/
開発環境
開発環境はこちら。
項目 | バージョン |
---|---|
ラズパイ | Raspberry Pi zero WH |
温度湿度センサ | DHT11 |
Python | 2.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の有効化に成功です。
w1_therm 7330 0
w1_gpio 3171 0
wire 32947 2 w1_gpio,w1_therm
DHT11ライブラリのインストール
gitコマンドを使って、DHT11のライブラリをインストールします。 こちら のDHT11ライブラリをインストールしました。$ git clone https://github.com/szazo/DHT11_Python.git
$ sudo apt-get install git
ライブラリのインストール完了後、現在のディレクトリにDHT11_Pythonディレクトリが作成されます。 DHT11_Pythonは、次のような階層になってます。
$ 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を配線します。
DHT11 | ラズパイ |
---|---|
VDD | 3.3V |
DATA | GPIO14⭐︎ |
NC | -- |
GND | GND |
⭐DHT11のDATAピンは4.7kΩの抵抗でプルアップします。
ソースコード
DHT11から温度と湿度データの取得するプログラムがこちらです。6秒おきに、温度と湿度が標準出力されます。
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で止めます。
$ 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をセットする、ピンの配列順の番号で指定されます。 ここらへんは間違えやすいので注意しましょう。
Raspberry PiとDHT22で温度ロガーの製作(Node.js・Chart.js)
最後に集大成として、こんなことやります。
- Raspberry PiでDHT22を使う
- 一定時間おきに温度・湿度を測定してCSV保存する
- Node.jsでWebサーバーを立ち上げる
- Chart.jsでデータをグラフ化
AdafruitのDHTライブラリをインストール
ここではAdafruitのDHTライブラリを使ってみます。
まずは、ライブラリをインストールする前やる「おまじない」です。パッケージリストやインストールされているパッケージ類を最新状態にします。
$ sudo apt-get update
$ sudo apt-get upgrade
python3とpipを使えるようにします。
$ sudo apt-get install python3-dev python3-pip
setuptoolsとwheelとpipを最新状態にしておきます。
$ sudo python3 -m pip install --upgrade pip setuptools wheel
こちらのAdafruitのDHTライブラリを使えば、Raspberry Piで簡単に温度と湿度が取得できるようになります。
$ sudo pip3 install Adafruit_DHT
GitHub-adafruit / DHT-sensor-library : Arduino library for DHT11, 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秒おきに温度と湿度を取得します。
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でプログラムを実行します。
$ 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ファイルに保存します。
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と&を使って次のようにプログラムを実行させます。
$ nohup python3 logger.py &
[1] 18117
プログラムを停止したい場合はpsコマンドでプロセスIDを調べてkillします
$ 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をインストールします。
$ sudo apt-get install -y nodejs npm
$ npm -v
5.8.0
$ node -v
v10.24.0
次に、WebアプリケーションフレームワークのExpressをインストールします。
$ npm install --save express
Node.jsでWebサーバーの起動
次の内容の app.js ファイルを作ります。
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)
});
$ mkdir www
<!DOCTYPE html>
<html><head></head><body>
Hello world!
</body></html>
Node.jsでWebサーバーを起動します。
$ node app.js
ブラウザからhttp://<Raspberry PiのIPアドレス>:8888/へアクセスしてみましょう。「Hello world!」が表示されれば成功です。
SSHログアウト後も継続させるには、$ nohup node app.js &で実行しましょう。
ディレクトリツリー
ここまでで、ディレクトリツリーは次のような構成になってます。
$ tree
.
|-- app.js
|-- dat
| `-- data.csv
|-- logger.py
|-- nohup.out
`-- www
|-- dat -> /home/pi/dht22/dat
`-- index.html
3 directories, 5 files
$ ln -s "$(pwd)/dat" www/dat
Chart.jsのインストール
あとは、温度・湿度データをWebページに表現すれば良いだけです。XMLHttpRequestを使ってCSVファイルを読み込み、Chart.jsでグラフ化します。
先ほどのindex.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/へアクセスすると、温度・湿度の観測データをグラフで閲覧することができるようになりました。
\おすすめ記事/