Error in channel for ESP32 ESP-NOW with Wifi

Testing out ESP-NOW with Wifi and I'm having errors with the channel. Both receiver and sender are in channel 1 but I kept seeing an error from the sender saying "E (383127) ESPNOW: Peer channel is not equal to the home channel, send fail!"

Is there anything missing from setting channel to make it work and send data?

Sender code:

/* Sender */
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Define the receiver's MAC address (replace with the correct address)
uint8_t receiverAddress[] = {0xE8, 0x6B, 0xEA, 0xCF, 0xE3, 0xF0};  // Replace with the correct MAC address

// Create a message structure
struct_message myData;

// Channel for ESP-NOW
const int CHANNEL = 1;

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password 


void setup() {
    Serial.begin(115200);  // Initialize serial communication

    // Initialize Wi-Fi in STA mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // Set the Wi-Fi channel
    esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
    Serial.print("Wi-Fi Channel set to: ");
    Serial.println(CHANNEL);

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the send callback function
    esp_now_register_send_cb(OnDataSent);

    // Initialize peer information
    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));  // Clear the peerInfo structure
    memcpy(peerInfo.peer_addr, receiverAddress, 6);  // Copy the receiver's MAC address
    peerInfo.channel = CHANNEL;
    peerInfo.encrypt = false;

    // Add peer to the ESP-NOW peer list
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("Peer added successfully");
}

void loop() {
    // Prepare data to send
    strcpy(myData.a, "Hello from sender");
    myData.b = random(1, 20);
    myData.c = 1.2;
    myData.d = false;

    // Send data via ESP-NOW
    esp_err_t result = esp_now_send(receiverAddress, (uint8_t *)&myData, sizeof(myData));

    if (result == ESP_OK) {
        Serial.println("Sent with success");
    } else {
        Serial.println("Error sending the data");
    }

    delay(2000);
}

// Callback function when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
    Serial.print("\r\nLast Packet Send Status: ");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

Receiver code:

/* Receiver */
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel
#include <WebServer.h>  // Include WebServer library

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Create a message structure to hold incoming data
struct_message incomingData;

// Channel for ESP-NOW
const int CHANNEL = 1;

// Create a web server object on port 80
WebServer server(80);

// Variable to hold received data as a string for web display
String receivedData = "";

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password 

void setup() {
    Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200

    // Initialize Wi-Fi in STA (station) mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);  // Connect to the Wi-Fi network

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // Set the Wi-Fi channel to match the ESP-NOW communication channel
    esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);  // Set the Wi-Fi channel
    Serial.print("Wi-Fi Channel set to: ");
    Serial.println(CHANNEL);

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the receive callback function
    esp_now_register_recv_cb(OnDataRecv);

    // Start the web server
    server.on("/", handleRoot);  // Define the root URL handler
    server.begin();  // Start the web server
    Serial.println("Web server started");
}

void loop() {
    server.handleClient();  // Handle incoming web requests
}

// Callback function when data is received via ESP-NOW
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
    // Cast the incoming data to the structure type
    struct_message* data = (struct_message*)incomingData;

    Serial.print("Bytes received: ");
    Serial.println(len);
    Serial.print("String: ");
    Serial.println(data->a);  // Correctly access struct members
    Serial.print("Int: ");
    Serial.println(data->b);
    Serial.print("Float: ");
    Serial.println(data->c);
    Serial.print("Bool: ");
    Serial.println(data->d);

    // Store received data as a string for web display
    receivedData = "String: " + String(data->a) + "\n" +
                   "Int: " + String(data->b) + "\n" +
                   "Float: " + String(data->c) + "\n" +
                   "Bool: " + String(data->d);

    // Print sender's MAC address
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    Serial.print("From MAC address: ");
    Serial.println(macStr);
}

// Handle root URL
void handleRoot() {
    server.send(200, "text/plain", receivedData);  // Send the received data as a plain text response
}

There seems to be some confusion in your code as to what the CHANNEL variable is used for

// Channel for ESP-NOW

const int CHANNEL = 1;

