ESP32でESP-NOWを使って通信してみよう

ESP-NOWのイメージ図

今回は、ESP32とM5StickC PLUSでESP-NOWを試してみました。

ESP-NOWとは、ESP32やE8266間で無線でデータを送受信できる通信方法 です。無線LANのIEEE 802.11を使用して実現しているようですが、WiFiネットワークではないためアクセスポイントの必要がありません。 また、Bluetoothのようなセントラル・ペリフェラルといった複雑なペアリングの必要もないので簡単に開発できます。 ESP-NOWに興味のある方またはESP-NOWをやってみようという方は、この記事をぜひ参考になさってみて下さい。

はじめに

ESP32とESP32 PICOが内蔵されているM5StickC PLUSを使って、ESP-NOWを試してみました。ESP32を受信機として、M5StickC PLUSを送信機にしました。ESP-NOWを使って送信するには、受信機のMACアドレスが分かれば送信可能です。 正確には複数台に送るブロードキャスト方式もありますが、ここでは扱いません。

M5StickC PLUSのボタンを押すたびにESP32のLEDが点滅するプログラムを作っていきたいと思います。

VKLSVAN ESP32 デュアルコア開発ボードモジュール 2.4GHz ワイヤレスWiFi + Bluetooth
VKLSVAN ESP32 デュアルコア開発ボードモジュール 2.4GHz ワイヤレスWiFi + Bluetooth
Amazon
M5Stack M5StickC Plus ESP32-PICO
M5Stack M5StickC Plus ESP32-PICO
Amazon

ESP-NOWとは

ESP-NOWをもう少し詳しくみていきたいと思います。こちらにESP-NOWのドキュメントがありますので、目を通しておくと良いでしょう。

ドキュメントによるとESP-NOWは次のように説明されています。

ESP-NOWは、Espressifによって定義された一種のコネクションレス型Wi-Fi通信プロトコルです。 ESP-NOWでは、アプリケーションデータはベンダー固有のアクションフレームにカプセル化され、接続なしで1つのWi-Fiデバイスから別のWi-Fiデバイスに送信されます。 CBC-MACプロトコル(CCMP)を使用したCTRは、セキュリティのためにアクションフレームを保護するために使用されます。 ESP-NOWは、スマートライト、リモートコントロール、センサーなどで広く使用されています。

TCPなどのハンドシェイクがないため到達したかどうかの確証はありませんが、高速で省電力な通信を実現できるようです。

ドキュメントには関数がズラリと書かれていますが、単純な送受信だけならばほんのわずかな関数だけでESP-NOWを実現できます。

プログラム

ESP-NOWでLチカ
ESP-NOWでLチカ

それではESP-NOWを使ったメインプログラムの紹介です。

次のプログラムでは、送信機のM5StickC PLUSのAボタンが押されるとESP-Now通信を使ってESP32のMACアドレス宛へメッセージが投げられます。受信機のESP32でメッセージが受信されると、GPIO13につながったLEDが交互に点滅され動画のような動作を振る舞います。

受信側のプログラム(ESP32)

Serial.println(WiFi.macAddress()); でESP32のMACアドレスがシリアルモニタへ表示しますので、それをメモしておいて下さい。

esp_now_init() で初期化をし、esp_now_register_recv_cb(onReceive) でデータが受信されたときの処理を登録する流れになっています。

WiFiモードはWIFI_STAのステーションモード(子機モード)を指定します。

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

const int LED_PIN = 13;
bool ledState = false;

void toggleLed() {
    if (ledState) {
        ledState = false;
        digitalWrite(LED_PIN, LOW);
    }
    else {
        ledState = true;
        digitalWrite(LED_PIN, HIGH);
    }
}


void onReceive(const uint8_t* mac_addr, const uint8_t* data, int data_len) {
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
    Serial.println();
    Serial.printf("Last Packet Recv from: %s\n", macStr);
    Serial.printf("Last Packet Recv Data(%d): ", data_len);
    for (int i = 0; i < data_len; i++) {
        Serial.print(data[i]);
        Serial.print(" ");
        if (data[i] == 222) {
            toggleLed();
        }
    }

}


void setup() {

    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);
    Serial.println(WiFi.macAddress()); // このアドレスを送信側へ登録します

    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    if (esp_now_init() == ESP_OK) {
        Serial.println("ESP-Now Init Success");
    }
    esp_now_register_recv_cb(onReceive);
}

void loop() {
}

送信側のプログラム(M5StickC PLUS)

slaveAddressを、受信機のMACアドレスに書き換えて下さい。esp_now_peer_info_tで送信先の情報を登録しています。esp_now_register_send_cb(onSend);では送信が完了したときのイベントを登録できます。必要なければ省略可能です。

データを送信するには esp_now_send(slaveAddress, data, sizeof(data)); で送信が可能です。

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

uint8_t slaveAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // 受信機のMACアドレスに書き換えます

void onSend(const uint8_t* mac_addr, esp_now_send_status_t status) {
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);

    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setTextSize(2);
    M5.Lcd.setCursor(5, 10);
    M5.Lcd.println(macStr);
    M5.Lcd.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Failed");
}


