ESP8266 with ESP-NOW as an alternative to nRF24L01+

lm317t:
Hi Robin2!
how can i use you example for remote control?

I'm sure you can.

It's a long time since I wrote the program and I'm afraid I have forgotten all I had learned at the time so I am not able to provide any more assistance.

...R

Robin2:
EXAMPLE PROGRAMS
The following 2 pairs of examples are functionally similar to the first 2 examples in my Simple nRF24L01+ Tutorial

Simple one-way transmission from the controller to slave. I am presenting the slave code first because it is where the mac address is defined and the controller must use that address.

EspnowSlave.ino

Hey Robin, can you please tell me how I can send an array of 2 variables using this code of yours? I tried to make some changes but it doesn't work, please help me

joseben:
Hey Robin, can you please tell me how I can send an array of 2 variables using this code of yours? I tried to make some changes but it doesn't work, please help me

It's a long time since I wrote this so I may not be able to help. However until you post your program so I can see what you have tried I definitely can't.

...R

Robin2:
It's a long time since I wrote this so I may not be able to help. However until you post your program so I can see what you have tried I definitely can't.

...R

It's okay, I finally did manage to send the variables, instead of using an array, I used them as variables in the structure data.Its working just fine.

Thanks for the original code

That's nice! Congratulations.

I have tried with 2 ESP8266 Master to Slave_1 OK.
Slave_1 returns via the "sendReplay (uint8_t * macAddr) function to the Master OK.

Then I added another slave_2,
like this: Master sends to slave_1 and slave_1 sends to slave_2, OK

How could I make a message from slave_2 return to Master? Thank you

busco:
How could I make a message from slave_2 return to Master? Thank you

Sorry, as I said in Reply #22 its a long time since I was familiar with this code so I probably can't help. Hopefully somebody else may be able to.

It would be a good idea to post the programs that represent your best attempt and tell us in detail what they actually do and what you want them to do that is different. It will make it much easier to focus on the parts you need help with rather than wasting time on things that you can do.

...R

I do know that this an old topic, but maybe someone can help.

I just tested both codes on ESP07 and it works nice. However, I am a little bit confused on how to pass variable instead of that Hallo World. I tried a few things but didn't make it.

who_took_my_nick:
I tried a few things but didn't make it.

Please post the program that represents your best attempt.

...R

If I change structure to this:

struct __attribute__((packed)) DataStruct {
    int integer;
};

…and with myData.integer I can pass a number from ESP to ESP. And that is ok. I made all necessary changes on both receiver and sender sketches. In the loop, I can assign myData.integer=5; and that is what I will get on my receiver ESP.

But, how to make it send different numbers in a period of time?

Tried this snippet in a loop:

  currentTimeTrigger = millis();
  elapsedTimeTrigger = currentTimeTrigger-startTimeTrigger;
  if(elapsedTimeTrigger > cycleTimeTrigger){
    startTimeTrigger = currentTimeTrigger;
    if(elapsedTimeTrigger > 0 && elapsedTimeTrigger < 999)
      myData.integer = 1;
      
    if(elapsedTimeTrigger > 1000 && elapsedTimeTrigger < 1999)
      myData.integer = 2;
      
    if(elapsedTimeTrigger > 2000 && elapsedTimeTrigger < 2999)
      myData.integer = 3;
    }

Where:

long startTimeTrigger = 0;
unsigned long currentTimeTrigger = millis();
long elapsedTimeTrigger = currentTimeTrigger-startTime;
long cycleTimeTrigger = 5000;

If needs, I can post the whole sender INO file. It obviously doesn’t pass the variable to the sendData() function.

Please post the complete program. Snippets are no use. The problem is usually somewhere else.

...R

Ok, here is the sender INO.

