知的好奇心 for IoT

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

ベランダの温湿度センサーをDHT11から気圧も計れるBME280に変更した

部屋のセンサーはDHT11からDHT12にアップグレードしていましたが、ベランダのセンサーはDHT11のままでした。

このところ急に寒くなって、気温が零度を下回ることもありえる状況になってきましたが、DHT11では零度以下は計測できないんです。

部屋と同じDHT12では芸がないなぁと思って新しいセンサーを物色していたら、気圧も計れる凄いやつを見つけました。

BME280はボッシュ社のセンサーで、温度・湿度・気圧が計れてI2Cに対応しています。センサー自体は非常に小さいので秋月電子では基板に半田付けしたキットとして販売されていました。

仕様は以下のようになっていて、これなら真冬の旭川でも余裕な感じです。

  • 温度:-40 ~ 85℃ 精度±1℃
  • 湿度:0 ~ 100% 精度±3%
  • 気圧:300 ~ 1100hPa 精度±1hPa

センサーを替えるついでに、バッテリーもモバイルバッテリーに替えることにしました。実際に取り付けたモバイルバッテリーは秋葉原で600円くらいで購入したものですが、ダイソーで300円で買えるものと大きさ電池容量的に大差のないものです。

モバイルバッテリーが横長で今まで使っていたおかず容器に入らなくなったので、おかず容器も横長の300mlタイプのものに替えました。底に9つの空気穴を開けています。

f:id:IntellectualCuriosity:20171214203945j:plain
ベランダに吊るされるWiFi温湿度・気圧計入りおかず容器

 

BME280のArduinoライブラリの多くには温度・湿度・気圧の他にもう一つ「標高」を取得できる機能があります。しかし、これは海面の気圧を基準とした換算値を単純に返すだけのためまったく役にたちません。ちょっと天気がいい(気圧が高い)と地下にもぐっている地底人扱いされてしまいます。

※2017/12/30更新

標高は本当に意味がないので外して、代わりに動作モードと前回計測時刻を表示するように改良しました。

f:id:IntellectualCuriosity:20171230153919p:plain
温湿度・気圧計のBlynk画面

 

AE-BME280の接続方法

秋月電子の温湿度・気圧センサモジュールキット(AE-BME280)にはJ1~J3の半田ジャンパがあります。

ジャンパ設定(半田ジャンパ)

  • J1:I2C設定時のSDA用プルアップ抵抗の選択
  • J2:I2C設定時のSCL用プルアップ抵抗の選択
  • J3:I2C設定時には半田でジャンパします

写真のように、ぼくは全て半田ジャンパしています。

また、I2Cのアドレスは5番ピン(SDO)をVDDに接続すると0x77になるとマニュアルに書かれてあったので、基板上で接続しています。

I2Cのアドレスを0x77にするのは、使用するAdafruitのライブラリが0x77を使用するようになっていたからです。

使用しているESP8266ボード(Wio Node)とは次のように接続しています。

  • 1番ピン(VDD) <ー> 赤(3.3V)
  • 2番ピン(GND) <ー> 黒(GND)
  • 4番ピン(SDI, SDA) <ー> 白(GPIO4)
  • 6番ピン(SCK, SCL) <ー> 黄色(GPIO5)
f:id:IntellectualCuriosity:20171214200357j:plain
センサーモジュールのアップ

8ピンのピンソケットを使っているのは、単に6ピンのものを持っていなくて手持ちの部品で作ったからで、深い理由は全くありません …。

 

BlynkのWidget設定 ※2017/12/30更新

温度・湿度・気圧・標高用にGauge Widget4つ3つ使っています。

LABELの「.」は小数点のことで、表示したい桁数分「#」を書きます。「#」が一つもないと小数点以下は表示されません。

f:id:IntellectualCuriosity:20171214224601p:plain

f:id:IntellectualCuriosity:20171230154822p:plain

プログラムでDeep Sleepをオンオフできるようにしたので、その制御用のボタンを配置しています。Deep Sleepの間隔はSliderで指定します。

f:id:IntellectualCuriosity:20171214230028p:plain

動作モードと前回計測時刻の表示はLCD Widgetを使いました。

f:id:IntellectualCuriosity:20171230160026p:plain

 

スケッチ

画面のボタンでDeep Sleepを制御できるようにしたため、少しごちゃごちゃしてしまいました。

