M5Stamp S3でできること 〜ESP-NOWでデータ送信する

先日、「M5Stamp S3」の消費電流値を調査しました(記事は こちら)。
1分毎にデータをWebサーバに送信し、送信完了したら低電力モードに移行するという処理の場合、単三型Ni-MH電池(2000mAh)4本で「76.8日」も連続稼働できる見込みという結果が得られました。

ところで、この調査をしていて気になったのが、比較対象として一緒に調査した「micro:bit V2.21」の結果です。
micro:bitにはWi-Fi通信機能がないため、micro:bit独自の「無線」機能で別のmicro:bit(親機)にデータを送信するという条件で調査を行いました。
以下のように、電源のある場所に、micro:bit親機とESP32などを有線でつないだ「ゲートウェイ」を設置しておき、ESP32経由でWebサーバにデータ送信することを想定しています。

この調査の結果、「micro:bit V2.21」で1回の処理にかかる時間は「0.4秒弱」となりました。
他のデバイスはいずれも直接Wi-Fiでデータを送信しているため、1回の処理にどうしても「1秒前後」の時間がかかっており、それらに比べると「micro:bit V2.21」は格段に短時間で処理できています。

ということは、「M5Stamp S3」などでも、micro:bitと同じようにゲートウェイを設置する方式にし、よりシンプルな無線通信でデータ送信すれば、処理時間が短くなり、乾電池駆動でも、より長期間にわたり稼働できるのではないか?と考えました。

そんな訳で、今回は「ESP-NOW」という無線通信方式を使って調査してみることにしました。

「ESP-NOW」は、Espressif社独自の無線通信プロトコルで、「ESP8266」や「ESP32」チップで利用できます。「Quick Response」「Ultra-low Power」「Long-distance Communication」といった特長があるようで、今回の目的にもピッタリです。

「M5Stamp S3」から直接Wi-Fiでデータ送信する代わりに、「M5Stamp S3」からゲートウェイのESPデバイスに「ESP-NOW」でデータ送信し、ゲートウェイからWi-FiでWebサーバにデータ送信することとします。

上が従来の方式で、「M5Stamp S3」からWi-Fiで、直接Webサーバにデータを送信しています。
それに対し、下が今回の方式で、「M5Stamp S3」からESP-NOWでゲートウェイにデータを送信し、ゲートウェイからWi-Fiで、Webサーバにデータを送信します。

調査対象となる「M5Stamp S3」用のスケッチはこちらです。

#include <FastLED.h>
#include <esp_now.h>
#include <WiFi.h>

#define NUM_LEDS 1
#define LED_PIN 21
CRGB leds[NUM_LEDS];

uint8_t recvAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; // 受信デバイスのMACアドレス

typedef struct struct_message {
  uint16_t chipid;
  float    val0;
} struct_message;
struct_message myData;

esp_now_peer_info_t peerInfo;

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  USBSerial.print("Packet Send ");
  USBSerial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
  esp_deep_sleep_start();
}

unsigned long interval = 30; // unit:sec