#include <ESP8266WiFi.h>
extern "C" {
    #include <espnow.h>
}
uint8_t remoteMac[] = {0x36, 0x33, 0x33, 0x33, 0x33, 0x33};
#define WIFI_CHANNEL 4
struct __attribute__((packed)) DataStruct {
    int integer;
};
DataStruct myData;
unsigned long lastSentMillis;
unsigned long sendIntervalMillis = 1000;
unsigned long sentMicros;
unsigned long ackMicros;
unsigned long lastBlinkMillis;
unsigned long fastBlinkMillis = 200;
unsigned long slowBlinkMillis = 700;
unsigned long blinkIntervalMillis = slowBlinkMillis;

long startTimeTrigger = 0;
unsigned long currentTimeTrigger = millis();
long elapsedTimeTrigger = currentTimeTrigger-startTimeTrigger;
long cycleTimeTrigger = 5000;

byte ledPin = 14;
void setup() {
    Serial.begin(9600);
    WiFi.mode(WIFI_STA); // Station mode for esp-now controller
    WiFi.disconnect();
    if (esp_now_init() != 0) {
        Serial.println("*** ESP_Now init failed");
        while(true) {};
    }
    esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
    esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
    esp_now_register_send_cb(sendCallBackFunction);
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, HIGH);
}
void loop() {
  currentTimeTrigger = millis();
  elapsedTimeTrigger = currentTimeTrigger-startTimeTrigger;
  if(elapsedTimeTrigger > cycleTimeTrigger){
    startTimeTrigger = currentTimeTrigger;
    if(elapsedTimeTrigger > 0 && elapsedTimeTrigger < 1000)
      myData.integer = 1;
      Serial.println("1");
    
    if(elapsedTimeTrigger > 1000 && elapsedTimeTrigger < 2000)
      myData.integer = 2;
      Serial.println("2");
    
    if(elapsedTimeTrigger > 2000 && elapsedTimeTrigger < 3000)
      myData.integer = 5;
      Serial.println("5");
   
    }
    Serial.println(elapsedTimeTrigger);
    //myData.integer = 5;
    sendData();
    blinkLed();
}
void sendData() {
    if (millis() - lastSentMillis >= sendIntervalMillis) {
        lastSentMillis += sendIntervalMillis;
        uint8_t bs[sizeof(myData)];
        memcpy(bs, &myData, sizeof(myData));
        sentMicros = micros();
        esp_now_send(NULL, bs, sizeof(myData)); // NULL means send to all peers
    }
}
void sendCallBackFunction(uint8_t* mac, uint8_t sendStatus) {
    Serial.printf("Send status = %i", sendStatus);
    Serial.println();
    if (sendStatus == 0) {
        blinkIntervalMillis = fastBlinkMillis;
    }
    else {
        blinkIntervalMillis = slowBlinkMillis;
    }
}
void blinkLed() {
    if (millis() - lastBlinkMillis >= blinkIntervalMillis) {
        lastBlinkMillis += blinkIntervalMillis;
        digitalWrite(ledPin, ! digitalRead(ledPin));
    }
}

And here is receiver INO.

#include <ESP8266WiFi.h>
extern "C" {
    #include <espnow.h>
    #include <user_interface.h>
}
uint8_t mac[] = {0x36, 0x33, 0x33, 0x33, 0x33, 0x33};
void initVariant() {
  WiFi.mode(WIFI_AP);
  wifi_set_macaddr(SOFTAP_IF, &mac[0]);
}
#define WIFI_CHANNEL 4
struct __attribute__((packed)) DataStruct {
    int integer;
};
DataStruct myData;
void setup() {
    Serial.begin(9600);
    if (esp_now_init()!=0) {
        Serial.println("*** ESP_Now init failed");
        while(true) {};
    }
    esp_now_set_self_role(ESP_NOW_ROLE_SLAVE);
    esp_now_register_recv_cb(receiveCallBackFunction);
    pinMode(12, OUTPUT);
    digitalWrite(12,HIGH);
}
void loop() {
  if(myData.integer == 5){
    digitalWrite(12,LOW);
    }else{
      digitalWrite(12,HIGH);
      }

}
void receiveCallBackFunction(uint8_t *senderMac, uint8_t *incomingData, uint8_t len) {
    memcpy(&myData, incomingData, sizeof(myData));
    Serial.print("  integer  ");
    Serial.print(myData.integer);
    Serial.println();
}

