温度湿度センサDHT20をESP32に接続してHomeKitから使う

DIYする

秋月電子で380円で販売されているI2C接続の温度湿度センサDHT20を、前回はRaspberry Piに接続しました。今回はこれのESP32版です。

このセンサを、ESP32に接続します。そして取得した温度、湿度のデータを、今回もMQTTメッセージとして流し、HomeKitで温度、湿度センサとして表示させます。センサ情報は下図の左から右に流れます。MQTTブローカとHomebridgeがLAN内のRaspberry Pi 4で稼働していて、これがESP32からのMQTTメッセージを受けて、ソフトウェア的なセンサアクセサリを作り、iPhoneやMacのあるHomeKit側に公開します。

DHT20を使うだけなら、前回のようにRaspberry Piに直結すれば簡単でした。でもESP32に接続できれば、安価に作れるので複数の場所の温度を知りたい場合に適してます。実はこの先、ESP32を使ったエアコンリモコンを作ろうと考えてます。それの温度センサ部分に使いたいと思い、準備のためにESP32に接続しました。

回路を作る

回路と言っても、Raspberry Piの時と同様に、ESP32にI2Cの2本の線で接続します。さらに電源(3.3V)とGNDを配線します。

GPIOは21と22を使用しました。他のピンでも可能なようですが、この2本を使う例がほとんどでした。ブレッドボードの実体配線図はこちらです。

配線した様子です。DHT20の足は弱いので、慎重にブレッドボードに挿します(曲げてしまいました)。

ライブラリを選択する

Arduino IDEのライブラリマネージャから、それらしいライブラリを検索しました。I2Cで検索すると多数現れました。いろいろ探しているうちに、なんとDHT20のためのライブラリもありそうでした。そこでdhtで検索したところこれも多数現れました。

DHT11, DHT12, DHT22などのセンサもあります。型番も形もは似てますがこれらはI2Cでは無い1線で通信するタイプです。DHT11は秋月電子でも売ってます。でもDHT20よりも値段が高くて精度が悪いので、DHT20が良いと思います。

そこで、DHT20だけに絞って検索しました。すると2個のライブラリが見つかりました。

便宜上、片方をDFRobot版、もう片方をRob版と呼ぶことにします。結局はどちらも試したのですが、どちらのライブラリも問題なく動作しました。更新はRob版の方が新しいですが、DFRobot版も昨年に更新されているので、放置されているわけでは無いです。調べたところ、使い方が簡単なのはDFRobot版、機能が充実しているのがRob版と言えます。

それぞれのバージョンで温度・湿度を読む手順は、DFRobota版が、

  1. getTemperature()で温度を読む
  2. getHumidity()で湿度を読む

ですが、Rob版の手順は

  1. read()コマンドを出す
  2. getTemperature()で温度を読む
  3. getHumidity()で湿度を読む

です。read()コマンドを出さずにgetすると、前回read()したタイミングでの値が、再びそのまま返ってきます。

Raspberry Piに接続したときは、I2C通信を生で使いましたが、その時の温度・湿度データ取得の手順は、

  1. DHT20にトリガーコマンドを送る
  2. 80ms待つ
  3. 温度と湿度のデータが一緒に得られる

でした。DFRobot版はAPIが簡単で分かりやすいすが、おそらくは温度、湿度を読むたびに、それぞれでトリガーコマンドを送って80ms待機する動作をしていると思われます。一方で、Rob版は、元々のセンサのI2Cプロトコルに忠実な無駄の無い実装だと思いました。DFRobotというところは、教育に重点を置きつつ、シングルボードコンピュータや電子部品を販売している会社のようです。日本だとスイッチサイエンスみたいな会社かな。プログラミング初心者が挫折しないよう、教育的な配慮がされているのかと想像しました。

室内の温度・湿度を取得するなら80ms程度の遅延はどうでも良いことですが、無駄な手順を踏むのは気持ちが落ち着かないので、Rob版を使うことにしました。Rob版のMore Infoをクリックした先のサイトはこちらです。

