Reputation: 45
I am using code derived from Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
I am using ESP NOW to send readings from an ESP32 sender to an ESP32 receiver then using the ESP32 receiver to send an html message to a ESP32 web server. Per Rui's instructions I need to start WiFi with WIFI_AP_STA to allow both wifi connection methods.
The sender and receiver code is below.
If I run the code as is, i.e. the receiver setup as WIFI_AP_STA but with the WiFi.begin line commented out, I get a sender status of: Send success, and a receive status of:Receive status. SO there is no problem sending an ESP NOW message from the sender to the receiver (also works with WIFI_STA).
If I use WIFI_AP_STA and uncomment the line in the receiver "WiFi.begin(SSIS, PASSWORD)" so that I can send a message to the ESP32 web server, I get a send status of:Send fail, and a receive status of:Receive status with failed send. The send fails but the receive is still successful. Same fail if I use WIFI_AP. It seems that in WIFI_AP_STA mode with a WiFi.begin, the receiver sends an incorrect status back to the sender.
In summary, on the receiver, using wifi mode WIFI_AP_STA without a WiFi.begin, works for sending an ESP NOW message from sender to receiver, as it should.
Using wifi mode WIFI_AP_STA and WiFi.begin on the receiver, the sender fails when sending an ESP NOW message. When I implement the web code the web html message send works. However the issue can be reproduced using the simplified code below.
Using [email protected].
I've run out of ideas, is anyone able to point me at further investigation areas?
My sender code is:
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
// Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0xAA, 0x84, 0x10};
typedef struct struct_message
{
char ESP32NowText[33];
} struct_message;
struct_message ESP32NowMessage;
//
String text = "AAA000010000200003000040000500006";
esp_now_peer_info_t peerInfo;
// callback when data is sent
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");
}
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_send_cb(OnDataSent);
// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK)
{
Serial.println("Failed to add peer");
return;
}
}
void loop()
{
strncpy(ESP32NowMessage.ESP32NowText, text.c_str(), text.length());
Serial.println("Msg to send:" + String(ESP32NowMessage.ESP32NowText));
Serial.println("Snd Len:" + String(sizeof(ESP32NowMessage)));
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&ESP32NowMessage, sizeof(ESP32NowMessage));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
delay(2000);
}
My receiver code is:
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
// Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
typedef struct struct_message
{
char ESP32NowValues[33];
} struct_message;
struct_message ESP32NowMessage;
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
{
memcpy(&ESP32NowMessage, incomingData, sizeof(ESP32NowMessage));
Serial.println("Bytes received: " + String(len));
Serial.println("Values:" + String(ESP32NowMessage.ESP32NowValues));
Serial.println("---------------------------------------");
}
const char WiFiSSID[] = "SSID";
const char WiFiPassword[] = "PASSWORD";
//
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_AP_STA);
// WiFi.begin(WiFiSSID, WiFiPassword);
// Init ESP-NOW
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_recv_cb(OnDataRecv);
}
void loop()
{
}
Upvotes: 1
Views: 4176
Reputation: 11
Modifying the previous answer slightly, I have successfully used both Wi-Fi, and ESPNOW, between two ESP8266's. My transmitter ESP8266 is connected to a temperature sensor and only transmits using ESP-NOW. (No WiFi).
My ESP8266 receiver first uses WiFi to set it's clock, then it disconnects from WiFi and uses ESP-NOW to receive temperature data from my remote transmitter.
From the Espressif documentation: "Can Wi-Fi be used with ESP-NOW at the same time? Yes, but it should be noted that the channel of ESP-NOW must be the same as that of the connected AP."
Simply add to the end of void setup() on the receiver:
int chan;
if (int32_t n = WiFi.scanNetworks()) {
for (uint8_t i=0; i<n; i++) {
if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
chan = WiFi.channel(i); } } }
wifi_set_channel(chan);
My transmitter doesn't need WiFi (only ESP-NOW), so nothing had to be added.
Before I added this communication was VERY unreliable. I manually changed channels on my WiFi modem to confirm this would work.
Upvotes: 1
Reputation: 723
You need to send data to the receiver using the same channel it is using on the WiFi gateway. The channel is set on the receiver after running WiFi.begin(WiFiSSID, WiFiPassword);
, according to the WiFi gateway configuration.
You can find the channel by adding this line WiFi.printDiag(Serial);
after WiFi.begin(WiFiSSID, WiFiPassword);
in your receiver code. Then set the channel manually in the sender code with:
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
Where channel
is the integer you need to replace.
You can save the WiFiSSID
in the sender code and use it to find the channel without having to write it down in case it changes over time:
cost char *WiFiSSID = "YOUR SSID";
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;
}
In your setup()
function, include the following lines:
int32_t channel = getWiFiChannel(WiFiSSID);
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
You can use the callback function to offset the channel until ESP-NOW communications are confirmed:
uint8_t channel = 1;
void tryNextChannel() {
Serial.println("Changing channel from " + String(channel) + " to " + String(channel+1));
channel = channel % 13 + 1;
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
}
void onDataSent(const uint8_t* mac_addr, esp_now_send_status_t status) {
if (!channelFound && status != ESP_NOW_SEND_SUCCESS) {
Serial.println("Delivery Fail because channel" + String(channel) + " does not match receiver channel.");
tryNextChannel(); // If message was not delivered, it tries on another wifi channel.
}
else {
Serial.println("Delivery Successful ! Using channel : " + String(channel));
channelFound = true;
}
}
When initializing ESP-NOW, just add this line: esp_now_register_send_cb(onDataSent);
.
If you would like to see a basic example of ESP-NOW communication that works with a WiFi gateway, you can take a look at my Github repository: https://github.com/lukalafaye/ESP-NOW-WiFi-Gateway.
Upvotes: 1