知的好奇心 for IoT

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

高精度温湿度センサーSHT31をESP8266のDeep Sleepでバッテリー運用してBlynkで可視化する

今までベランダの温度と湿度はWio NodeにBME280を付けて測っていたのですが、幾つか問題が出ていました。

  1. バッテリー運用で電圧降下が徐々に起きずにいきなり切れる
  2. 今年の梅雨に夜になると湿度がずっと100%になっていた

まず1ですが、Wio Nodeの開発元Seeed社のページをよく見ると「Input Voltage (Battery holder)」の値が「3.4~4.2V」と記載されていました。これは、Wio Nodeが使っているマイコンモジュールESP-WROOM-02の動作範囲(2.7V~3.6V)を超えており、Battery holderからの給電に電圧レギュレーターが使用されていることを示唆しています。

それで、マイコンボードを普段よく使用しているWeMos D1 miniに変更することにしました。

次に2ですが、これは正直よくわからなかったので、とりあえず秋月電子で売っている「高精度」と名の付いているセンサー「SENSIRION SHT31」に変えてみることにしました。

f:id:IntellectualCuriosity:20190824163220j:plain

f:id:IntellectualCuriosity:20190824164646j:plain

あと一つ、Deep Sleepで眠っている間もセンサーに電源供給しているとバッテリーを消耗してしまうので、起きているときだけ電源を供給するように工夫をしてみます。

 

リニューアル完成写真

f:id:IntellectualCuriosity:20190824184045j:plain

部品リスト

電池は普通の電池だと2本(1.5V x 2で3V)でニッケル水素充電池だと3本(1.2V x 3で3.6V)になるので注意してください。

配線

f:id:IntellectualCuriosity:20190824192015j:plain

完成写真では配線がWeMos D1 Miniの下に隠れてしまっていたので、配線の写真を載せました。

配線の繋ぎ先は上から順にこうなります。

  • 赤線(長) WeMos D1 mini 3V3 <===> 電池ボックス+
  • 茶線-橙線 WeMos D1 mini D7(GPIO13) <===> SHT31 +V
  • 赤線(短) WeMos D1 mini D0(GPIO16) <===> WeMos D1 mini RST
  • 白線 WeMos D1 mini D2(GPIO4) <===> SHT31 SDA
  • 白線 WeMos D1 mini D1(GPIO5) <===> SHT31 SCL
  • 緑線 WeMos D1 mini G <===> SHT31 GND, 電池ボックス-

赤線(短)はDeep Sleepから起きるのに必要な配線です。しかし、これを繋いでいるとプログラムの書き込みができなくなるので、プログラムを書き込むときはWeMos D1 miniをブレッドボードから外す必要があります。

 

スケッチ

/*
 * SHT31 sensor using ESP8266 and Blynk with Deep Sleep.
 * August 24, 2019
 * 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 <Wire.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <TimeLib.h>
#include <Adafruit_SHT31.h>

// Blynk Auth Token and WiFi credentials.
#define AUTH_TOKEN  "YourAuthToken"
#define WIFI_SSID   "YourNetworkName"
#define WIFI_PASS   "YourPassword"

// NTP
#define NTP_SERVER  "ntp.nict.jp" // National Institute of Information and Communications Technology
#define TIME_OFFSET 9*60*60       // UTC+9h (JST)

#define VCC_PIN     13            // Sensor VCC Pin (WeMos D1 mini D7)
#define DS_INTERVAL 60            // Deep Sleep Interval Time 2-60 (minutes)

// Global Objects
ADC_MODE(ADC_VCC);                // A-D Converter mode (Voltage)
Adafruit_SHT31 sht31 = Adafruit_SHT31();

/*
 * Get Time as String
 */
void getDateTime(char *dateTime) {
  sprintf(dateTime, "%04d/%02d/%02d %02d:%02d", year(), month(), day(), hour(), minute());
}

/*
 * Get and Send Sensor Data to Blynk
 */
