先日、「M5Stack CoreInk開発キット」用の環境構築(記事は こちら)、およびディスプレイに文字を表示する方法の確認(記事は こちら)を行いました。
「M5Stack CoreInk」をつかって、最終的には以下のようなIoTデバイスをつくりたいと思っています。
- 「ENV IIIユニット」をつかって、一定時間毎に温度・湿度を測定する。
- 測定した温度・湿度をディスプレイに表示する。また、次に温度・湿度を測定するまで、その表示内容を保持する。
- 測定した温度・湿度をAmbientに送信する。
- ESP32などの電源をOFFにするモード(ここではスタンバイモードと呼ぶことにします)を活用することで、内蔵バッテリーのみで長期間連続稼働させる(例えば10分毎の測定で数週間稼働させる、など)。
- 可能であれば、外部から電源供給して、より長期間(例えば数ヶ月)連続稼働させる、もしくは小型ソーラーパネルなどを接続することで常時稼働させる。
今回は、スタンバイモードの使い方を確認してみます。
前回の記事(こちら)で、「ENV IIIユニット」で測定した温度・湿度をディスプレイに表示するスケッチを作成済みです。
まずは、ここで測定した温度・湿度をAmbientに送信するようにしてみます。
あわせて、内蔵バッテリー電圧も測定し、その値もディスプレイに表示、Ambientにも送信するようにしておきます。
内蔵バッテリー電圧の測定方法は、「ファイル」>「スケッチ例」>「M5-CoreInk」>「FactoryTest」に記載されています。
#include "M5CoreInk.h"
#include "UNIT_ENV.h"
#include "esp_adc_cal.h"
#include <WiFi.h>
#include "Ambient.h"
WiFiClient client;
Ambient ambient;
SHT3X sht30;
unsigned int channelId = XXXXX;
const char* writeKey = "XXXXXXXX";
const char* ssid = "XXXXXXXX";
const char* password = "XXXXXXXX";
Ink_Sprite InkPageSprite(&M5.M5Ink);
float getBatVoltage() {
analogSetPinAttenuation(35, ADC_11db);
esp_adc_cal_characteristics_t *adc_chars = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 3600, adc_chars);
uint16_t ADCValue = analogRead(35);
uint32_t BatVolmV = esp_adc_cal_raw_to_voltage(ADCValue, adc_chars);
float BatVol = float(BatVolmV) * 25.1 / 5.1 / 1000;
return BatVol;
}
void setup() {
M5.begin(true, true, true); // InkEnable, wireEnable, SpeakerEnable
if(!M5.M5Ink.isInit()) {
Serial.printf("Ink Init faild");
}
M5.M5Ink.clear();
if(InkPageSprite.creatSprite(0, 0, 200, 200, true)!=0) {
Serial.printf("Ink Sprite creat faild");
}
Serial.printf("Connecting to %s\n", ssid);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.printf("\nWiFi connected\n");
}
void loop() {
if(sht30.get()!=0) {
return;
}
float temp = sht30.cTemp;
float humi = sht30.humidity;
float volt = getBatVoltage();
char strTemp[6], strHumi[6], strVolt[6];
sprintf(strTemp, "%.2f", temp);
sprintf(strHumi, "%.2f", humi);
sprintf(strVolt, "%.2f", volt);
Serial.printf("Temperature: %.2f, Humidity: %.2f\n", temp, humi);
InkPageSprite.clear();
InkPageSprite.drawString(20, 0, "Temperature", &AsciiFont8x16);
InkPageSprite.drawString(20, 16, strTemp, &AsciiFont24x48);
InkPageSprite.drawString(20, 64, "Humidity", &AsciiFont8x16);
InkPageSprite.drawString(20, 80, strHumi, &AsciiFont24x48);
InkPageSprite.drawString(20, 128, "Bat Voltage", &AsciiFont8x16);
InkPageSprite.drawString(20, 144, strVolt, &AsciiFont24x48);
InkPageSprite.pushSprite();
ambient.begin(channelId, writeKey, &client);
ambient.set(1, temp);
ambient.set(2, humi);
ambient.set(3, volt);
ambient.send();
delay(30000);
}
これで、30秒毎に温度・湿度・内蔵バッテリー電圧を測定し、ディスプレイの表示内容が更新されるとともに、そのデータがAmbientに送信されるようになりました。
次に、データを送信してから次のデータを測定するまでの30秒間、スタンバイモードに移行するようにしてみます。
1回データを送るたびに再起動することになるので、全ての処理をsetup()の中に移動します。
その上で、処理の最後に「M5.shutdown()」を追加します。
ちなみに、「M5Stack CoreInk」にUSBで電源供給している場合は、「M5.shutdown()」でスタンバイモードに移行できません。そのため「M5.shutdown()」の後に、通常のディープスリープへの移行コマンドを追加しておきます。これで、内蔵バッテリーで動作している時はスタンバイモードに移行、USBで給電している場合はディープスリープに移行するようになるはずです。
#include "M5CoreInk.h"
#include "UNIT_ENV.h"
#include "esp_adc_cal.h"
#include <WiFi.h>
#include "Ambient.h"
WiFiClient client;
Ambient ambient;
SHT3X sht30;
unsigned int channelId = XXXXX;
const char* writeKey = "XXXXXXXX";
const char* ssid = "XXXXXXXX";
const char* password = "XXXXXXXX";
Ink_Sprite InkPageSprite(&M5.M5Ink);
float getBatVoltage() {
analogSetPinAttenuation(35, ADC_11db);
esp_adc_cal_characteristics_t *adc_chars = (esp_adc_cal_characteristics_t *)calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 3600, adc_chars);
uint16_t ADCValue = analogRead(35);
uint32_t BatVolmV = esp_adc_cal_raw_to_voltage(ADCValue, adc_chars);
float BatVol = float(BatVolmV) * 25.1 / 5.1 / 1000;
return BatVol;
}
void setup() {
M5.begin(true, true, true); // InkEnable, wireEnable, SpeakerEnable
if(!M5.M5Ink.isInit()) {
Serial.printf("Ink Init faild");
}
M5.M5Ink.clear();
if(InkPageSprite.creatSprite(0, 0, 200, 200, true)!=0) {
Serial.printf("Ink Sprite creat faild");
}
Serial.printf("Connecting to %s\n", ssid);
WiFi.begin(ssid, password);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.printf("\nWiFi connected\n");
if(sht30.get()!=0) {
return;
}
float temp = sht30.cTemp;
float humi = sht30.humidity;
float volt = getBatVoltage();
char strTemp[6], strHumi[6], strVolt[6];
sprintf(strTemp, "%.2f", temp);
sprintf(strHumi, "%.2f", humi);
sprintf(strVolt, "%.2f", volt);
Serial.printf("Temperature: %.2f, Humidity: %.2f\n", temp, humi);
InkPageSprite.clear();
InkPageSprite.drawString(20, 0, "Temperature", &AsciiFont8x16);
InkPageSprite.drawString(20, 16, strTemp, &AsciiFont24x48);
InkPageSprite.drawString(20, 64, "Humidity", &AsciiFont8x16);
InkPageSprite.drawString(20, 80, strHumi, &AsciiFont24x48);
InkPageSprite.drawString(20, 128, "Bat Voltage", &AsciiFont8x16);
InkPageSprite.drawString(20, 144, strVolt, &AsciiFont24x48);
InkPageSprite.pushSprite();
ambient.begin(channelId, writeKey, &client);
ambient.set(1, temp);
ambient.set(2, humi);
ambient.set(3, volt);
ambient.send();
M5.shutdown(30);
esp_sleep_enable_timer_wakeup(30*1000*1000);
esp_deep_sleep_start();
}
void loop() {}
起動すると、本体上部の緑LEDが点灯し、各処理を実行します。
処理が終わるとLEDが消灯し、スタンバイモードに移行します。この間もディスプレイには温度、湿度、バッテリー電圧が表示され続けています。
なお、スタンバイモードから復帰する際には、処理が最初からスタートすることになるので、ディスプレイが一旦暗くなってから真っ白になり、その後に改めてデータが表示されます。
これで所望の処理ができた訳ですが、動作内容だけでは、本当にスタンバイモードに移行できているのかどうかが分かりません。
そのため、テスターを使って実際に消費電流値を確認してみたいと思います。
「M5Stack CoreInk」の回路図(こちら)を確認したところ、電源周りの接続は以下のようになっています(間違っているかもしれません)。
USB給電すると「CP2104」が動作してしまいますが、「EXT_5VI」に給電するのであれば、内蔵バッテリーで動作するのとほぼ同じ状態になるはずです。
そのため、単三型Ni-MH電池4本を「EXT_5VI」に給電し、その電源ライン上の電流値を測定することとします。
以下のようにテスターをつなぎ、内蔵バッテリーが満充電のとき(内蔵バッテリーに充電していないときには、本体下部の赤LEDが消灯します)の、動作中およびスタンバイ中の電流値を測定しました。
その結果、動作中は数十mA〜100mA程度の電流消費が数秒間継続し、スタンバイ中の電流消費は 0.07mA程度でした。
非常に低電力です。
ちなみに、前述の電源周りの回路図を見るとわかるとおり、GROVEポートの電源端子「EXT_5VO」も、スタンバイモードの間は電源遮断されています。よって、スタンバイ中は「ENV IIIユニット」も電流消費しません。
上記の結果より、もしも1回の動作で100mAの電流消費が10秒間継続すると仮定すると、10分毎にデータ測定する場合の平均消費電流値は、
100mA × 10sec / 600sec + 0.07mA = 1.74mA
となります。
内蔵バッテリー容量は 390mAh なので、
390mAh / 1.74mA = 224.1h = 9.3日
と、10日近く連続稼働できる計算になります。
ちなみに、同じ方法でUSBポートから給電したときの電流消費を調べたところ、動作中の電流消費は同等でしたが、ディープスリープ中の電流消費は 7.9mA 程度と、スタンバイ中の電流消費の100倍の値となりました。