スケッチ中のBLYNK_CONNECTED()で、クラウドサーバー接続時にクラウドに送られていたボタンのオンオフ情報と間隔を取得しています。そのため、画面のボタンでDeep Sleepをオフにしても次にDeep Sleepから目覚めるまでは反映されません。

BME280で使用するI2CのピンはWire.begin(I2C_SDA, I2C_SCL)で自由に指定することができます。

※2017/12/30更新

/*
 * BME280Blynk
 * December 30, 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 <Wire.h>
#include <Adafruit_BME280.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <TimeLib.h>

// Set Blynk Auth Token and WiFi credentials.
const char *auth = "YourAuthToken";
const char *ssid = "YourNetworkName";
const char *pass = "YourPassword";

// Select I2C sensor pin and BME280
#define I2C_SCL 5 // WeMos D1 mini D1 or Wio Node Right Yellow
#define I2C_SDA 4 // WeMos D1 mini D2 or Wio Node Right White
Adafruit_BME280 bme; // I2C Address 0x77

// Set NTP
const char *NTP_SERVER = "ntp.nict.jp"; // National Institute of Information and Communications Technology
const int TIME_OFFSET = 9 * 60 * 60;    // UTC+9h (JST)

// Deep Sleep
#define TEXT_DS "Deep Sleep mode"
#define TEXT_RT "Real Time mode "
int ds_switch = 0;    // 0:Off 1:On
int ds_interval = 60; // minutes

BlynkTimer timer;
WidgetLCD lcd(V7);

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

/*
 * Send Sensor Data to Blynk
 */
void sendSensor() {
  char dateTime[17];
  getDateTime(dateTime);
  if (ds_switch == 1) {
    lcd.print(0, 0, TEXT_DS);
  } else {
    lcd.print(0, 0, TEXT_RT);
  }
  lcd.print(0, 1, dateTime);

  // Get data from BME280 sensor
  float t = bme.readTemperature();                  // C
  float h = bme.readHumidity();                     // %
  float p = bme.readPressure() / 100.0F;            // hPa
  
  Blynk.virtualWrite(V1, t);
  Blynk.virtualWrite(V2, h);
  Blynk.virtualWrite(V3, p);
  BLYNK_LOG2("Time:", dateTime);
  BLYNK_LOG2("Temperature:", t);
  BLYNK_LOG2("Humidity:", h);
  BLYNK_LOG2("Pressure:", p);
}

/*
 * Receive Data from Blynk at connected 
 */
BLYNK_CONNECTED() {
  Blynk.syncVirtual(V5);
  Blynk.syncVirtual(V6);
}

/*
 * Receive Data from Blynk
 *  Deep Sleep Switch
 */
BLYNK_WRITE(V5) {
  ds_switch = param.asInt();
  BLYNK_LOG2("ds_switch:", ds_switch);
}

/*
 * Receive Data from Blynk
 *  Deep Sleep interval time
 */
BLYNK_WRITE(V6) {
  ds_interval = param.asInt();
  BLYNK_LOG2("ds_interval:", ds_interval);
}

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

  // Uncomment 2 lines if you use Wio Node
  //pinMode(15, OUTPUT);      
  //digitalWrite(15,HIGH);

  Blynk.begin(auth, ssid, pass);
  timer.setInterval(2000L, sendSensor); // 2 seconds

  // setup BME280
  Wire.begin(I2C_SDA, I2C_SCL);
  if (!bme.begin()) {
      BLYNK_LOG("Could not find a valid BME280 sensor, check wiring!");
      while (1); // Hung up!
  }
  delay(100); // let sensor boot up

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

/*
 * Main Loop
 */
void loop() {
  if (ds_switch == 1) {
    Blynk.run(); // Get V5 data
    Blynk.run(); // Get V6 data

    // Confirm the time to wake up
    int min = ds_interval - minute() % ds_interval;
    if (min != ds_interval) {
      BLYNK_LOG("Go to sleep for %d minutes.", min);
      ESP.deepSleep((min * 60 - second() + 10) * 1000 * 1000, WAKE_RF_DEFAULT);
    }

    sendSensor();

    // Deep Sleep
    min = ds_interval - minute() % ds_interval;
    BLYNK_LOG("Go to sleep for %d minutes.", min);
    ESP.deepSleep((min * 60 - second() + 10) * 1000 * 1000, WAKE_RF_DEFAULT);
  } else {
    Blynk.run();
    timer.run();
  }
}

 

おしまい