void setup() {
    M5.begin();
    M5.Lcd.fillScreen(BLACK);

    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    if (esp_now_init() == ESP_OK) {
        Serial.println("ESPNow Init Success");
    }

    esp_now_peer_info_t peerInfo;
    memcpy(peerInfo.peer_addr, slaveAddress, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;

    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }

    esp_now_register_send_cb(onSend);
}

void loop() {
    M5.update();

    if (M5.BtnA.wasPressed()) {
        uint8_t data[2] = { 111, 222 }; // 送信データ
        esp_err_t result = esp_now_send(slaveAddress, data, sizeof(data));

        Serial.print("Send Status: ");
        switch (result)
        {
        case ESP_OK:
            Serial.println("Success");
            break;
        case ESP_ERR_ESPNOW_NOT_INIT:
            Serial.println("ESPNOW not Init.");
            break;
        case ESP_ERR_ESPNOW_ARG:
            Serial.println("Invalid Argument");
            break;
        case ESP_ERR_ESPNOW_INTERNAL:
            Serial.println("Internal Error");
            break;
        case ESP_ERR_ESPNOW_NO_MEM:
            Serial.println("ESP_ERR_ESPNOW_NO_MEM");
            break;
        case ESP_ERR_ESPNOW_NOT_FOUND:
            Serial.println("Peer not found.");
            break;

        default:
            Serial.println("Not sure what happened");
            break;
        }

    }
    delay(1);
}

まとめ

いかがだったでしょうか。うまくESP-NOWの通信ができましたでしょうか。

ボタンを押すとLEDが点灯したり消灯したりしますが、有線と変わらない反応の良さに驚きました。ESP-NOW、これから大活躍しそうです。

最初でもお伝えしましたが、ルーターの必要がない点、そしてBLEのGATTのような複雑な記述がないのがとても良いですね。いままで敷居が高く感じてたアイデアもESP-NOWを使えばサクッと実現できそうですね。

ESP32搭載ボード

VKLSVAN ESP32 デュアルコア開発ボードモジュール 2.4GHz ワイヤレスWiFi + Bluetooth
VKLSVAN ESP32 デュアルコア開発ボードモジュール 2.4GHz ワイヤレスWiFi + Bluetooth
Amazon
HiLetgo ESP32ワイヤレススティックLora + WiFi + BLE開発ボード LoRaWAN 868 / 915MHz、0.49インチOLEDディスプレイ
HiLetgo ESP32ワイヤレススティックLora + WiFi + BLE開発ボード LoRaWAN 868 / 915MHz、0.49インチOLEDディスプレイ
Amazon
ESPr Developer 32
ESPr Developer 32
Amazon
M5Stack M5StickC Plus ESP32-PICO
M5Stack M5StickC Plus ESP32-PICO
Amazon
M5Stack Core2 開発キットデュアルコア32ビット240Mhz LX6プロセッサー
M5Stack Core2 開発キットデュアルコア32ビット240Mhz LX6プロセッサー
Amazon

ESP32の書籍

ESP32&Arduino 電子工作 プログラミング入門
ESP32&Arduino 電子工作 プログラミング入門
KindleAmazon
IoT開発スタートブック ── ESP32でクラウドにつなげる電子工作をはじめよう!
IoT開発スタートブック ── ESP32でクラウドにつなげる電子工作をはじめよう!
KindleAmazon
超特急Web接続!ESPマイコン・プログラム全集[CD-ROM付き]
超特急Web接続!ESPマイコン・プログラム全集[CD-ROM付き]
Amazon
みんなのM5Stack入門
みんなのM5Stack入門
KindleAmazon

Arduinoで人気の周辺パーツ

サインスマート(SainSmart) 8チャンネル 5V リレーモジュール for Arduino DSP AVR PIC ARM
サインスマート(SainSmart) 8チャンネル 5V リレーモジュール for Arduino DSP AVR PIC ARM
Amazon
KKHMF 10個 TTP223 静電容量式 タッチ スイッチ ボタン セルフロック モジュール 「国内配送」
KKHMF 10個 TTP223 静電容量式 タッチ スイッチ ボタン セルフロック モジュール 「国内配送」
Amazon
DSD TECH 2 PCS OLED 0.91インチディスプレイ  I2C
DSD TECH 2 PCS OLED 0.91インチディスプレイ I2C
Amazon
OSOYOO(オソヨー) DIY センサーモジュール キット
OSOYOO(オソヨー) DIY センサーモジュール キット
Amazon

M5Stack製品

M5Stack 2020 ATOMマトリックスESP32 PICO開発キットIMUセンサーPython
M5Stack 2020 ATOMマトリックスESP32 PICO開発キットIMUセンサーPython
Amazon
M5Stack Core2 開発キットデュアルコア32ビット240Mhz LX6プロセッサー
M5Stack Core2 開発キットデュアルコア32ビット240Mhz LX6プロセッサー
Amazon
M5Stack StickV K210 AI Camera
M5Stack StickV K210 AI Camera
Amazon
M5Stack ATOM Echo スマートスピーカー開発キット
M5Stack ATOM Echo スマートスピーカー開発キット
Amazon
記事に関するご質問などがあれば、ぜひTwitterへお返事ください。