LoginSignup
2
1

More than 1 year has passed since last update.

ESPNOWの送受信関数群とサンプルです

Posted at

 個人的にイロイロとIOTグッズを作って遊んでいるのですが、
「WiFiに依存しないで各IOTグッズ間通信出来ると良いなぁ」と思う
事がよくあります。そんな問題を解決するのがBLE通信です。
そう思っていたのですが昨年よりESPNOWの仕様を確認すると簡素で
超軽量で安上がりという仕様に気付きました。
自分のアプリに反映する苦難につきましては日記の方にウダウダ書くとして、
こちらではシンプルな送受信関数と送受信プログラムを紹介します。

#実行に必要なリソース
  ArduinoIDE開発環境
  ESP32/ESP8266

#機能
  ESPNOWを用いた双方向通信をサポートします。
  ESP32とESP8266で一応同じソースコードで使える様にしました。
  ※通信相手の数制限は20ぐらいでESPNOWのヘッダに記載の様ですが、細かいトコロは不明。

#送受信関数です

espnow_pack.h
//ESP8266=========================================================================================
#if defined(ESP8266)
#include <espnow.h>
uint8_t esp_now_temp[6];
uint8_t esp_now_channel;

// データの受信
#define ESP_NOW_RECEIVE_BUFFER 128
uint8_t esp_now_receive_mac_address[6];
char esp_now_receive_data[ESP_NOW_RECEIVE_BUFFER];
int esp_now_receive_datalength;
bool esp_now_receive;
// データの受信イベント
void on_esp_now_receive(uint8_t *mac_addr, uint8_t *data, uint8_t data_len) {
  if( esp_now_receive==true )
    return;
  memcpy( esp_now_receive_mac_address, mac_addr, 6 );
  if( data_len>ESP_NOW_RECEIVE_BUFFER ) data_len = ESP_NOW_RECEIVE_BUFFER;
  esp_now_receive_datalength = data_len;
  memcpy( esp_now_receive_data, data, data_len );
  esp_now_receive = true;
}
// データの送信イベント
uint8_t esp_now_send_status;
void on_esp_now_sent(uint8_t *mac_addr, uint8_t status) {
  esp_now_send_status = status;
}
//
uint8_t esp_now_send_data( uint8_t *mac_addr, uint8_t *data, int data_len ){
  // peerリストに無い場合は追加する
  for (int ii = 0; ii < 6; ++ii )   esp_now_temp[ii] = (uint8_t) mac_addr[ii];
  if( !esp_now_is_peer_exist(esp_now_temp) ){
    uint8_t result = esp_now_add_peer(esp_now_temp, ESP_NOW_ROLE_SLAVE, esp_now_channel, NULL, 0);
    if(result!=0 )
      return result;
  }
  // 送信(send)
  uint8_t *peer_addr = mac_addr;
  return esp_now_send(peer_addr, data, data_len);  
}

uint8_t esp_now_begin( int channel ){
  uint8_t result = esp_now_init();
  esp_now_channel = channel;
  if( result!=0 ) return result;
  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(on_esp_now_sent);
  esp_now_register_recv_cb(on_esp_now_receive);
  return result;
}

#else
//ESP32===========================================================================================
#include <esp_now.h>
esp_now_peer_info_t esp_now_temp;
uint8_t esp_now_channel;

// データの受信
#define ESP_NOW_RECEIVE_BUFFER 128
uint8_t esp_now_receive_mac_address[6];
char esp_now_receive_data[ESP_NOW_RECEIVE_BUFFER];
int esp_now_receive_datalength;
bool esp_now_receive;
// データの受信イベント
void on_esp_now_receive(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
  if( esp_now_receive==true )
    return;
  memcpy( esp_now_receive_mac_address, mac_addr, 6 );
  if( data_len>ESP_NOW_RECEIVE_BUFFER ) data_len = ESP_NOW_RECEIVE_BUFFER;
  esp_now_receive_datalength = data_len;
  memcpy( esp_now_receive_data, data, data_len );
  esp_now_receive = true;
}
// データの送信イベント
esp_now_send_status_t esp_now_send_status;
void on_esp_now_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  esp_now_send_status = ESP_NOW_SEND_SUCCESS;
}
//
esp_err_t esp_now_send_data( uint8_t *mac_addr, const uint8_t *data, size_t data_len ){
  // peerリストに無い場合は追加する
  for (int ii = 0; ii < 6; ++ii )   esp_now_temp.peer_addr[ii] = (uint8_t) mac_addr[ii];
  esp_now_temp.channel = esp_now_channel; // pick a channel
  esp_now_temp.encrypt = 0;       // no encryption  
  if( !esp_now_is_peer_exist(esp_now_temp.peer_addr) ){
    esp_err_t result = esp_now_add_peer(&esp_now_temp);    // Master not paired, attempt pair
    if(result!=ESP_OK ){
      return result;
    }
  }
  // 送信(send)
  const uint8_t *peer_addr = mac_addr;
  return esp_now_send(peer_addr, data, data_len);  
}

esp_err_t esp_now_begin( int channel ){
  esp_err_t result = esp_now_init();
  esp_now_channel = channel;
  if( result!=ESP_OK ) return result;
  esp_now_register_send_cb(on_esp_now_sent);
  esp_now_register_recv_cb(on_esp_now_receive);
  return result;
}

#endif

#サンプルです
メッセージを受信すると、その相手にメッセージを返信するサンプルです。

電源投入時にbroadcast送信(MAC=FF:FF:FF:FF:FF)で送信します。
受信した側は相手先のMACアドレスに対してメッセージを返します。(以後双方とも続く)
ESPNOWは時々通信が届かない事があるので気が付けば止まっていると思います。

sample.ino
#if defined(ESP8266)
#include <ESP8266WiFi.h>    // ESP8266
#else
#include <WiFi.h>           // ESP32
#endif

#include <espnow_pack.h>
#define ESP_NOW_CH 0
uint8_t esp_now_send_mac_address[6];

void setup(){
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  Serial.printf("\n\nSTA MAC: %s\n", WiFi.macAddress().c_str() );
  WiFi.disconnect();
  if( esp_now_begin( ESP_NOW_CH )!=0 ){
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
  // broadcast   MAC=FF:FF:FF:FF:FF:FF
  for( int i=0 ; i<6 ; i++ )
    esp_now_send_mac_address[i] = 0xff;
  esp_now_send_data( esp_now_send_mac_address, (uint8_t *)"bradcast", (strlen("bradcast")+1) );
}

String mac_string( const uint8_t *ad ){
  char macStr[18];
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", ad[0], ad[1], ad[2], ad[3], ad[4], ad[5]);
  return macStr;
}

int loopCount = 0;
void loop() {
  delay(1);
  if( esp_now_receive!=true )
    return;
  Serial.printf( "recv:[%s] %s\n", mac_string( esp_now_receive_mac_address ).c_str(), esp_now_receive_data );
  char message[20];
  sprintf( message, "client loop : %d", loopCount );
  uint8_t result = esp_now_send_data( esp_now_receive_mac_address, (uint8_t *)message, (strlen(message)+1) );
  Serial.printf( "send:[%s]%s\n", mac_string( esp_now_receive_mac_address ).c_str(), message );
  loopCount++;
  esp_now_receive = false;
}

あとがき

 どなたか岡山:倉敷近辺でオッサンでも加入可能なそんなArduino系な集まり誘ってくれませんか? (ぷ

2
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1