Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
Giovanni '@Cyb3rn0id' Bernardo
Published © CC BY

Arduino Nano ESP32 ESP-NOW tutorial

Arduino Nano ESP32 is just launched, why don't try something interesting by transferring data between two boards using the ESP-NOW protocol?

BeginnerProtip2 hours3,216
Arduino Nano ESP32 ESP-NOW tutorial

Things used in this project

Hardware components

Arduino Nano ESP32
×2

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Code

NanoESP32_MacAddress.ino

Arduino
Code for obtaining the board MAC Address
/*
  MAC Address example
*/

#include "WiFi.h"
 
void setup()
  {
  Serial.begin(115200);
  WiFi.mode(WIFI_MODE_STA);
  }
 
void loop()
  {
  Serial.println(WiFi.macAddress());
  delay(1000);
  }

Arduino Nano ESP32 - ESP-NOW example - Device A

Arduino
/*
  ESP-NOW example on Arduino Nano ESP32
  by Giovanni 'Cyb3rn0id' Bernardo
  https://www.linktree.com/cyb3rn0id

  Code for "Device A"

  Obtain the MAC address of Device B first
*/

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

// Device B MAC address
uint8_t deviceBAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// Structure used for sending data
struct structTX
  {
    char text[5]; // we'll send "Ciao" to Device B
    uint16_t count; // we'll send an incremental counter to Device B
  };

// Structure used for receiving data
struct structRX
  {
  char text[6]; // we'll receive "Hello" from Device B
  uint16_t number; // we'll receive a random number from Device B
  };

// I define two structures for sending and receiving data
structTX payloadToSend;
structRX payloadReceived;

// I instantiate a structure that will contain infos about the coupled device (also called 'peer' : the Device B)
// we can define additional esp_now_peer_info_t structures for adding other coupled devices
esp_now_peer_info_t deviceBInfo;

// This is a callback function that will be automatically called at the end of data sending procedure
void payloadSentCB(const uint8_t *mac_addr, esp_now_send_status_t status) 
  {
  if (status == ESP_NOW_SEND_SUCCESS)
    {
    Serial.println("Payload sent to Device B");
    }
  else
    {
    Serial.println("Error sending payload to Device B");
    }
  } // \payloadSentCB

// This is a callback function that will be automatically called when a payload is received
// Note: the first parameter could change in the future with: const esp_now_recv_info_t *recv_info
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/networking.html
// see also the example: https://github.com/espressif/esp-idf/blob/4fc2e5cb95/examples/wifi/espnow/main/espnow_example_main.c
void payloadReceivedCB(const uint8_t *mac_addr, const uint8_t *payload, int len) 
  {
  // callback will store the entire payload as a byte sequence in the '*payload' array
  // using memcpy function I'll transfer data from that RAM location to my 'payloadReceived' structure
  // callback stores also the MAC address of the device: this can be useful in case
  // we wanto to connect to more devices and then understand from which one we've received data
  memcpy(&payloadReceived, payload, sizeof(payloadReceived));
  
  // now I can manage received data
  Serial.print("I received ");
  Serial.print(len);
  Serial.println(" bytes of data");

  // content of the 'text' field (first 6 bytes of payload)
  Serial.print("Received text: ");
  // I must use a loop for printing array (text) elements
  for (uint8_t i=0; i<5; i++) Serial.print(payloadReceived.text[i]);
  Serial.println();

  // content of the 'number' field (subsequent 2 bytes of data)
  Serial.print("Received number: ");
  Serial.println(payloadReceived.number);
  } // \payloadReceivedCB

void setup()
  {
  Serial.begin(115200);
  
  // those are the default led on the Arduino Nano ESP32
  pinMode(LED_BUILTIN, OUTPUT);  // the yellow led near the USB connector
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  digitalWrite(LED_BUILTIN, LOW); // yellow led off
  digitalWrite(LED_RED, HIGH); // red led off : yes, the RGB leds will turn off by putting High
  digitalWrite(LED_GREEN, HIGH); // green led off 
  digitalWrite(LED_BLUE, HIGH); // blue led off 

  WiFi.mode(WIFI_MODE_STA);

  // I start to zero the 'count' element of payloadToSend
  // this thing cannot be done outside a function for a data structure
  payloadToSend.count=0;

  // I'll copy the device B address in the peer_addr field of the deviceBInfo structure
  // (we will repeat this for additional devices)
  memcpy(deviceBInfo.peer_addr, deviceBAddress, 6);
  deviceBInfo.channel=0; // when you put 0 here, the default SoftAP channel will be used
  deviceBInfo.encrypt=false; // no encryption will be used
    
  // ESP-NOW start
  if (esp_now_init() != ESP_OK) 
    {
    Serial.println("Error starting ESP-NOW");
    return;
    }
  
  // Add the peer device (Device B)
  // (we will repeat this for additional devices)
  if (esp_now_add_peer(&deviceBInfo) != ESP_OK)
    {
    Serial.println("Error adding the peer device");
    return;
    }
  
  // Register callback on payload received
  esp_now_register_recv_cb(payloadReceivedCB);
  
  // Register callback on payload sendt
  esp_now_register_send_cb(payloadSentCB);
  } // \setup
 