void setup() {
  USBSerial.begin(115200);
  USBSerial.println("ESP-NOW Test(Send)");
  esp_sleep_enable_timer_wakeup(interval*1000*1000);

  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  leds[0] = CRGB::Green;
  FastLED.show();

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  if (esp_now_init() == ESP_OK) USBSerial.println("Init Success");
  else ESP.restart();

  memcpy(peerInfo.peer_addr, recvAddress, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;
  if (esp_now_add_peer(&peerInfo) == ESP_OK) USBSerial.println("Add Peer Success");
  else ESP.restart();

  esp_now_register_send_cb(OnDataSent);

  myData.chipid = (uint16_t)((ESP.getEfuseMac())>>32);
  myData.val0 = random(0, 1000) / 10.0;
  esp_now_send(recvAddress, (uint8_t *) &myData, sizeof(myData));

  leds[0] = CRGB::Black;
  FastLED.show();
}

void loop() {}

「recvAddress[]」で、受信側(ゲートウェイ)のESPデバイスのMACアドレスを設定しておきます。
起動したらESP-NOWの初期化を行い、「チップID」と「ランダムな値(3桁の整数を10で割った値)」をWebサーバに送信します。送信完了するとディープスリープに移行し、30秒たってから再起動、以降は同じ処理を繰り返します。

受信側(ゲートウェイ)のESPデバイス用のスケッチはこちらです。
ESPデバイスは何でもいいのですが、今回は「M5StickC」を使いました。
また、今回はただ単にESP-NOWで送られてきたデータを受信し、LCD画面に表示しているだけで、UARTでの転送などの処理は入れていません。

#include <M5StickC.h>
#include <esp_now.h>
#include <WiFi.h>

typedef struct struct_message {
  uint16_t chipid;
  float    val0;
} struct_message;
struct_message myData;

void OnDataRecv(const uint8_t *mac_addr, const uint8_t *incomingData, int len) {
  memcpy(&myData, incomingData, sizeof(myData));
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.print("ChipID : ");
  M5.Lcd.println(myData.chipid);
  M5.Lcd.print("val0 : ");
  M5.Lcd.println(myData.val0);
}

void setup() {
  M5.begin();
  M5.Lcd.setRotation(3);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0, 0);
  M5.Lcd.println("ESP-NOW Test(Recv)");

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  if (esp_now_init() == ESP_OK) M5.Lcd.println("Init Success");
  else ESP.restart();

  // 受信デバイスのMACアドレス表示(ここで表示される内容を送信デバイス用スケッチに記載する)
  Serial.println(WiFi.macAddress());

  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {}

Ni-MH電池4本を「M5Stamp S3」のUSBポート(電源端子名は「VIN_5V」)につなぎ、前回と同様に電流波形を測定します。

調査結果の電流波形はこちらです。処理を4回行い、その時の消費電流の変化を重ねてグラフ表示しました。

あっというまに処理が終わっています。

消費電流グラフなどから、1回の処理にかかる時間やその間の消費電流値などをまとめてみました。
「M5Stamp S3」から直接Wi-Fiでデータ送信した時の結果と並べて記載しています。

処理時間(ms)消費電流(mA)電源電圧(V)消費電力(mW)
動作時待機時動作時待機時動作時待機時
M5Stamp S3(Wi-Fi)822.559.050.285.395.55318.281.55
M5Stamp S3(ESP-NOW)48.545.760.265.785.95264.371.53

一定時間間隔で間欠動作させた時の平均消費電流値を机上計算しました。

間欠動作時の平均消費電流値(mA)
1分毎10分毎1時間毎
M5Stamp S3(Wi-Fi)1.090.360.29
M5Stamp S3(ESP-NOW)0.300.260.26

また、この結果を元に、単三型Ni-MH電池(2000mAh)での稼働日数を机上計算しました。

単三型Ni-MH電池での稼働日数
1分毎10分毎1時間毎
M5Stamp S3(Wi-Fi)76.8231.1284.0
M5Stamp S3(ESP-NOW)280.9316.0319.8

1回の処理時間は、Wi-Fiを使った場合の「822.5ms」に対し、ESP-NOWを使った場合は「48.5ms」と大幅に時間短縮されています。
また処理中の平均消費電流値も、Wi-Fiを使った場合の「59.05mA」に対し、ESP-NOWを使った場合は「45.76mA」と、やや小さくなっています。
1分毎に処理する場合の、単三型Ni-MH電池4本での稼働日数は、Wi-Fiを使った場合の「76.8日」に対し、ESP-NOWを使った場合は「280.9日」と大幅に伸びました。

電池交換せずに9ヶ月も連続稼働できるということで、これならIoTデバイスとして活用する際の、とても良い選択肢となりそうです。


なお、私がM5Stack、M5StickCの使い方を習得するのにあたっては、以下の書籍を参考にさせていただきました。


ごく基本的なところから、かなり複雑なスケッチや、ネットワーク接続など、比較的高度なものまで、つまづかずに読み進めていけるような構成になっており、大変わかりやすい本です。


このサイトで書いている、M5Stackシリーズ(M5Stack、M5StickCなど)に関するブログ記事を、「さとやまノート」という別のブログページに、あらためて整理してまとめました。

他のM5Stackシリーズの記事にも興味のある方は「さとやまノート」をご覧ください。