I have a project that involves two ESP8266 and a NEO-6M GPS module. I want to send the GPS data to the other microcontroller using ESP-NOW, however it fails to send the data although it displays the coordinates. I just want to figure out how can I send the data through ESP-NOW. I have tried putting the two microcontrollers near each other, however, the status still displays as fail. The sender code is
#include <TinyGPS++.h>
#include <ESP8266WiFi.h>
#include <espnow.h>
#include <SoftwareSerial.h>
SoftwareSerial ss(5, 4);
TinyGPSPlus gps;
int baud = 9600;
uint8_t receiverMAC[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
typedef struct struct_message {
float latitude;
float longitude;
float altitude;
} struct_message;
struct_message myData;
void setup() {
Serial.begin(baud);
ss.begin(baud);
WiFi.mode(WIFI_STA);
delay(100);
if (esp_now_init() != 0) {
Serial.println("ESP-NOW initialization failed!");
while (true);
}
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
if (esp_now_add_peer(receiverMAC, ESP_NOW_ROLE_SLAVE, 1, NULL, 0) != 0) {
Serial.println("Failed to add peer");
return;
}
}
void loop() {
while (ss.available() > 0) {
if (gps.encode(ss.read())) {
if (gps.location.isValid()) {
myData.latitude = gps.location.lat();
myData.longitude = gps.location.lng();
myData.altitude = gps.altitude.meters();
displayInfo();
sendData();
}
}
}
esp_now_register_send_cb(OnDataSent);
}
void OnDataSent(uint8_t * mac_addr, uint8_t sendStatus) {
Serial.print("ESP-NOW Send Status: ");
if (sendStatus == 0) {
Serial.println("Delivery success");
}
else {
Serial.println("Delivery fail");
}
}
void displayInfo() {
Serial.print("Latitude: ");
Serial.println(myData.latitude, 6);
Serial.print("Longitude: ");
Serial.println(myData.longitude, 6);
Serial.print("Altitude: ");
Serial.println(myData.altitude, 2);
}
void sendData() {
delay(100);
uint8_t result = esp_now_send(receiverMAC, (uint8_t *) &myData, sizeof(myData));
if (result != 0) {
Serial.println("Error sending data");
}
}
While the receiver code for the other microcontroller is shown below
#include <ESP8266WiFi.h>
#include <espnow.h>
typedef struct struct_message {
float latitude;
float longitude;
float altitude;
} struct_message;
struct_message myData;
void OnDataRecv(uint8_t * mac, uint8_t *incomingData, uint8_t len) {
Serial.println("Data received!");
memcpy(&myData, incomingData, sizeof(myData));
Serial.print("Latitude: ");
Serial.println(myData.latitude, 6);
Serial.print("Longitude: ");
Serial.println(myData.longitude, 6);
Serial.print("Altitude: ");
Serial.println(myData.altitude, 2);
}
void setup() {
Serial.begin(9600);
WiFi.mode(WIFI_STA);
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}
2 Answers 2
There are several things regarding ESP-Now is not setup correctly.
- For ESP-Now Receiver, it needs to be in AP mode with
WiFi.mode(WIFI_AP)
, and make sure it doesn't connect to WiFi withWiFi.disconnect()
. - For ESP-Now Transmitter, it needs to be in STA mode (this is done correctly) and it MUST NOT connect to WiFi, so add
WiFi.disconnect()
right afterWiFi.mode(WIFI_STA)
. - You don't need to register the callback repeatedly in the loop, the line
esp_now_register_send_cb(OnDataSent);
should be moved tosetup()
. 4. For the sendData(), remove theuint8_t result =
and theif
statement, the sendData status is provided in the callback function. - For the
receiveMAC[]
address in the transmitter need to either match the actual MAC address of the receiver ESP8266 or the Locally Administrated MAC Address, the advantage of using the locally administrated MAC address is that a) you don't need to write a sketch to find out the MAC address as shown in the other answer; b) when you change swap ESP8266 receiver with another new one in future, you don't need to re-flash your transmitter to change the MAC address.
The following is the example code (without the GPS code) for the ESP8266 ESP-Now transmitter and ESP-Now receiver, with the example of using a locally administrated MAC address.
ESP-Now Transmitter
#include <ESP8266WiFi.h>
#include <espnow.h>
typedef struct gps_message_s {
float latitude;
float longitude;
float altitude;
} gps_t;
// *** the following variables need to match the receiver settings ***
uint8_t receiverMAC[] = {{0x82, 0x88, 0x88, 0x88, 0x88, 0x88};
gps_t myData;
const unit8_t channel = 1;
// **************************************************************
unsigned long sendStartTime;
void OnDataSent(uint8_t * mac, uint8_t sendStatus) {
unsigned long sentEndTime = micros();
Serial.printf("< Device: %02x:%02x:%02x:%02x:%02x:%02x\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
Serial.printf("< Status: %s\n",
(sendStatus == 0 ? "Success" : "Failed"));'
Serial.printf("Round-trip in uS: %4lu, ", sentEndTime - sentStartTime);
}
void setup() {
Serial.begin(115200);
WiFi.persistent(false); // turn off wifi persistent
WiFi.mode(WIFI_STA); // ESP-Now transmitter must be in STA mode
WiFi.disconnect(); // Do not connect to WiFi
if (esp_now_init() != 0) {
Serial.println("ESP-NOW initialization failed!");
while (true);
}
esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
esp_now_add_peer(receiverMAC, ESP_NOW_ROLE_SLAVE, channel, NULL, 0);
esp_now_register_send_cb(onDataSent);
}
void loop() {
// dummy data for the myData struct, replace it with actual data
myData.latitude = 1.72;
myData.longitude = 1.03;
myData.altitude = 13.0;
Serial.printf("Sending Lat=%.2f, Long=%.2f; Alt=%.2f\n",
myData.latitude, myData.longitude, myData.altitude);
sentStartTime = micros();
esp_now_send(receiverMAC, (uint8_t *) &myData, sizeof(myData));
delay(1000); // send again in 1 second
}
ESP-Now Receiver
#include <ESP8266WiFi.h>
#include <espnow.h>
typedef struct struct_message {
float latitude;
float longitude;
float altitude;
} struct_message;
// *** following 3 settings must match transmitter's settings ***
uint8_t mac[] = {0x82, 0x88, 0x88, 0x88, 0x88, 0x88};
const uint8_t channel = 1;
struct_message myData;
// **************************************************************
void OnDataRecv(uint8_t * tmac, uint8_t *incomingData, uint8_t len) {
Serial.println("Data received!");
memcpy(&myData, incomingData, len);
Serial.printf("From: %02x:%02x:%02x:%02x:%02x:%02x, ",
tmac[0], tmac[1], tmac[2], tmac[3], tmac[4], tmac[5]);
Serial.print("Latitude: ");
Serial.println(myData.latitude, 6);
Serial.print("Longitude: ");
Serial.println(myData.longitude, 6);
Serial.print("Altitude: ");
Serial.println(myData.altitude, 2);
}
void setup() {
Serial.begin(115200);
WiFi.persistent(false); // turn off wifi persistent
WiFi.mode(WIFI_AP); // ESP-Now receiver must be in AP mode
WiFi.disconnect(); // Do not connect to WiFi
wifi_set_macaddr(SOFTAP_IF, mac); // if using Locally Administrated MAC
if (esp_now_init() != 0) {
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
}
Here are two of my blogs for my ESP-Now doorbell project and Range and Response time test
Your receiverMAC
is currently {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}. This is not a valid MAC address. Get the correct MAC address of the receiving ESP8266, by writing the following code:
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
Serial.print("ESP8266 MAC: ");
Serial.println(WiFi.macAddress());}
void loop() {}
You can get more info from this tutorial. https://randomnerdtutorials.com/get-change-esp32-esp8266-mac-address-arduino/. Please figure out the correct MAC address and update it in your code. If you want to make print PCBs for your project, here you will get some idea about the cost. https://www.allpcb.com/blog/pcb-ordering/pcb-cost-per-unit.html
WiFi.mode(WIFI_AP);
,WiFi.disconnect();
. 2) For ESP-Now Transmitter, you don't need to register the callback repeatedly in the loop, the lineesp_now_register_send_cb(OnDataSent);
should be moved to setup(). 3) for the sendData(), remove theuint8_t result =
and the if statement, the sendData status is provided in the callback function.WiFi.disconnect();
to the transmitter code to make sure it does not connected to WiFi. 2)Are you matching thereceiverMAC[]
with the actual mac address of your receiver board mac address. 3) You don't have to use the actual hardware mac address of the receiver board, you could also assigned a Locally Administered mac address to the receiver and make sure you use it on both the transmitter and the receiver as shown in my example code.