and

    // Set the Wi-Fi channel
    esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
    Serial.print("Wi-Fi Channel set to: ");
    Serial.println(CHANNEL);

and

   peerInfo.channel = CHANNEL;

Let me try to correct this. This is what I have come up with:

Sender code:

/* Sender */

#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Define the receiver's MAC address (replace with the correct address)
uint8_t receiverAddress[] = {0xE8, 0x6B, 0xEA, 0xCF, 0xE3, 0xF0};  // Replace with the correct MAC address

// Create a message structure
struct_message myData;

// Channel for ESP-NOW
// const int CHANNEL = 1;

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password 

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
      for (uint8_t i=0; i<n; i++) {
          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
              return WiFi.channel(i);
          }
      }
  }
  return 0;
}

void setup() {
    Serial.begin(115200);  // Initialize serial communication

    // Initialize Wi-Fi in STA mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // // Set the Wi-Fi channel
    // esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
    // Serial.print("Wi-Fi Channel set to: ");
    // Serial.println(CHANNEL);

   // Set the Wi-Fi channel
    int32_t channel = getWiFiChannel(ssid);

    WiFi.printDiag(Serial); // Uncomment to verify channel number before
    esp_wifi_set_promiscuous(true);
    esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
    esp_wifi_set_promiscuous(false);
    WiFi.printDiag(Serial); // Uncomment to verify channel change after

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the send callback function
    esp_now_register_send_cb(OnDataSent);

    // Initialize peer information
    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));  // Clear the peerInfo structure
    memcpy(peerInfo.peer_addr, receiverAddress, 6);  // Copy the receiver's MAC address
    // peerInfo.channel = CHANNEL;
    peerInfo.encrypt = false;

    // Add peer to the ESP-NOW peer list
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("Peer added successfully");
}

void loop() {
    // Prepare data to send
    strcpy(myData.a, "Hello from sender");
    myData.b = random(1, 20);
    myData.c = 1.2;
    myData.d = false;

    // Send data via ESP-NOW
    esp_err_t result = esp_now_send(receiverAddress, (uint8_t *)&myData, sizeof(myData));

    if (result == ESP_OK) {
        Serial.println("Sent with success");
    } else {
        Serial.println("Error sending the data");
    }

    delay(2000);
}

// Callback function when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
    Serial.print("\r\nLast Packet Send Status: ");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

Receiver code:

/* Receiver */
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel
#include <WebServer.h>  // Include WebServer library

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Create a message structure to hold incoming data
struct_message incomingData;

// Channel for ESP-NOW
const int CHANNEL = 6;

// Create a web server object on port 80
WebServer server(80);

// Variable to hold received data as a string for web display
String receivedData = "";

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password 

void setup() {
    Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200

    // Initialize Wi-Fi in STA (station) mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);  // Connect to the Wi-Fi network

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // Set the Wi-Fi channel to match the ESP-NOW communication channel
    esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);  // Set the Wi-Fi channel
    Serial.print("Wi-Fi Channel set to: ");
    Serial.println(CHANNEL);

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the receive callback function
    esp_now_register_recv_cb(OnDataRecv);

    // Start the web server
    server.on("/", handleRoot);  // Define the root URL handler
    server.begin();  // Start the web server
    Serial.println("Web server started");
}

void loop() {
    server.handleClient();  // Handle incoming web requests
}

// Callback function when data is received via ESP-NOW
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
    // Cast the incoming data to the structure type
    struct_message* data = (struct_message*)incomingData;

    Serial.print("Bytes received: ");
    Serial.println(len);
    Serial.print("String: ");
    Serial.println(data->a);  // Correctly access struct members
    Serial.print("Int: ");
    Serial.println(data->b);
    Serial.print("Float: ");
    Serial.println(data->c);
    Serial.print("Bool: ");
    Serial.println(data->d);

    // Store received data as a string for web display
    receivedData = "String: " + String(data->a) + "\n" +
                   "Int: " + String(data->b) + "\n" +
                   "Float: " + String(data->c) + "\n" +
                   "Bool: " + String(data->d);

    // Print sender's MAC address
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    Serial.print("From MAC address: ");
    Serial.println(macStr);
}

