2018年8月4日土曜日

ESP WROOM 02(ESP8266)でDeep Sleep(メモ)

以下のサイトを参考にしました。

@asusa9さんの「ESP8266の真骨頂Deep-Sleepモードの使い方
@anaptfoxさんの「MAKING THE ESP8266 LOW-POWERED WITH DEEP SLEEP
「じわじわ進む」さんの「ESP単体で30分のデータをまとめて送信
「電子工作と治具ツールの備忘録」さんの「ESP-WROOM-02のメモ(11):3つのSleepの使い分け
@exabugsさんの「ESP8266 (ESP-WROOM-02) で消費電力を抑えるには (スリープモードまとめ)

配線図


Deep Sleepモードを使うときは、IO16ピンとRSTピンを接続します。WakeUp時にIO16がLoになるのでResetがかかって最初から実行する仕組みです。

したがってスケッチはSetup()内に書いて、起動時に1回だけ実行されるようにします。

また、Arduino IDEからIO0を書き込みモード(GNDに接続)で書き込んだあと、プログラムが1回だけ実行されて、Sleep後WakeUpしても書き込みモードのためにプログラムが実行されません。一旦電源を切ってIO0を書き込みモード(3.3Vに接続)にして電源を再投入します。

Deep Sleepモードのテスト


Arduinoのスケッチ <ESP_WROOM_02_DeepSleep.ino>
/*
 * ESP8266 DeepSleep Test
 *
 * 2018.08.02
 *
 */
#include <ESP8266WiFi.h>

extern "C" {
#include "user_interface.h"
}

#define PERIOD 10

WiFiClient client;

const char* ssid = "WiFi APのssid";
const char* password = "WiFi APのpassword";

void setup()
{
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);
       
    int t = millis();

    Serial.begin(115200);
    delay(10);

    Serial.println("\r\nStart");

    WiFi.begin(ssid, password);  //  Wi-Fi APに接続
    while (WiFi.status() != WL_CONNECTED) {  //  Wi-Fi AP接続待ち
        delay(100);
    }

    Serial.print("WiFi connected\r\nIP address: ");
    Serial.println(WiFi.localIP());

    digitalWrite(LED_BUILTIN, LOW);
    
    t = millis() - t;
    t = (t < PERIOD * 1000) ? (PERIOD * 1000 - t) : 1;
    ESP.deepSleep(t * 1000, RF_DEFAULT);
    delay(1000);
}

void loop()
{
}

Amibientのサンプルスケッチ[スケッチ例]-[Ambient ESP8266 lib]-[ESP8266]-[Ambient_ESP_BME280_ds]をもとにしました。このスケッチはWiFi接続のみでAmbientには接続しません。

前回と同じようにOWON B35で電源電流を測定しました。1mV→10mA換算です。サンプリング周期は1sです。


Avg 2.285633333 mV
Max 13.37 mV
Min 0 mV

10秒毎にWakeUpし、動作時には70mA程度、スリープ時には0mAで推移しています。平均値は23mA程度ですが、Sleepの間隔を長くすれば消費電力は抑えられます。

単3電池を使うとModem Sleepだと1日程度しか持たないので(概算で2000mAh / 50mA = 40h)電池駆動する場合はDeep Sleepは必須かもしれません。

Ambientに送信するテスト


HDC1000を使うようにサンプルスケッチを改変しました。

HDC1000.hとHDC1000.cppをインクルードする必要があります。

Arduinoのスケッチ <Ambient_ESP8266_HDC1000_DeepSleep.ino>

/*
   ESP8266 & HDC1000 DeepSleep

   2018.08.02

*/
#include <ESP8266WiFi.h>
#include <Wire.h>
#include "Ambient.h"
#include "HDC1000.h"

#define TITLE_STR1  ("Ambient ESP8266 HDC1000 DeepSleep Test")
#define TITLE_STR2  ("2018.08.04")

#define PERIOD (60) // Sec

extern "C" {
#include "user_interface.h"
}

// Pin Assign (I2C)
#define SDA 14
#define SCL 13
#define RDY 12

// WiFi
const char* ssid = "WiFi APのssid";
const char* password = "WiFi APのpassword";

// Ambient
const unsigned int channelId = <Ambientchannel id>;
const char* writeKey = "Ambientのwarite key";

WiFiClient client;
Ambient ambient;

HDC1000 hdc1000;

void setup()
{
  float temp, humid;
  char humidbuf[12];

  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, HIGH);

  int t = millis();
  //wifi_set_sleep_type(LIGHT_SLEEP_T);

  Serial.begin(115200);
  delay(100);

  Serial.println("\r\nStart");
  Serial.println(TITLE_STR1);
  Serial.println(TITLE_STR2);

  // WiFi
  WiFi.begin(ssid, password);  //  Wi-Fi APに接続
  while (WiFi.status() != WL_CONNECTED) {  //  Wi-Fi AP接続待ち
    delay(100);
  }

  Serial.print("WiFi connected\r\nIP address: ");
  Serial.println(WiFi.localIP());

  hdc1000.begin(SDA, SCL, RDY);
  ambient.begin(channelId, writeKey, &client);
  
  // HDC1000
  Serial.print("Manufacture ID: ");
  Serial.println(hdc1000.readId(), HEX);

  temp = hdc1000.readTemperature();
  humid = hdc1000.readHumidity();

  Serial.print("temp: ");
  Serial.print(temp);
  Serial.print(" DegC,  humid: ");
  Serial.println(humid);

  // Ambient
  ambient.set(1, temp);                // データーがint型かfloat型であれば、直接セットすることができます。
  dtostrf(humid, 3, 1, humidbuf);      // データーの桁数などを制御したければ自分で文字列形式に変換し、
  ambient.set(2, humidbuf);            // セットします。

  ambient.send();

  digitalWrite(LED_BUILTIN, LOW);
  
  t = millis() - t;
  t = (t < PERIOD * 1000) ? (PERIOD * 1000 - t) : 1;
  ESP.deepSleep(t * 1000, RF_DEFAULT);
  delay(1000);
}

void loop()
{
}

こちらも動作しているように見えるのですが、Ambientのデータにときどき欠損が見られます。



Ambient.cppのDebugモードを有効にして

#define AMBIENT_DEBUG 1

Arduinoのシリアルモニタに表示させてみましたが、データ送信は行われている感じです。


Ambientの「諸元/制限」があるので何か制限に引っかかっているのかもしれません。

ともかく、データを送れば時刻付きでグラフ化してもらえる便利なサービスだと思います。

「じわじわ進む」さんの「ESP単体で30分のデータをまとめて送信」で紹介されているThingSpeak.com(Math Works運営(@@;)も試してみようと思います。

Light Sleepモード


ESP8266のドキュメント「ESP8266 Low Power Solutions」の「3. Light Sleep」に以下のように書いてありました。



素直に読めば「Light Sleep」では「ペリフェラルからの信号、割り込みには反応しない」ので「GPIOに信号(LまたはH)を受け取る必要があります」ということになります。やはり外部割り込みが必要そうです。

Deep SleepモードでWakeUpに使うIO16(信号出力)はLight SleepモードのWakeUp(信号入力)には使えないようです。

HDC1000が壊れているっぽい(読み取り値がおかしい)のでAliExpressでBME280モジュールを発注してありそろそろ届く頃です。

健康のためにも、なんとかこの猛暑中に対応したい(@@;