0

I'm using the Arduino IDE to program ESP8266 to communicate with each other using ESP-NOW.

If I call esp_now_send with the broadcast MAC address (FF:FF:FF:FF:FF:FF), the message is sent and the slave receives it clearly.

If I call esp_now_send with a specific slave MAC address (i.e. unicast) it fails every time with a sendStatus of 1.

What am I doing wrong?

Complete example code:

#define IS_CONTROLLER
#define UART_BAUD 9600

#include <ESP8266WiFi.h>
#include <espnow.h>

uint8_t broadcast_mac[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t slave_mac[]     = {0xBC, 0xFF, 0x4D, 0x18, 0xE4, 0xD8};

#ifdef IS_CONTROLLER
    char broadcast_payload[]    = "broadcast message";
    char payload[]              = "unicast message";
    void onDataSent(uint8_t *mac, uint8_t sendStatus) {
        if (sendStatus == 0)
            Serial.println("SUCCESS");
        else {
            Serial.print("FAILED (status ");
            Serial.print(sendStatus);
            Serial.println(")");
        }
        Serial.println();
    }
#else
    void onDataReceived(uint8_t *mac, uint8_t *incomingData, uint8_t len) {
        Serial.print("MESSAGE RECEIVED: ");
        Serial.println((char*)incomingData);
        Serial.println();
    }
#endif

void send_message(uint8_t *mac, char *message) {
    esp_now_send(mac, (uint8_t*)message, strlen(message)+1);
}

void setup() {
    Serial.begin(UART_BAUD);
    WiFi.mode(WIFI_AP);
    WiFi.disconnect();
    if (esp_now_init() != 0) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
#ifdef IS_CONTROLLER
    esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
    esp_now_register_send_cb(onDataSent);
    esp_now_add_peer(slave_mac, ESP_NOW_ROLE_SLAVE, 0, nullptr, 0);
#else  
    esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
    esp_now_register_recv_cb(onDataReceived);
#endif
}

bool broadcasting = false;
void loop() {
    #ifdef IS_CONTROLLER
        Serial.println("CONTROLLER");
    #else
        Serial.println("SLAVE");
    #endif
    Serial.print("MAC ADDRESS: ");
    Serial.println(WiFi.macAddress());
    #ifdef IS_CONTROLLER
        Serial.print(broadcasting ? "BROADCASTING MESSAGE ... " : "SENDING MESSAGE ... ");
        send_message(broadcasting ? broadcast_mac : slave_mac, broadcasting ? broadcast_payload : payload);
        broadcasting = !broadcasting;
    #endif
    delay(2000);
}

(Comment out IS_CONTROLLER when flashing the slave device.)

EDIT: If I change the Slave to use WIFI_STA mode, it works properly. But if the Slave uses WIFI_AP, unicast always fails – while broadcast still works. What gives?

7
  • For ESP-NOW, Transmitter(Controller) should be in WIFI_STA mode, and Receiver(Slave) should be in WIFI_AP mode. Commented Oct 3 at 1:25
  • As I said, if the slave is in WIFI_AP mode, it literally doesn't receive unicast messages. Like, at all. Whereas if it's in WIFI_STA (or if a multicast message is sent), it receives fine. Try it yourself with the code I provided. What I want to know is: Why? Commented Oct 3 at 12:22
  • @hcheung Thank you, that will save a little memory in my code. Commented Oct 3 at 12:23
  • 1
    Another possibility why it does not work could be that the slave address might not match the slave mac address {0xBC, 0xFF, 0x4D, 0x18, 0xE4, 0xD8}. What you can try is to define the slave address at the Slave sketch and call wifi_set_macaddr(SOFTAP_IF, slave_mac); in the setup(). Commented Oct 3 at 14:44
  • You're correct: The AP MAC is different to the STA MAC. This explains why the Slave in AP mode can't receive. But I've tried setting a new MAC using wifi_set_macaddr (as shown in your linked code) and it just doesn't take. WiFi.softAPmacAddress() always returns the same result, even after I try to change it. Commented Oct 3 at 17:16

1 Answer 1

0

The MAC address used in WIFI_AP mode is generally not the same as the MAC address used in WIFI_STA mode. Which I guess makes sense, seeing as you can use both at the same time.

Use WiFi.softAPmacAddress() to query the AP MAC address.

(Thanks to hcheung for a hint that led to this discovery.)

Now in theory, one can call wifi_set_macaddr(SOFTAP_IF, ...) to choose a new MAC address for the ESP8266 to use in AP mode, but in practice this can be problematic:

  • The user-defined MAC address must meet the requirements for a Locally Administrated Mac Address and therefore must start with X2, X6, XA or XE.

  • Due to the above restriction, it is not allowed to set the SoftAP MAC address to be equal to the STA MAC address. (I mean, it may be possible, but it would violate the standard.)

  • The new MAC address doesn't get applied immediately: After wifi_set_macaddr you must call WiFi.softAP(...) or esp_now_init() to actually commit the change. esp_now_init can't be called more than once, so this effectively means the MAC address can't be changed after initialisation without hard-resetting the ESP8266.

3
  • Re “It seems that SoftAP MAC addresses must have a divisible-by-two first octet”: the last bit of the first octet is the unicast/multicast bit. An odd first octet means a multicast address. Commented Oct 3 at 20:25
  • to choose an arbitrary MAC address, It is not an arbitrary MAC address, whatever MAC address you used must meet the requirements for Locally Administrated Mac Address, that is, X2-XX-XX-XX-XX-XX, X6-XX-XX-XX-XX-XX, XA-XX-XX-XX-XX-XX, or XE-XX-XX-XX-XX-XX as the unicast mac address. Commented Oct 4 at 0:08
  • Thank you. I will update my answer. Commented Oct 4 at 11:43

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.