What I get with these sketches…
When I remove this millis() part and assign myData.integer=5; sketch pass it to sendData() function and I can get it on the other ESP. When I include millis() part to send different integer after 1 second all I get on the other ESP is 0. On the first ESP Serial doesn’t show any number, just as it doesn’t match the condition.

My brain just get stuck. Any help would be nice.

My mistake.

It passes all three integers one by one in a second to Serial. But not to sendData(); function.

Wrong if condition. :frowning:

Eventually, it works.

Sender INO file. If someone needs it. It sends different values every second from one ESP to the other. The receiver is from the above post.

#include <ESP8266WiFi.h>
extern "C" {
    #include <espnow.h>
}
uint8_t remoteMac[] = {0x36, 0x33, 0x33, 0x33, 0x33, 0x33};
#define WIFI_CHANNEL 4
struct __attribute__((packed)) DataStruct {
    int integer;
};
DataStruct myData;
unsigned long lastSentMillis;
unsigned long sendIntervalMillis = 1000;
unsigned long sentMicros;
unsigned long ackMicros;
unsigned long lastBlinkMillis;
unsigned long fastBlinkMillis = 200;
unsigned long slowBlinkMillis = 700;
unsigned long blinkIntervalMillis = slowBlinkMillis;

long startTimeTrigger = 0;
unsigned long currentTimeTrigger = millis();
long elapsedTimeTrigger = currentTimeTrigger-startTimeTrigger;
long cycleTimeTrigger = 5000;

byte ledPin = 14;
void setup() {
    Serial.begin(9600);
    WiFi.mode(WIFI_STA); // Station mode for esp-now controller
    WiFi.disconnect();
    if (esp_now_init() != 0) {
        Serial.println("*** ESP_Now init failed");
        while(true) {};
    }
    esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
    esp_now_add_peer(remoteMac, ESP_NOW_ROLE_SLAVE, WIFI_CHANNEL, NULL, 0);
    esp_now_register_send_cb(sendCallBackFunction);
    pinMode(ledPin, OUTPUT);
    digitalWrite(ledPin, HIGH);
}
void loop() {
  currentTimeTrigger = millis();
  elapsedTimeTrigger = currentTimeTrigger-startTimeTrigger;
  if(elapsedTimeTrigger > cycleTimeTrigger){
    startTimeTrigger = currentTimeTrigger;
  }
    if(elapsedTimeTrigger > 0 && elapsedTimeTrigger < 1000){
      myData.integer = 1;
    }
   if(elapsedTimeTrigger > 1000 && elapsedTimeTrigger < 2000){
      myData.integer = 2;
   }
   if(elapsedTimeTrigger > 2000 && elapsedTimeTrigger < 3000){
      myData.integer = 3;
   }
   if(elapsedTimeTrigger > 3000 && elapsedTimeTrigger < 4000){
      myData.integer = 4;
   }
   if(elapsedTimeTrigger > 4000 && elapsedTimeTrigger < 5000){
      myData.integer = 5;
   }
    sendData();
    blinkLed();
}
void sendData() {
  //myData.integer = 5;
    if (millis() - lastSentMillis >= sendIntervalMillis) {
        lastSentMillis += sendIntervalMillis;
        uint8_t bs[sizeof(myData)];
        memcpy(bs, &myData, sizeof(myData));
       // sentMicros = micros();
        esp_now_send(NULL, bs, sizeof(myData)); // NULL means send to all peers
    }
}
void sendCallBackFunction(uint8_t* mac, uint8_t sendStatus) {
    Serial.printf("Send status = %i", sendStatus);
    Serial.println();
    if (sendStatus == 0) {
        blinkIntervalMillis = fastBlinkMillis;
    }
    else {
        blinkIntervalMillis = slowBlinkMillis;
    }
}
void blinkLed() {
    if (millis() - lastBlinkMillis >= blinkIntervalMillis) {
        lastBlinkMillis += blinkIntervalMillis;
        digitalWrite(ledPin, ! digitalRead(ledPin));
    }
}