void loop()
  {
  static uint8_t blink=0;

  // Preparing data to sent to Device B
  strcpy(payloadToSend.text, "Ciao"); // set the 'text' field
  payloadToSend.count++; // set the 'count' field
  if (payloadToSend.count>255) payloadToSend.count=0; // counter rollover

  // Sending the payload
  esp_now_send(deviceBAddress, (uint8_t *)&payloadToSend, sizeof(payloadToSend));

  switch(blink)
    {
      case 0:
      digitalWrite(LED_BUILTIN, HIGH); // yellow led on
      digitalWrite(LED_RED, HIGH); // red led off
      digitalWrite(LED_GREEN, HIGH); // green led off
      digitalWrite(LED_BLUE, HIGH); // blue led off
      break;

      case 1:
      digitalWrite(LED_BUILTIN, LOW); // yellow led off
      digitalWrite(LED_RED, LOW); // red led on
      digitalWrite(LED_GREEN, HIGH); // green led off
      digitalWrite(LED_BLUE, HIGH); // blue led off
      break;
      
      case 2:
      digitalWrite(LED_BUILTIN, HIGH); // yellow led on
      digitalWrite(LED_RED, HIGH); // red led off
      digitalWrite(LED_GREEN, LOW); // green led on
      digitalWrite(LED_BLUE, HIGH); // blue led off
      break;

      case 3:
      digitalWrite(LED_BUILTIN, LOW); // yellow led off
      digitalWrite(LED_RED, HIGH); // red led off
      digitalWrite(LED_GREEN, HIGH); // green led off
      digitalWrite(LED_BLUE, LOW); // blue led on
      break;
    } // \switch(blink)

  blink++;
  if (blink>3) blink=0;

  delay(1000);
  } // \loop

Arduino Nano ESP32 - ESP-NOW example - Device B

Arduino
/*
  ESP-NOW example on Arduino Nano ESP32
  by Giovanni 'Cyb3rn0id' Bernardo
  https://www.linktree.com/cyb3rn0id

  Code for "Device B"

  Obtain the MAC address of Device A first
*/

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

