知的好奇心 for IoT

IoT関連の知的好奇心を探求するブログです

WiFi温度・湿度計をDHT11からDHT12にアップグレードした

温度・湿度センサーのDHT11トランジスタ型のセンサーに比べれば若干高いのですが、校正要らずのデジタルセンサーでArduinoで簡単に扱えるライブラリーが提供されていることから人気のセンサーとなっているようです。

ぼくもこれまでのブログで何回か扱っていましたが、少し問題点も見えて来ていました。

  1. Adafruitのライブラリーでは有効な値が整数になっている(floatなのに!)
  2. 湿度が異常に高かったり、低かったりする個体がある
  3. 1-wire通信が安定しない場合がある
  4. 温度の測定範囲が狭い0~50℃、精度が低い±2℃

ちょっと解説しますね。

まず1番です。

Adafurtのライブラリーにあるサンプルコードでは、温度と湿度をfloat(倍精度浮動小数点数)で取得しています。

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

しかし、このサンプルコードを実行したログには悲惨な結果が表示されます。

Humidity: 45.00 %	Temperature: 27.00 *C

せっかく小数点以下も扱えるfloatでデータを取得しているのに、小数点以下はいつも00なんです!意味ねー!!!

これまで説明はしていなかったのですが、ぼくのプログラムで温度と湿度を一応丸めて(四捨五入して)intにキャストしていたのは、いつも.00と表示されるのを防ぐためだったんです。

Blynk.virtualWrite(V5, (int)round(h));
Blynk.virtualWrite(V6, (int)round(t));

つぎ、2番。

DHT11を今まで10個ぐらい買ったのですが、友達にあげた1個の湿度が部屋の中にあるにも関わらずいつも80%超えてるって教えてくれたんです。その他、ぼくの部屋に設置していたセンサーが、落っことした後ぐらいから湿度が30%~40%と低い値を表示するようになったんです。温度は大丈夫そうなんですが...。

半導体って衝撃には弱くないと思うんですが、このセンサー、衝撃に弱いとか何かありそうな感じなんです。

つぎ、3番。

実は、1番を書いた後、2番以降を書くのを忘れて次の項目を書いてしまって...。

DHT12の項目に内容を書いてしまいました!

4番は書いた通りで、実用というよりはお遊び用のスペックしか持っていません。

 

DHT12

安くてコンパクトなため、最近お気に入りのESP8266ボードWemos D1 Mini用のシールドを何気に見ていて見つけたのがこのセンサーです。DHT11と同じメーカーの製品でDHT11より性能が良く、DHT11と同じ1-wireの他にI2Cインターフェースも装備している優れものですが、日本で売っているお店を見つけられないうえメーカーのサイトにさえ載っていないかわいそうなやつです...。

グレても不思議じゃない不遇なDHT12ですが、その性能は申し分のないものです。

  • 測定範囲:温度-20~+60℃ 湿度20~95%
  • 解像度: 温度0.1℃     湿度0.1%
  • 精度:  温度±0.5℃   湿度±5% 

それとI2Cインターフェースに対応したことで動作の安定性が格段に上がりました。

DHT11のサンプルコードではloop()の初っ端にdelay(2000);を入れて2秒待ってから値を取得するようになっています。その理由はコメントに書いてありました。

// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)

値を取得した後は取得に失敗したかどうかを確認するコードが書かれています。

// Check if any reads failed and exit early (to try again).
if (isnan(h) || isnan(t) || isnan(f)) {
  Serial.println("Failed to read from DHT sensor!");
  return;
}

Failed to read from DHT sensor!は、シンプルなサンプルコードでは出ないんですが、milkcocoaやBlynkを使うようなプログラムだと結構な頻度でお目にかかるんです。

これが、DHT12でI2Cインターフェースを使うと、値の取得に2秒待たなくていいしエラーログにもお目にかかることがなくなるんです!

 

DHT Shield V2.0.0(for Wemos D1 mini)

f:id:IntellectualCuriosity:20170926014642j:plain

DHT ShieldはDHT12をI2Cインターフェースで使うようにデザインされたWemos D1 mini用のシールドです。写真のようにセンサー部分だけを手でパキッと割れるように作られていて、センサーを本体から離して本体の熱の影響を受けない設置がしやすいように配慮されています。

ライブラリ

Arduino用のライブラリがメーカーのWemosから提供されていて、DHT Shieldのページの下の方にリンクが貼ってあります。リンク先のGitHubでzipファイルをダウンロードして、Arduinoのスケッチメニューから[ライブラリをインクルード]-[.ZIP形式のライブラリをインストール...]で読み込ませると使えるようになります。

サンプルコード

