IoT開発(5)
ESP-WROOM-02をDeepSleepで長時間駆動させる
どもです。
この記事は、以下の記事の続きです。
- IoT開発(1)-ESP-WROOM-02のセットアップ
- IoT開発(2)-ESP-WROOM-02で気温測定
- IoT開発(3)-ESP-WROOM-02でデータを送信
- IoT開発(4)-ESP-WROOM-02を電池で駆動
本エントリでは、ESP-WROOM-02を電池で長時間させる方法について書きます。
1.DeepSleep
ESP-WROOM-02には、「DeepSleep」というモードがあります。
ESP-WROOM-02/ESP8266の仕様書によれは、このモードは以下のような場合に使用します。
- WiFi接続を維持する必要が無い
- データ送信の間隔が長い
具体例として、
- 100秒ごとに温度を測定する
- 300秒スリープし、APに接続するために0.3~1.0秒を要する
という場合が挙げられています。
1.1.復帰の方法
DeepSleepモードから復帰する方法は、ボタンでの復帰とタイマーでの復帰があります。
今回のエントリでは、「タイマーでの復帰」を採用します。
2.回路
DeepSleepモードを使用する際には、回路をこれまで使用してたものから変更する必要があります。
変更点は、「IO16」を「RST」につなげる、という点です。
「IO16」と「RST」をつなげることで、DeepSleepモードから復帰させられるようになります。
具体的な回路図は、下記になります。
3.プログラム
DeepSleepモードを使用するにあたり、コードに対して変更を行っています。
変更した後のコードは、下記になります。
#include <SPI.h>
#include <ESP8266WiFi.h>
#include <Wire.h>
#include "Ambient.h"
extern "C" {
#include "user_interface.h"
}
#define _DEBUG 0
#if _DEBUG
#define DBG(...) { Serial.print(__VA_ARGS__); }
#define DBGLED(...) { digitalWrite(__VA_ARGS__); }
#else
#define DBG(...)
#define DBGLED(...) { digitalWrite(__VA_ARGS__); }
//#define DBGLED(...)
#endif /* _DBG */
#define LED 4
#define ERR_LED 5
#define CS_E 15
const char* ssid = "Buffalo-G-D0F8";
const char* password = "prjhgbvtvcich";
unsigned int channelId = 23197;
const char* writeKey = "39f9577973a01df0";
WiFiClient client;
Ambient ambient;
const float temperature_min = -55.0;
const float temperature_max = 150.0;
void setup()
{
#ifdef _DEBUG
Serial.begin(115200);
delay(20);
#endif
DBG("Start");
pinMode(LED, OUTPUT);
pinMode(ERR_LED, OUTPUT);
WiFi.begin(ssid, password);
int i = 0;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
DBGLED(LED, i++ % 2);
DBG(".");
}
DBGLED(LED, LOW);
DBGLED(ERR_LED, LOW);
DBG("WiFi connected\r\n");
DBG("IP address: ");
DBG(WiFi.localIP());
DBG("\r\n");
ambient.begin(channelId, writeKey, &client);
DBG("Set SPI to communicate with MDK001");
DBG("\r\n");
pinMode(CS_E, OUTPUT);
digitalWrite(CS_E, HIGH);
//Initialize SPI configuration.
SPI.begin();
SPI.setDataMode(SPI_MODE3);
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV8);
digitalWrite(CS_E, LOW);
SPI.transfer(0x54);
delay(240);
}
float get_temperature()
{
uint16_t readVal = 0;
float temp = 0;
readVal = (uint16_t)SPI.transfer(0) << 8; //Upper 8bit.
readVal = readVal | SPI.transfer(0);
DBG("readVal = ");
DBG(readVal, HEX);
DBG("\r\n");
readVal = readVal >> 3;
if (0x1000 & readVal) {
readVal = (uint32_t)readVal - 8192;
}
temp = ((float)((int16_t)readVal)) / 16.0;
return temp;
}
void loop()
{
DBGLED(LED, 1);
DBGLED(ERR_LED, 0);
uint16_t readVal = 0;
float temp = 0;
/*
* 測定結果が、センサーの「精度」の範囲に収まっているか確認する。
* 収まっていない場合には、再度測定を実施しなおす。
* (ただし、測定の間隔は1秒空ける。)
*/
do {
DBGLED(ERR_LED, 1);
temp = get_temperature();
DBG("temp = ");
DBG(temp, HEX);
DBG("\r\n");
delay(1000);
} while((temp < temperature_min)|| (temperature_max < temp));
DBGLED(ERR_LED, 0);
ambient.set(1, temp);
ambient.send();
DBGLED(LED, 0);
//Sleep 5 minutes.
ESP.deepSleep(5 * 60 * 1000 * 1000, WAKE_RF_DEFAULT);
delay(1000); //Dummy.
}
3.1.コードの解説
簡単ですが、変更点を中心にコードを解説します。
これまでのコードからの主な変更点として、下記が挙げられます。
wifi_set_sleep_type()
の削除- 測定結果の判定~やり直し
3.1.1.wifi_set_sleep_type()
の削除
これまでのコードでは、setup()の先頭で、wifi_set_sleep_type()
メソッドを削除しています。
wifi_set_sleep_type()
メソッドで指定可能な引数は、以下のように定義されています。
typedef enum {
NONE_SLEEP_T = 0,
LIGHT_SLEEP_T,
MODEM_SLEEP_T
} sleep_type_t;
見ての通り、DeepSleepモードに対応する値がありません。
今回の目的である、DeepSleepモードを使用するにあたり、この設定は不要なので、削除しました。
3.1.2.測定結果の判定~やり直し
これまで使用してきた温度センサーMDK001(ADT7310)の測定範囲は、-55℃~+150℃となっています。
これまでのエントリで使用してきたプログラムでは、この判定を行わず、取得できた値をそのまま出力/送信していましたが、それではまずいので、これを機に修正を行っています。
なお、範囲外の値を取得した場合には、「正常な値が取得できるまで測定をやり直す」という動作にしています。
この処理についても、測定の再実行の回数に制限を設けるなどの対応が本来は必要です。
4.測定結果
ここまでで書いてきた回路、およびプログラムを使用して、1日気温を測定した結果をグラフ化したのが、下記です。
途中で値が「0」に落ちてしまっています。
しかしそれ以外は、温度が測定ができています。
最高気温も30℃を越えており、とても暑い一日でした。
測定結果も、その体感に一致しています。
ディスカッション
コメント一覧
まだ、コメントがありません