// Device A MAC address
uint8_t deviceAAddress[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

// Structure used for receiving data
struct structRX
  {
    char text[5]; // we'll receive "Ciao" from Device A 
    uint16_t count; // we'll receive an incremental counter from Device A
  };

// Structure used for sending data
struct structTX
  {
  char text[6]; // we'll send "Hello" to Device A
  uint16_t number; // we'll send a random number to Device A
  };

// I define two structures for sending and receiving data
structTX payloadToSend;
structRX payloadReceived;

// I instantiate a structure that will contain infos about the coupled device (also called 'peer' : the Device A)
// we can define additional esp_now_peer_info_t structures for adding other coupled devices
esp_now_peer_info_t deviceAInfo;

// This is a callback function that will be automatically called at the end of data sending procedure
void payloadSentCB(const uint8_t *mac_addr, esp_now_send_status_t status) 
  {
  if (status == ESP_NOW_SEND_SUCCESS)
    {
    Serial.println("Payload sent to Device A");
    }
  else
    {
    Serial.println("Error sending payload to Device A");
    }
  } // \payloadSentCB

// This is a callback function that will be automatically called when a payload is received
// Note: the first parameter could change in the future with: const esp_now_recv_info_t *recv_info
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/networking.html
// see also the example: https://github.com/espressif/esp-idf/blob/4fc2e5cb95/examples/wifi/espnow/main/espnow_example_main.c
void payloadReceivedCB(const uint8_t *mac_addr, const uint8_t *payload, int len) 
  {
  // callback will store the entire payload as a byte sequence in the '*payload' array
  // using memcpy function I'll transfer data from that RAM location to my 'payloadReceived' structure
  // callback stores also the MAC address of the device: this can be useful in case
  // we wanto to connect to more devices and then understand from which one we've received data
  memcpy(&payloadReceived, payload, sizeof(payloadReceived));
  
  // now I can manage received data
  Serial.print("I received ");
  Serial.print(len);
  Serial.println(" bytes of data");

  // content of the 'text' field (first 5 bytes of payload)
  Serial.print("Received text: ");
  // I must use a loop for printing array (text) elements
  for (uint8_t i=0; i<4; i++) Serial.print(payloadReceived.text[i]);
  Serial.println();

  // content of the 'count' field (subsequent 2 bytes of data)
  Serial.print("Received count: ");
  Serial.println(payloadReceived.count);
  } // \payloadReceivedCB

void setup()
  {
  Serial.begin(115200);
  
  // those are the default led on the Arduino Nano ESP32
  pinMode(LED_BUILTIN, OUTPUT);  // the yellow led near the USB connector
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);

  digitalWrite(LED_BUILTIN, LOW); // yellow led off
  digitalWrite(LED_RED, HIGH); // red led off : yes, the RGB leds will turn off by putting High
  digitalWrite(LED_GREEN, HIGH); // green led off 
  digitalWrite(LED_BLUE, HIGH); // blue led off 

  WiFi.mode(WIFI_MODE_STA);

  // I start to zero the 'count' element of payloadToSend
  // this thing cannot be done outside a function for a data structure
  payloadToSend.number=0;

  // random number generator init using the analog read as seed
  randomSeed(analogRead(0));
  
  // I'll copy the device A address in the peer_addr field of the deviceAInfo structure
  // (we will repeat this for additional devices)
  memcpy(deviceAInfo.peer_addr, deviceAAddress, 6);
  deviceAInfo.channel=0; // when you put 0 here, the default SoftAP channel will be used
  deviceAInfo.encrypt=false; // no encryption will be used
    
  // ESP-NOW start
  if (esp_now_init() != ESP_OK) 
    {
    Serial.println("Error starting ESP-NOW");
    return;
    }
  
  // Add the peer device (Device A)
  // (we will repeat this for additional devices)
  if (esp_now_add_peer(&deviceAInfo) != ESP_OK)
    {
    Serial.println("Error adding the peer device");
    return;
    }
  
  // Register callback on payload received
  esp_now_register_recv_cb(payloadReceivedCB);
  
  // Register callback on payload sendt
  esp_now_register_send_cb(payloadSentCB);
  } // \setup
 
 
void loop()
  {
  static uint8_t blink=0;

  // Preparing data to sent to Device A
  strcpy(payloadToSend.text, "Hello"); // set the 'text' field 
  payloadToSend.number=random(65536); // set the 'number' field to a number from o to 65535

  // Sending the payload
  esp_now_send(deviceAAddress, (uint8_t *)&payloadToSend, sizeof(payloadToSend));
  
  switch(blink)
    {
      case 0:
      digitalWrite(LED_BUILTIN, HIGH); // yellow led on
      digitalWrite(LED_RED, HIGH); // red led off
      digitalWrite(LED_GREEN, HIGH); // green led off
      digitalWrite(LED_BLUE, HIGH); // blue led off
      break;

      case 1:
      digitalWrite(LED_BUILTIN, LOW); // yellow led off
      digitalWrite(LED_RED, LOW); // red led on
      digitalWrite(LED_GREEN, HIGH); // green led off
      digitalWrite(LED_BLUE, HIGH); // blue led off
      break;
      
      case 2:
      digitalWrite(LED_BUILTIN, HIGH); // yellow led on
      digitalWrite(LED_RED, HIGH); // red led off
      digitalWrite(LED_GREEN, LOW); // green led on
      digitalWrite(LED_BLUE, HIGH); // blue led off
      break;

      case 3:
      digitalWrite(LED_BUILTIN, LOW); // yellow led off
      digitalWrite(LED_RED, HIGH); // red led off
      digitalWrite(LED_GREEN, HIGH); // green led off
      digitalWrite(LED_BLUE, LOW); // blue led on
      break;
    } // \switch(blink)

  blink++;
  if (blink>3) blink=0;
  delay(1000);
  } // \loop

Credits

Giovanni '@Cyb3rn0id' Bernardo
8 projects • 46 followers
Technical Writer, Maker. Addicted to retrocomputing and making stuff with microcontrollers & 3D-printing. Available for technical reviews.
Contact

Comments

Please log in or sign up to comment.