// Handle root URL
void handleRoot() {
    server.send(200, "text/plain", receivedData);  // Send the received data as a plain text response
}

Is there a way that I can automatically set my channel based on the channel my receiver is in? and do I have to manually set my channel in receiver?

I have uploaded your code and ESP-NOW seems to be working

I don't know much about ESP-NOW so cannot answer your questions but

sounds like a chicken/egg situation

The docs imply that you cannot use esp_wifi_set_channel with a normal WiFi connection to an AP. You should check the return value. If the call fails, the code would only work if your AP happens to be on the channel you chose.

Seems like one reason these examples connect to a normal AP in the first place is to get everyone on the same channel. If you want to hard-code a channel, just pick one. You could scan the channels where you are to find one that is not used.

Another approach is to have the sender send pings every few seconds, and then have the receiver channel-hop to find it. And again, you can't have an active WiFi connection to an AP when you're doing that. Then have the receiver send a response message, and the sender can go back to regular operation without the active pings.

I've check with serial and it is working for the ESP-NOW part. How can I check if it's working on the Wifi part?

Running the webserver would be a good test

You might like to read this ESP32: ESP-NOW and Wi-Fi Web Server Dashboard (Arduino) | Random Nerd Tutorials

Correct me from what I understood so far, so it means I have to use WIFI_AP_STA instead of WIFI_STA? and then if that's the case I don't need to set the channel to 6 (which I found based on the sender code)

and if I don't set the channel, how would my sender connect to the correct channel as same as my receiver?

No, neither has to be an AP. If both sender and receiver do WiFi.begin as a STA to an AP, then they will, after connecting, both be on the same channel. Let's say that is channel 6 with your AP. Then you set/leave the peerInfo.channel as zero, which means "the current channel". And you just need the target MAC address.

However, in my limited testing, if the receiver is an active STA, it only receives 15%-25% of the messages sent to it via ESP-Now. The esp_now_send returns ESP_OK (the message "goes out"), but then the callback gets ESP_NOW_SEND_FAIL instead of _SUCCESS, the majority of the time. If these are periodic sensor pings, that might be good enough. If you're having better luck than I did, that's great.

If not, you can do a WiFi.disconnect on the receiver so that ESP-Now works reliably, but then it can no longer act as a web server, for example.

Note the reverse: an active STA can send messages to a disconnected STA reliably.

I opened the IP address from the receiver in the browser and I can read it but I have to refresh to see the changes.

I did a bit of change in the code mainly in making float increment and receiver to WIFI_AP_STA though not sure if leaving it at WIFI_STA would work the same.

Sender code:

/* Sender */

#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c = 0;
    bool d;
} struct_message;

// Define the receiver's MAC address (replace with the correct address)
uint8_t receiverAddress[] = {0xE8, 0x6B, 0xEA, 0xCF, 0xE3, 0xF0};  // Replace with the correct MAC address

// Create a message structure
struct_message myData;

// Channel for ESP-NOW
// const int CHANNEL = 1;

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
      for (uint8_t i=0; i<n; i++) {
          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
              return WiFi.channel(i);
          }
      }
  }
  return 0;
}

void setup() {
    Serial.begin(115200);  // Initialize serial communication

    // Initialize Wi-Fi in STA mode
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // // Set the Wi-Fi channel
    // esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
    // Serial.print("Wi-Fi Channel set to: ");
    // Serial.println(CHANNEL);

   // Set the Wi-Fi channel
    int32_t channel = getWiFiChannel(ssid);

    WiFi.printDiag(Serial); // Uncomment to verify channel number before
    esp_wifi_set_promiscuous(true);
    esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
    esp_wifi_set_promiscuous(false);
    WiFi.printDiag(Serial); // Uncomment to verify channel change after

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the send callback function
    esp_now_register_send_cb(OnDataSent);

    // Initialize peer information
    esp_now_peer_info_t peerInfo;
    memset(&peerInfo, 0, sizeof(peerInfo));  // Clear the peerInfo structure
    memcpy(peerInfo.peer_addr, receiverAddress, 6);  // Copy the receiver's MAC address
    // peerInfo.channel = CHANNEL;
    peerInfo.encrypt = false;

    // Add peer to the ESP-NOW peer list
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }
    Serial.println("Peer added successfully");
}