サンプルを動かす

ライブラリをインストールすると、ファイル・スケッチ例・DHT20のメニューの中にいくつかのサンプルファイルが見えるようになります。ここのDHT20というサンプルを動かしました。問題なくコンパイルできて動作しました。温度と湿度の値がシリアルモニターに表示されました。

ライブラリの基本的な使い方は:

  1. DHT20のクラスのインスタンスを作る(以下dht)。引数でGPIOを指定できるが省略すると21, 22
  2. setup()でdht.begin()をする
  3. dht.read()をする。戻り値が0ならばエラーなし。50msくらいブロックされる。
  4. float dht.getTemerature()すると戻り値に温度が得られる、
  5. float dht.getHumidity()すると戻り値に湿度が得られる
  6. 1秒程度以上待ってからステップ3に戻る

です。

read()して、getTemperature(), getHumidity()で温度湿度を得るのが基本的な順番です。getTemperature()とgetHumidity()は何回も続けて呼べるけど、次にread()するまで同じ値が返ってくるだけのようです。

read()では50msくらいブロックされるそうです。このサンプルのシリアルモニターに表示されているTimeの値は、ブロックされていた時間を表示しています。47msくらいでした。このブロック時間が問題になる場合には、非同期で動かす機能がライブラリにあるのでそちらを使うそうです。スマートホームの室温測定の目的なら50msは全く問題ないので、単純に待つことにします。

シンプルなプログラムを作る

スケッチ例を参考に、シンプルなプログラムを作りました。

#include "DHT20.h"
DHT20 dht = DHT20();

void setup(){
  dht.begin(); //default: 21,22
  Serial.begin(115200);
  while (!Serial); //wait for serial connected.
  delay(1000);
}

void loop(){
  if(millis() - dht.lastRead() >= 1000) {
    if(DHT20_OK == dht.read()){
      Serial.print("Humidity: ");
      Serial.print(dht.getHumidity(), 1);
      Serial.print("  Temerature: ");
      Serial.println(dht.getTemperature(), 1);
    }
  }
}

1秒おきに温度・湿度を読むプログラムです。lastRead()で前回read()した時刻が読めてタイミング調整に使えるようです。read()してエラーが返って来なかった時だけシリアル表示します。

MQTTにパブリッシュする

Raspberry Piの時と同じく、結果をMQTTブローカーパブリッシュする機能を追加しました。トピック名なども同じです。

#include <EspMQTTClient.h>
#include "DHT20.h"
EspMQTTClient *client;
DHT20 *dht = new DHT20();
//WiFi & MQTT
const char SSID[] = "XXXXXXXX"; //WiFi SSID
const char PASS[] = "xxxxxxxx"; //WiFi password
char CLIENTID[] = "DHT20_623575725"; //something random
const char  MQTTADD[] = "192.168.xxx.xxx"; //Broker IP address
const short MQTTPORT = 1883; //Broker port
const char  MQTTUSER[] = "xxxx";//Can be omitted if not needed
const char  MQTTPASS[] = "XXXX";//Can be omitted if not needed
const char  PUBTOPIC[] = "mqttthing/dht20/get"; //mqtt topic
const char  SUBTOPIC[] = "mqttthing/dht20/set"; //mqtt topic
const char  DEBUG[] = "mqttthing/dht20/debug"; //mqtt topic

void onConnectionEstablished() {
  Serial.println("MQTT connection established.");
  client->subscribe(SUBTOPIC, onMessageReceived); //callback
  publishDHT();
}

void onMessageReceived(const String& msg) {
  publishDHT();
}

void publishDHT() {
  char buff[64];
  float humi, temp;
  if(DHT20_OK != dht->read()){
    client->publish(DEBUG,"DHT20 Read Error.");
  }else{
    humi=dht->getHumidity();
    temp=dht->getTemperature();
    sprintf(buff, "{\"temperature\":%.1f,\"humidity\":%.0f}", temp, humi);
    client->publish(PUBTOPIC,buff);
  }
}