void sendSensor() {
  // Sensor Power ON
  digitalWrite(VCC_PIN, HIGH);

  // Setup SHT31
  sht31.begin(0x45); // AE-SHT31 Open:0x45 Close:0x44

  // Get and Send SHT31 Data
  float t = sht31.readTemperature();
  float h = sht31.readHumidity();
  Blynk.virtualWrite(V1, t);
  Blynk.virtualWrite(V2, h);
  BLYNK_LOG2("Temperature: ", t);
  BLYNK_LOG2("Humidity: ", h);

  // Get and Send Voltage
  WidgetLCD lcd(V4);
  char dateTime[17];
  float vcc = ESP.getVcc() / 1024.0;
  getDateTime(dateTime);
  String s = String(dateTime) + " " + vcc + "V";
  lcd.clear();
  lcd.print(0, 0, s);
  BLYNK_LOG2("Time&Voltage: ", s);

  // Sensor Power OFF
  digitalWrite(VCC_PIN, LOW);
  delay(1000);
}

void setup() {
  Serial.begin(74880);

  // Setup Sensor Power Pin
  pinMode(VCC_PIN, OUTPUT);      
 
  // Setup Blynk
  Blynk.begin(AUTH_TOKEN, WIFI_SSID, WIFI_PASS);

  // Setup NTP
  WiFiUDP ntpUDP;
  NTPClient timeClient(ntpUDP, NTP_SERVER, TIME_OFFSET);
  timeClient.begin();
  while (!timeClient.update()) {
    delay(500);
  }
  setTime(timeClient.getEpochTime());
  BLYNK_LOG("Got time from ntp.");
}

void loop() {
  int min = DS_INTERVAL - minute() % DS_INTERVAL; // Time to wake up
  double sleep = (double)(min * 60 - second() + 10) * 1000 * 1000; // Sleep time (microsecond)

  // Double sleep confirmation
  if (min != DS_INTERVAL) {
    BLYNK_LOG("It's early. Go to sleep for %d minutes.", min);
    ESP.deepSleep(sleep, WAKE_RF_DEFAULT);
  }

  // Get and Send Sensor Data to Blynk
  sendSensor();

  // Sleep until wake up time
  BLYNK_LOG("Go to sleep for %d minutes.", min);
  ESP.deepSleep(sleep, WAKE_RF_DEFAULT);
}

 ESP8266のDeep SleepはESP.deepSleep(microsecond, WAKE_RF_DEFAULT)を実行すると即座に寝ます。起きたときはスケッチの続きを実行するのではなく、電源を入れ直したのと同じ状態になります。また、Deep Sleepから起きるためにはGPIO16とRSTを繋いでおく必要があります。

Deep Sleepの寝る時間はマイクロ秒で指定しますが、ESP8266は時計を持っていないので60分だと2分くらい早く目覚めます。どうも、内部的には指定した時間分の数値をデクリメントしているというような感じらしく、正確に起きることができません。

そのため、スケッチでは本当に起きる時間かを確認して早い場合は2度寝するようにしています。

起きる間隔はDS_INTERVALで指定しています。単位は分で2分から60分を設定することができます。この値が10だとxx時00分、10分、20分、30分、40分、50分に起きて、60だと毎時00分に起きます。実際には2度寝していますが...。

 

ライブラリ

使用するライブラリは次の4つです。

f:id:IntellectualCuriosity:20190824213511p:plain

NTPで時間を取得するのに使います。

f:id:IntellectualCuriosity:20190824214007p:plain

日時を簡単に扱うことができます。

f:id:IntellectualCuriosity:20190824214451p:plain

SHT31センサーのライブラリです。

f:id:IntellectualCuriosity:20190824214652p:plain

Blynkのライブラリです。読みずらい何とかスキーさんはBlynkの共同創業者の方らしいです。


Blynk

今回作る画面はこんな感じです。

Gauge2個、LCD、SuperChartで1,900エナジーになるので、初めてBlynkを使う人は課金なしで作れます。

f:id:IntellectualCuriosity:20190824221655p:plain

温度Gaugeの設定(ゲージの範囲は好きに設定しても大丈夫です。)

f:id:IntellectualCuriosity:20190824221851p:plain

湿度Gaugeの設定
f:id:IntellectualCuriosity:20190824222434p:plain

計測日時と電圧表示用のLCDの設定

f:id:IntellectualCuriosity:20190824222521p:plain

温度と湿度のグラフ用SuperChartの設定

f:id:IntellectualCuriosity:20190824222742p:plain

「+ Add Datastream」をタップして「温度」と「湿度」を追加してから、右の赤枠部分をタップして、それぞれの設定をします。

SuperChartの温度の設定

f:id:IntellectualCuriosity:20190824223046p:plain

SuperChartの湿度の設定

f:id:IntellectualCuriosity:20190824223208p:plain


おしまい