GitHubにはサンプルコードもUPされています。なんと、DHT11のライブラリよりも手順が少なく簡単に扱えるようになっていて、#include <wemos_dht12.h>の後にDHT12 dht12;とオブジェクトを作成するだけで、温度はdht12.cTemp、湿度はdht12.humidityで取得できます。サンプルではloop()の最後でdelay(1000);と1秒待つように書かれていますが、このディレイを削除しても値の取得に失敗することはありませんでした。素晴らしい!

入手方法

DHT Shieldのページ上方にある黄色い「Buy Now」をクリックすると、AliExpressに出店しているWEMOS StoreのDHT Shield V2.0.0ページに飛びます。2017/9/26の時点で1個172円!配送がシンガポール郵便なら届くのに22-37日かかると表示されていますが、送料はなんと70円です!安い、安すぎる!

ぼくがDHT Shield 2つとMotor Shield 2つをAliExpress Standard Shippingという配送手段(送料301円)で9月11日にオーダーしたときは11日後の22日に荷物が届きました。

f:id:IntellectualCuriosity:20170926061040p:plain
配送追跡記録

 

WiFi温度・湿度計改二

f:id:IntellectualCuriosity:20170926070540j:plain

パキッと割ったDHT Shieldのセンサー部分に秋月電子で購入したピンソケットを取り付け、ジャンパーワイヤーでESP8266ボードと接続したものが、WiFi温度・湿度計改二です。

ESP8266ボードとセンサー間の距離を取ったことで発熱の影響を完全に受けなくなりました。

Arduinoスケッチ

ESP8266とDHT11とBlynkでスマホとWebにリアルタイムで温度と湿度を表示する」に載せていた3つのファイルの内、DHT11Blynk.inoを以下のDHT12Blynk.inoに替えます。

DHT12Blynk.ino

/*
 * DHT12Bylnk
 * September 25, 2017
 * By Hiroyuki ITO
 * http://intellectualcuriosity.hatenablog.com/  
 * MIT Licensed.
 */

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <WEMOS_DHT12.h>

// EEPROM
char eep_auth[33];
char eep_ssid[33];
char eep_pass[33];

// RUN MODE
#define MODE_PIN 5        // WeMos D1 mini assined pin D1
#define MODE_SENSOR 0
#define MODE_SERVER 1
int run_mode;

DHT12 dht12;
BlynkTimer timer;

/*
 * Send Sensor Data to Blynk
 */
void sendSensor()
{
  if (dht12.get() != 0) {
    BLYNK_LOG("Failed to read from DHT sensor!");
    return;
  }
  Blynk.virtualWrite(V5, dht12.humidity);
  Blynk.virtualWrite(V6, dht12.cTemp);
  BLYNK_LOG3("Temperature:", dht12.cTemp, "'C");
  BLYNK_LOG3("Humidity:", dht12.humidity, "%");
}

/*
 * Main Setup
 */
void setup()
{
  delay(10);
  Serial.begin(74880);
  BLYNK_LOG2("Reset Reason: ", ESP.getResetReason());

  // EEPROM and Server Mode
  pinMode(MODE_PIN, INPUT_PULLUP);
  ReadEEPROM();
  BLYNK_LOG2("Auth:", eep_auth);
  BLYNK_LOG2("SSID:", eep_ssid);
  BLYNK_LOG2("Pass:", eep_pass);
  // Not set EEPROM or Set jumper wire
  if (eep_ssid[0] == 0 || (digitalRead(MODE_PIN) == LOW)) {
    // Server mode
    setup_server();
    run_mode = MODE_SERVER;
    return;
  }

  // Sensor mode
  BLYNK_LOG("*** Sensor mode ***");
  Blynk.begin(eep_auth, eep_ssid, eep_pass);
  run_mode = MODE_SENSOR;

  // Setup a function to be called every 2 seconds
  timer.setInterval(2000L, sendSensor);
}

/*
 * Main Loop
 */
void loop()
{
  if (run_mode == MODE_SERVER) {
    loop_server();
  } else {
    Blynk.run();
    timer.run();
  }
}

DHT11Blynk.inoとDHT12Blynk.inoはほぼ一緒ですが、温度と湿度のデータが整数から実数になっているのが大きな違いです。

Blynk Gauge Widgetの設定

温度と湿度を整数で表示するようになっていたものを、少数第1位まで表示するように修正しました。

f:id:IntellectualCuriosity:20170926082210p:plain

修正後の表示

f:id:IntellectualCuriosity:20170926082234p:plain

サイドバーの部屋の気温のコード

温度と湿度のデータが実数でクラウドサーバーに送られているため、そのままだと小数点以下に0が沢山ならんで表示されてしまいました。少数第1位まで表示するようにtoFixed()を使って次のように変えています。

温度の表示

document.getElementById("blynk_temperature").innerHTML = "温度:" + temperature.toFixed(1) + "℃";

湿度の表示

document.getElementById("blynk_humidity").innerHTML = "湿度:" + humidity.toFixed(1) + "%";

 

おわり