void setup()
{
  dht->begin(GPIO_SDA, GPIO_SCL);
  Serial.begin(115200);
  while (!Serial);  //wait for serial.
  client = new EspMQTTClient(SSID,PASS,MQTTADD,MQTTUSER,MQTTPASS,CLIENTID,MQTTPORT);
  delay(1000);
}

void loop()
{
  client->loop();
  if(millis() - dht->lastRead() >= 180000) publishDHT();
}

更新頻度を3分にしました。別のターミナルウィンドウでmosquitto_subコマンドを動かし、サブスクライブしておきます。結果は以下のようになりました。

mqttthing/dht20/get {"temperature":22.9,"humidity":61}
mqttthing/dht20/get {"temperature":22.9,"humidity":61}
mqttthing/dht20/get {"temperature":22.9,"humidity":60}

また、おまけの機能として、setというトピックに何かメッセージを送ると、次の3分を待たずにすぐに結果を返してくれるようにしてみました。Zigbeeセンサで見かけた機能です。

% mosquitto_pub -h 192.168.xxx.xxx -t "mqttthing/dht20/set" -m {}

などすると 、すぐに

mqttthing/dht20/get {"temperature":22.1,"humidity":62}

のように、結果を返します。測定結果がすぐに必要なアプリで役立つのではと思いました。

Homebridgeで受け取る

ここから先は、前回Raspberry PiにDHT20を取り付けた時と同じです。HomebridgeにはMqttthingプラグインを入れてあります。MQTTメッセージで動くアクセサリを実装できます。

Mqttthinの設定から、tenmeratureSensorとhumiditySensorを使います。MQTTの設定は、プラグインの設定画面からGUIで入力できます。最終的に出来上がったconfigの部分は以下になりました。

{
  "type": "temperatureSensor",
  "name": "DHT20_temp",
  "username": "xxxxxxxx",
  "password": "XXXXXXXX",
  "topics": {
    "getCurrentTemperature": "mqttthing/dht20/get$.temperature"
  },
  "accessory": "mqttthing"
},
{
  "type": "humiditySensor",
  "name": "DHT20_humi",
  "username": "xxxxxxxx",
  "password": "XXXXXXXX",
  "topics": {
    "getCurrentRelativeHumidity": "mqttthing/dht20/get$.humidity"
  },
  "accessory": "mqttthing"
}

Mqttthingは、json形式のデータも扱えます。上の設定で、

mqttthing/dht20/get$.temperature

としたことで、mqttthing/dht20/getトピックに流れてくるjson形式のデータ:

{"temperature":23.0,"humidity":56}

のtemperatureキーの部分(23.0という値)を取得できます。humidityも同様です。

HomeKitから使ってみる

この結果、iPhoneやMacのホーム.appの上に、

というような表示が現れ、これをクリックすると、

のように、今回取り付けたセンサーの値が表示されました。これをもとにオートメーションも作れます。室温が下がったらエアコンを動作させるとか、湿度が下がったら加湿器をonにするなどの自動化が可能です。例えば、上のDHT20_humiの表示をクリックして、「オートメーションを追加」のメニューを選択すると、数クリックの操作で、下のようなオートメーションが完成します。

まとめ

秋月で380円で買えるI2C温度・湿度センサDHT20をESP32に接続して、iPhoneやMacのホーム.appから利用できるように設定しました。Raspberry Piの時と同様に、4本の線を配線するだけで温度・湿度センサが作れます。専用のライブラリも用意されていたので、プログラミングも簡単でした。結果をMQTTのメッセージで流すようにしたので、他のプログラムやスマートホームシステムからも利用できます。

ESP32に赤外線LEDを取り付けてエアコン用のスマートリモコンを作ろうと予定してます。HomeKItの空調アクセサリには、室温測定機能が備わっていることになってます。今回の仕組みで、自作スマートリモコンの室温測定機能を実現する予定です。

コメント

タイトルとURLをコピーしました