知的好奇心 for IoT

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

温湿度計にOLEDを追加して、部屋置き用に光センサーも付けて暗いと消灯するようにした

ガイガーカウンターにOLED(有機ELディスプレイ)を付けたら思いの外良かったので、温湿度計にも付けてみました。OLEDって物凄く明るいので、常時部屋置きするためにCDSセル(光センサー)も付けて、周りが暗いとOLEDも消えるようにしました。

ハーフサイズのブレッドボードに収めることができました。

f:id:IntellectualCuriosity:20180909230004j:plain

使っているもの

安いものが多いので、今回は全てaitendoさんで揃えてみました。

 

回路図

回路図はこんな感じです。

f:id:IntellectualCuriosity:20180910220001p:plain

「SSD1036」と書いてあるのがOLEDです。OLEDとBME280はI2C接続なので「SCL」を「D1(GPIO5)」に「SDA」を「D2(GPIO4)」に繋ぎます。

WeMos D1 miniの端子とArduinoの対応表をホームページから抜粋しました。

f:id:IntellectualCuriosity:20180910221855p:plain

WeMos D1 miniのアナログ入力端子「A0」は、分圧用の抵抗が内蔵されていて3.3V(電源電圧)まで加えることができるのでとっても便利です。

CDSセルと直列に10kΩの抵抗を繋げて、中間の電圧を測ることで明るさを検出しています。

 

Blynk

今回もIoTプラットフォームにはBlynkを使っています。機器側にもOLEDを付けているので、ネットに繋がずにスタンドアローンで動作できるように、D7(GPIO13)端子をGND(LOW)にするとWiFiが無くても動くようにしました。

実行時の画面

f:id:IntellectualCuriosity:20180917163939p:plain

今回使ったWidgetはお馴染みのGaugeとお高いSuperChartです。設定は次のようにしています。

温度設定(Gauge)

f:id:IntellectualCuriosity:20180917164215p:plain

「#」の数で小数点以下の桁数を指定できるのですが、今回は全て少数第2位までにしています。気圧を少数第2位まで表示すると、機器を高く持ち上げるだけでも数値が変化するのが面白かったので、全て揃えてみました。

湿度設定(Gauge)

f:id:IntellectualCuriosity:20180917171223p:plain

気圧設定(Gauge)

f:id:IntellectualCuriosity:20180917171429p:plain

グラフ設定(SuperChart)

f:id:IntellectualCuriosity:20180917171706p:plain f:id:IntellectualCuriosity:20180917173251p:plain

高機能でお高いSuperChartは設定がちょっと面倒です。4つまでのデータを同じグラフに表示できるようになっていて、「+ Add DataStrem」で表示するデータを追加していきます。追加したら、右側の設定アイコンで各データの設定を行います。

f:id:IntellectualCuriosity:20180917174037p:plain f:id:IntellectualCuriosity:20180917174102p:plain

f:id:IntellectualCuriosity:20180917174206p:plain

「DECIMALS」で小数点以下の桁数を指定できそうなんですが、何故かできないみたいです。

 

スケッチ

今回のスケッチはこんな感じです。

/*
 * BME280BlynkOLED
 * Septembe 17, 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 <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define NETWORK_MODE    1
#define STANDALONE_MODE 2
#define MODE_PIN        13
#define ILLUMINANCE     50

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

// for OLED
#define OLED_RESET -1
Adafruit_SSD1306 display(OLED_RESET);
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

Adafruit_BME280 bme;
BlynkTimer timer;
int runmode;

/*
 * Send Sensor Data to Blynk
 */
void sendSensor() {
  // 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("Temperature:", t);
  BLYNK_LOG2("Humidity:", h);
  BLYNK_LOG2("Pressure:", p);
  BLYNK_LOG("");

  // Display
  int illuminance = analogRead(A0);
  int color;
  if (illuminance < ILLUMINANCE) {
    color = BLACK;
  } else {
    color = WHITE;
  }
  display.setTextColor(color);
  display.setCursor(0, 0);
  display.fillRect(0, 0, 127, 7, BLACK);
  display.setTextSize(1);
  if (runmode == NETWORK_MODE) {
    display.print("Network        L:" + String(illuminance) + " \n\n");
  } else {
    display.print("Standalone     L:" + String(illuminance) + " \n\n");
  }
  display.setTextSize(2);
  // Temperature
  display.fillRect(0, 15, 127, 31, BLACK);
  display.print("  " + String(t) + "C\n");
  // Humidity
  display.fillRect(0, 31, 127, 47, BLACK);
  display.print("  " + String(h) + "%\n");
  // Pressure
  display.fillRect(0, 47, 127, 63, BLACK);
  display.print(String(p) + "hPa");
  display.display();
}

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

  // Netowrk or Standalone
  if (digitalRead(MODE_PIN) == HIGH) {
    runmode = NETWORK_MODE;
    Blynk.begin(auth, ssid, pass);
  } else {
    runmode = STANDALONE_MODE;
  }

  // setup BME280
  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 OLED
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  

  timer.setInterval(2000L, sendSensor); // 2 seconds
}

/*
 * Loop
 */
void loop() {
  if (runmode == NETWORK_MODE) {
    Blynk.run();
  }
  timer.run();
}

追加ライブラリ

BME280で使ったライブラリは次の2つです。

f:id:IntellectualCuriosity:20180917183655p:plain

f:id:IntellectualCuriosity:20180917183748p:plain

OLEDモジュール「SSD1306」で使ったライブラリは次の2つです。

f:id:IntellectualCuriosity:20180917183822p:plain

f:id:IntellectualCuriosity:20180917183853p:plain

Adafruit SSD1306を使う上での注意点

ヘッダーファイルの修正

「Adafruit SSD1306」ライブラリをこのOLEDモジュールで使う場合は、ヘッダーファイルを修正する必要があります。

修正するヘッダーファイル「Adafruit_SSD1306.h」は、スケッチフォルダの「libraries」の「Adarfuit_SSD1306」の中にあります。

73行目から75行目までが使用するSSD1306のサイズの選択で、使用するサイズのコメントを外して指定するようになっています。使用するOLEDモジュールは128x64ピクセルなので73行目のコメントを外して、他をコメントにします。

73:   #define SSD1306_128_64
74://   #define SSD1306_128_32
75://   #define SSD1306_96_16

使い方を学ぶ方法

このライブラリの使い方は、Arduino IDEの[ファイル]-[スケッチ例]-[Adarfruit SSD1306]-[ssd1306_128x64_i2c]で表示できるサンプルスケッチから学びました。

サンプルスケッチを実行するには61行目のdisplay.begin(SSD1306_SWITCHCAPVCC, 0x3D);display.begin(SSD1306_SWITCHCAPVCC, 0x3C);に変更する必要があります。

書く前に消す

文字を書くのは簡単で、display.print("Hello!");のようにSerial.print()と同じような感じですが、この文で書かれる先はバッファです。バッファの内容を表示するためにはdisplay.display();を実行する必要があります。また、display.print()は紙に鉛筆で書くのと似ていて、消さないと文字が重ね書きされてしまいます。そのため予め書きたい場所を消しておく必要があるので注意してくださいね。

注意が必要な機能 

ちょっと注意が必要なのが表示用のバッファをクリアするdisplay.clearDisplay();で、どうもこれの実行に随分時間がかかるみたいなんです。最初、データの書き換え前にdisplay.clearDisplay();を入れていたら、Blynkが正常に動作しなくなって頻繁に接続が切れていたんです。データを書き換える部分を黒の矩形で塗るように変更したら、ピタッと症状が出なくなりました。

 

おわり