#概要
お手軽にWifi通信ができるESP-Nowですが、通常のWifi接続して切断した場合、ESP-Now通信ができなくなる事例がありました。
原因は無線APのWifiチャンネルにあわせて値が変更されたために、ESP-Nowで使うチャンネルとずれてしまうからでした。
原因がわかるまで数日かかったのでここにまとめます。
#ESP-Nowについて
ESP32同士で使える高速でコネクションレスな通信方式
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html
#経緯
M5Stack(ESP32)を検証中ですが、
ESP-Nowで収集したデータをWEBサーバーにアップロードしたくて、Wifiに接続したのですが、接続後ESP-Nowが使えなくなりました。
https://github.com/espressif/arduino-esp32/issues/878
こちらを参考にしましたがいまいち理解がおよばず
APモードやMACアドレスをしらべたりNVSリセットしたりしましたが改善せず、Wifiチャンネルを明示的にセットしたところ安定して通信できるようになりました。
ESP-Nowのサンプルはチャンネルを初期化していないため原因にたどりつくのに時間がかかりました。
サンプルはMACアドレスの表示だけでなく、Wifiチャンネルも表示すべきだと思います。
Wifi接続したままESP-Nowを使うような同時利用は検証していませんが
反応が遅くなったりチャンネルの変更についていけなかったりが予想されるので、活用は困難かと考えます。
#結論
ESP-NowをつかうときはWifiチャンネルもあわせること。
(MACアドレスを合わせただけでは十分ではない。)
無線APに接続したときに変更されていることがあるので要チェック。
#サンプル概要
M5Stack用の例です。
送信側でAボタンを押すとデータを送信します。
受信側は、データを受信したら無線APに接続、hogehogeしたら切断して、再びESP-Nowの受信待ちに入ります。
#Master(送信側)
#include <esp_now.h>
#include <WiFi.h>
#include <M5Stack.h>
#define WIFI_CHANNEL_ESPNOW 1
const char *ssidSoftAP = "ESP32AP-WiFi";
const char *passSoftAP = "esp32apwifi";
uint8_t remoteMac[] = {0x33, 0x33, 0x33, 0x33, 0x33, 0x31};
esp_now_peer_info_t peerRx;
const esp_now_peer_info_t *peerRxNode = &peerRx;
const uint8_t maxDataFrameSize = 250;
uint8_t dataToSend[maxDataFrameSize];
byte cnt = 0;
int dataSent = 0;
long timers[3];
void setup()
{
Serial.begin(115200);
M5.begin();
M5.Power.begin();
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setRotation(1);
M5.Lcd.setCursor(0, 10);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(2);
M5.Lcd.println("ESPNow/Wifi Example Tx");
reset_wifi();
start_espnow();
M5.Lcd.print("AP MAC: "); M5.Lcd.println(WiFi.softAPmacAddress());
M5.Lcd.print("Wifi channel: "); M5.Lcd.println(WiFi.channel());
}
void reset_wifi() {
WiFi.persistent(false);
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
delay(10);
}
void start_espnow() {
WiFi.mode(WIFI_STA);
WiFi.softAP(ssidSoftAP, passSoftAP, WIFI_CHANNEL_ESPNOW);
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
Serial.print("Wifi channel: "); Serial.println(WiFi.channel());
if (esp_now_init() == ESP_OK) {
Serial.println("ESP NOW INIT!");
} else {
Serial.println("ESP NOW INIT FAILED....");
}
memcpy( &peerRx.peer_addr, &remoteMac, 6 );
peerRx.channel = WIFI_CHANNEL_ESPNOW;
peerRx.encrypt = 0;
peerRx.ifidx = ESP_IF_WIFI_AP;
if ( esp_now_add_peer(peerRxNode) == ESP_OK) {
Serial.println("Added Peer!");
}
esp_now_register_send_cb(OnDataSent);
esp_now_register_recv_cb(OnDataRecv);
}
void loop()
{
M5.update();
// ボタンを押したら送信
if ( M5.BtnA.wasPressed() ) {
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setCursor(0, 10);
for (cnt = 0; cnt < maxDataFrameSize; cnt++) {
dataToSend[cnt]++;
}
if ( esp_now_send(peerRx.peer_addr, dataToSend, maxDataFrameSize) == ESP_OK) {
timers[0] = micros();
M5.Lcd.printf("\r\nSuccess Sent Value->\t%d", dataToSend[0]);
}
}
delay(1);
}
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
M5.Lcd.print("\r\nLast Packet Send Status:\t");
M5.Lcd.print(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len)
{
if (data[0] == dataToSend[0])
{
timers[1] = micros();
timers[2] = timers[1] - timers[0];
M5.Lcd.printf("\r\nReceived\t%d Bytes val\t%d\t in %ld micros", data_len, data[0], timers[2]);
}
else
{
M5.Lcd.printf("\r\nReceived\t%d Bytes\t%d", data_len, data[0]);
}
}
#Slave(受信側)
#include <esp_now.h>
#include <WiFi.h>
#include <M5Stack.h>
#define WIFI_CHANNEL_ESPNOW 1
const char *ssidSta = "ssid";
const char *passSta = "pass";
const char *ssidAP = "ESP32AP-WiFi";
const char *passAP = "esp32apwifi";
uint8_t remoteMac[] = {0x44, 0x44, 0x44, 0x44, 0x44, 0x41};
esp_now_peer_info_t peerTx;
const esp_now_peer_info_t *peerTxNode = &peerTx;
const byte maxDataFrameSize = 250;
uint8_t dataRx[maxDataFrameSize];
bool data_recieved = false;
void setup()
{
Serial.begin(115200);
M5.begin();
M5.Power.begin();
M5.Lcd.fillScreen(TFT_BLACK);
M5.Lcd.setCursor(0, 10);
M5.Lcd.setTextColor(WHITE);
M5.Lcd.setTextSize(2);
M5.Lcd.println("ESPNow/Wifi Example Rx");
reset_wifi();
start_espnow();
M5.Lcd.print("AP MAC: "); M5.Lcd.println(WiFi.softAPmacAddress());
M5.Lcd.print("Wifi channel: "); M5.Lcd.println(WiFi.channel());
}
void reset_wifi() {
WiFi.persistent(false);
WiFi.disconnect();
WiFi.mode(WIFI_OFF);
delay(10);
}
void start_wifi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssidSta, passSta);
int maxTry = 10;
while (WiFi.status() != WL_CONNECTED && maxTry > 0 ) {
delay(1000);
Serial.print(".");
maxTry--;
}
Serial.println("WiFi connected..!");
Serial.print("IP: "); Serial.println(WiFi.localIP());
Serial.print("MAC: "); Serial.println(WiFi.macAddress());
Serial.print("Wifi channel: "); Serial.println(WiFi.channel());
}
void start_espnow() {
WiFi.mode(WIFI_AP);
WiFi.softAP(ssidAP, passAP, WIFI_CHANNEL_ESPNOW);
Serial.print("AP MAC: "); Serial.println(WiFi.softAPmacAddress());
Serial.print("Wifi channel: "); Serial.println(WiFi.channel());
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success!");
} else {
Serial.println("ESPNow Init Failed....");
}
memcpy( &peerTx.peer_addr, &remoteMac[0], 6 );
peerTx.channel = WIFI_CHANNEL_ESPNOW;
peerTx.encrypt = 0;
peerTx.ifidx = ESP_IF_WIFI_AP;
if ( esp_now_add_peer(peerTxNode) == ESP_OK) {
Serial.println("Added peerNode!");
}
esp_now_register_recv_cb(OnDataRecv);
esp_now_register_send_cb(OnDataSent);
}
void loop()
{
delay(1);
if (data_recieved) {
M5.Lcd.clear(BLACK);
M5.Lcd.setCursor(0, 0);
M5.Lcd.printf("Received val %d", dataRx[0]); M5.Lcd.println("");
Serial.printf("Received val %d", dataRx[0]);
data_recieved = false;
delay(10);
reset_wifi();
start_wifi();
M5.Lcd.print("STA MAC: "); M5.Lcd.println(WiFi.macAddress());
M5.Lcd.print("Wifi channel: "); M5.Lcd.println(WiFi.channel());
//hogehoge
start_espnow();
M5.Lcd.print("AP MAC: "); M5.Lcd.println(WiFi.softAPmacAddress());
M5.Lcd.print("Wifi channel: "); M5.Lcd.println(WiFi.channel());
}
}
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len)
{
memcpy( dataRx, data, data_len );
esp_err_t sendResult = esp_now_send(peerTx.peer_addr, dataRx, sizeof(dataRx));
data_recieved = true;
}
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}