void loop() {
    // Prepare data to send
    strcpy(myData.a, "Hello from sender");
    myData.b = random(1, 20);
    myData.c += 1;
    myData.d = false;

    // Send data via ESP-NOW
    esp_err_t result = esp_now_send(receiverAddress, (uint8_t *)&myData, sizeof(myData));

    if (result == ESP_OK) {
        Serial.println("Sent with success");
    } else {
        Serial.println("Error sending the data");
    }

    delay(2000);
}

// Callback function when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
    Serial.print("\r\nLast Packet Send Status: ");
    Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

Receiver code:

/* Receiver */

#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>  // Include this library for esp_wifi_set_channel
#include <WebServer.h>  // Include WebServer library

// Define the structure for the message
typedef struct struct_message {
    char a[32];
    int b;
    float c;
    bool d;
} struct_message;

// Create a message structure to hold incoming data
struct_message incomingData;

// Channel for ESP-NOW
const int CHANNEL = 6;

// Create a web server object on port 80
WebServer server(80);

// Variable to hold received data as a string for web display
String receivedData = "";

// Wi-Fi credentials
const char* ssid = "HOMEWIFI"; //This is a dummy ssid
const char* password = "password"; //This is a dummy password 

void setup() {
    Serial.begin(115200);  // Initialize serial communication at a baud rate of 115200

    // Initialize Wi-Fi in STA (station) mode
    WiFi.mode(WIFI_AP_STA);
    WiFi.begin(ssid, password);  // Connect to the Wi-Fi network

    // Check if Wi-Fi is connected
    while (WiFi.status() != WL_CONNECTED) {
        delay(1000);
        Serial.println("Connecting to WiFi...");
    }
    Serial.println("Connected to WiFi");
    Serial.println(WiFi.localIP());  // Print the IP address assigned to the ESP32

    // Set the Wi-Fi channel to match the ESP-NOW communication channel
    esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);  // Set the Wi-Fi channel
    Serial.print("Wi-Fi Channel set to: ");
    Serial.println(CHANNEL);

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("Error initializing ESP-NOW");
        return;
    }

    // Register the receive callback function
    esp_now_register_recv_cb(OnDataRecv);

    // Start the web server
    server.on("/", handleRoot);  // Define the root URL handler
    server.begin();  // Start the web server
    Serial.println("Web server started");
}

void loop() {
    server.handleClient();  // Handle incoming web requests
}

// Callback function when data is received via ESP-NOW
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len) {
    // Cast the incoming data to the structure type
    struct_message* data = (struct_message*)incomingData;

    Serial.print("Bytes received: ");
    Serial.println(len);
    Serial.print("String: ");
    Serial.println(data->a);  // Correctly access struct members
    Serial.print("Int: ");
    Serial.println(data->b);
    Serial.print("Float: ");
    Serial.println(data->c);
    Serial.print("Bool: ");
    Serial.println(data->d);

    // Store received data as a string for web display
    receivedData = "String: " + String(data->a) + "\n" +
                   "Int: " + String(data->b) + "\n" +
                   "Float: " + String(data->c) + "\n" +
                   "Bool: " + String(data->d);

    // Print sender's MAC address
    char macStr[18];
    snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    Serial.print("From MAC address: ");
    Serial.println(macStr);
}

// Handle root URL
void handleRoot() {
    server.send(200, "text/plain", receivedData);  // Send the received data as a plain text response
}

Also went ahead and built a simple app in MIT app inventor to validate if the Wifi connection works.


Though it seems like you can't run the app while the screen sleeps or like in the background without some extensions

How would I go about implementing that in my current code?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.