@Robin2 (&or constructive others)
[I understand that you’ve kind-of dropped interest but still offered to have a look under the hood since.]

I’m trying to make a remote control using peer-to-peer one-way.
My sketch is attached.
It sits and waits for my “button-push”, ok, but once it gets one it locks into sending packets (Delivery Success, ad infinitum). It doesn’t go/get back to the top of the loop and the “button-push” do-while.

If I place a delay(2000); at the end of the loop then the sketch locks in Delivery Failed (ad infinitum).

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

uint8_t broadcastAddress[] = {0xDC, 0x4F, 0x22, 0x18, 0x4E, 0x09};

typedef struct struct_message 
{
  char phs[10];
  bool st;
} struct_message;

struct_message myData;

const byte onbdLED = D0;
const byte sendBtn = D5;

byte pbClick;

void OnDataSent(uint8_t *mac_addr, uint8_t sendStatus) 
{
  Serial.print("Last Packet Send Status: ");
  if (sendStatus == 0){
    digitalWrite (onbdLED, LOW);
    Serial.println("Delivery success");
    delay(500);
    digitalWrite (onbdLED, HIGH);
  }
  else{
    Serial.println("Delivery fail");
  }
}
 
void setup() 
{
  pinMode (onbdLED, OUTPUT);
  digitalWrite (onbdLED, HIGH);
  
  Serial.begin(115200); 
  WiFi.mode(WIFI_STA);

  if (esp_now_init() != 0) 
  {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  else
  Serial.println();
  Serial.println(" -- OK -- ");
}
 
void loop() 
{
  do
  {
    yield();
    pbClick = digitalRead(sendBtn);
  }while(pbClick == 1);

  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(OnDataSent);
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

  strcpy(myData.phs, "Red1");
  myData.st = true;
 
  esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
}

All I'm doing is trying to relate your code to my code from back in 2018 - I don't have any current familiarity with this.

The only thing that strikes me is that you have this stuff in loop() whereas I have it in setup()

  esp_now_set_self_role(ESP_NOW_ROLE_CONTROLLER);
  esp_now_register_send_cb(OnDataSent);
  esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_SLAVE, 1, NULL, 0);

I guess, as I recommend to people using nRF24L01+ modules - start with working example and modify it very gradually to add the extra bits you need.

I don't like your use of the DO WHILE to block everything - but I don't know that it would cause a problem. Or might it? How many times might loop() repeat while the button is pressed? I suggest you check for a change of button state rather than simply a LOW. DO WHILE messes with my head.

...R

I didn't/don't get why that ESP stuff was in setup(), as the example I saw in "RNT" (where that continually, by design, sends the struct/packet over and over).

With regard to my do-while, there's nothing else for it to do but poll that PB. A successful delivery results and serial.print confirmation and I added delay(500) to blink the NodeMCU's LED, which I thought would effectively debounce the PB.
It never gets back to the top of the loop (I left it going like that overnight).

Trying to make a supplementary garage door trigger -- first iteration: toggling the receiver's output pin with each good packet (refinable later, trying to prove a point).

[wait for PB --> send packet --> blink LED --> start over again].

I put those three lines [Reply #34] back into setup ( ); same result/s.

Perhaps there's something about it (Undocumented) where it's not meant to be a once through, but some basically constant data stream.

Maybe I should try rigging it up so that it's transmitting the state of the PB instead, changing the bool (myData.st).

Post Edit -- My idea of sending out packets of the PB's state gave me the result I need ("it works").
Now I need to dig up a relay.

Sorry, I don't have anything else to suggest.

Maybe you should start your own Thread in the Networking section where more people might see it.

...R