0

I'm trying to set up a network like the following:

|Host| <-------> |Node x 3|

I want to have a two-way connection between a host and each node, but each node cannot communicate with other nodes. The host and nodes are all NodeMCU 1.0 ESP8266 12E with the same software on each node (has to be this way). The problem I'm dealing with at the moment is that I can send messages successfully, but my host is not receiving any messages from the nodes. Right now I'm only testing it with one node, and I'm only testing sending from the node to the host just to make sure the devices are connected properly. Here's my code for both the node and host:

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


//Macros

#define PORT 80
#define CHANNEL 1
#define ESP_OK 0

//-----Anonymous Project----//
//-----Author: Anonymous----------//
//
// Last Date Modified: 6/18/20
// 
// Description: This project is designed to have several node arduinos connected to a host arduino. Whenever an 
// event is triggered on a node arduino, the host reacts to this and activates the corresponding LEDs.
// The host arduino acts as a server while the node arduinos act as clients. Both the hosts and clients send data
// back and forth to each other to ensure arduinos are still active and are responding properly.
// All the software is the same on host and client arduinos, so whether an arduino is a host
// or client is determined by its MAC Address.
//
// Progress: At the moment, this project successfully establishes connections between the host and the nodes.
// I am currently working on figuring out why the nodes do not successfully send to the host.


//Global Variables
char hostMACAdd [18] = "XX:XX:XX:XX:XX:XX"; //change this MAC address to change the host node 
String SSID = "NETWORK NAME"; //change this SSID to change the network name
String Password = "PASSWORD"; //change this to change the password required to connect. If node, connect to SSID with password given

bool isHost; //flag that controls whether host or node code executes
bool A = true; //flag for event A
bool B = false; //flag for event B

//Server-Specific Globals
bool haveMessage;        //global for detecting readings

//Client-Specific Globals


//Function Prototypes
uint8_t * MACAddrToInt(String MAC);
void configDeviceAP(void);
void initESPNow();
void wifiConnect();

void setup() {
    Serial.begin(115200);
    Serial.println();
    delay(500);
    
    //is it a host or node?
    if(strcmp(WiFi.macAddress().c_str(),hostMACAdd)){
      //node
      isHost = false;
      Serial.println("Client powered!");
      Serial.println();

      //set device in station mode if it's a node
      WiFi.mode(WIFI_STA); // Station mode for esp-now sensor node

      //Enable ESP Now
      initESPNow();
      
      Serial.println("Initialization successful!");
      
      //attempt to connect to host
      Serial.println("Connecting to " + SSID);

      esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
      if(esp_now_add_peer(MACAddrToInt(hostMACAdd), ESP_NOW_ROLE_SLAVE, CHANNEL, NULL, 0)!=ESP_OK){
        Serial.println("Error connecting to host.");
        //TODO: make this station a host and a node
      }

      Serial.println("Connection to host successful!");
    }
    else{
      //host
      isHost = true;
      Serial.println("Host powered!");
      Serial.println();

      //set device in AP mode if it's the host
      WiFi.mode(WIFI_AP);
      
      //Enable ESP Now
      initESPNow();
      
      Serial.println("Initialization successful!");
      esp_now_set_self_role(ESP_NOW_ROLE_COMBO);
      
      int unsuccessfullyRegistered = esp_now_register_recv_cb([](uint8_t *mac, uint8_t *data, uint8_t len) {

        String deviceMac = "";
        deviceMac += String(mac[0], HEX);
        deviceMac += String(mac[1], HEX);
        deviceMac += String(mac[2], HEX);
        deviceMac += String(mac[3], HEX);
        deviceMac += String(mac[4], HEX);
        deviceMac += String(mac[5], HEX);
        
    
        Serial.println("Message received from device: "); 
        Serial.println(deviceMac);
        Serial.println(*data, DEC);
        //haveMessage = true;
      });

      if(!unsuccessfullyRegistered){
        Serial.println("Callback function registered!");
      }
      else{
        Serial.println("Callback function not registered.");
      }

      Serial.println("Waiting for clients...");
    }
}

void loop() {
  
  if(isHost){
    
  }
  else{

    String IP = WiFi.localIP().toString();
    uint8_t flagMsg;                  //message for events A and B.
    
    
    //             Inputs | Output
    //                    |
    //             A   B  |  flagMsg
    //             0   0  |  0
    //             0   1  |  1
    //             1   0  |  2
    //             1   1  |  3
    
    
    //FOR TESTING
    A = true;
    B = true;
    
    if(A){
      if(B){
        flagMsg = 3;
      }
      else{
        flagMsg = 2;  
      }
    }
    else{
      if(B){
        flagMsg = 1;  
      }
      else{
        flagMsg = 0;
      }
    }
    
    //String message = IP + " " + String(flagMsg); //maybe add pattern to this as well
    
    uint8_t * intMAC = MACAddrToInt(hostMACAdd);
    
    
    while(esp_now_send(intMAC, &flagMsg, sizeof(flagMsg))!=ESP_OK){
      Serial.println("Failed to send.");
      delay(2000);
    }
    
    Serial.println("Message Sent!");
    delay(5000);
  }
   
}









//convert MAC Address string to int
uint8_t * MACAddrToInt(String MAC){
  uint8_t hostMACAddArray [6];
  int values[6];
  
  sscanf(hostMACAdd, "%x:%x:%x:%x:%x:%x", &values[0], &values[1], &values[2], &values[3], &values[4], &values[5]);
  
  for(int i = 0; i<6; ++i){
    hostMACAddArray[i] = (uint8_t) values[i];
  }
  return hostMACAddArray;
}




//set as Access Point
void configDeviceAP(){
  bool result = WiFi.softAP(SSID.c_str(), Password.c_str(), CHANNEL, 0);
  if (!result)
  {
    Serial.printf("AP Config failed.");
  }
  else
  {
    Serial.printf("AP Config Success. Broadcasting with AP: ");
    Serial.printf("%s", SSID.c_str());
  }
}

void initESPNow(){
  WiFi.disconnect();
  if (esp_now_init() == ESP_OK) {
    Serial.println("ESPNow Init Success");
  }
  else
  {
    Serial.println("ESPNow Init Failed");
    ESP.restart();
  }
}


void wifiConnect() {
  WiFi.mode(WIFI_STA);
  Serial.printf("");
  Serial.printf("Connecting... "); //Serial.printf("%s",SSID.c_str());
  WiFi.begin(SSID, Password);
  while (WiFi.status() != WL_CONNECTED) {
     delay(250);
     Serial.print(".");
  }  
  Serial.print("\nWiFi connected."); //Serial.printf("%s",WiFi.localIP().c_str());
}

The code isn't near finished yet, but theoretically the nodes should send an integer to the host and the host should print it. The console output for the node shows that the message is being sent, but the last thing that shows up on the host console output is "Waiting for clients", which would indicate that the host isn't receiving anything. I'm pretty new to ESP_NOW but I've been reading a lot of documentation on it recently and my code shouldn't be breaking any rules, but here we are.

Some potential problems that I suspect:

  1. I had to define ESP_OK in my file for whatever reason. In most examples I've looked at, this macro hasn't had to be defined, and it's possible the value isn't actually 0.
  2. Maybe I need to set up the host as a WIFI_AP_STA instead of WIFI_AP. Not sure why this would cause problems, but I'm just speculating at this point.
  • imho, there is some poorly document connections between wifi settings and espnow. I found a way to avoid much of the config each boot by using "cached" wifi settings. That is, you flash each chip w/ a sketch that connects to your wifi, run it, then re-flash with your espnow sketch. The only wifi config in setup is then WiFi.mode(WIFI_STA);WiFi.disconnect();. Then the only espnow stuff in setup becomes esp_now_set_self_role,esp_now_add_peer,esp_now_register_send_cb, and esp_now_send. – dandavis Jun 25 at 16:40
  • @dandavis What do you think the issue I'm dealing with is? I don't have SendCB functions registered, but should that really affect anything? – SD'Anc Jun 26 at 1:47
  • The ESP-Now slave must be in AP mode because you can then set the MAC address. Your code did set the AP mode with ` WiFi.mode(WIFI_AP);` but it doesn't explicitly set the AP Mac address, so all the sensor nodes are sending data to a pre-defined remote hostMACAdd, but your AP is using the default physical MAC address, you need to set it to match the sensor node configuration with wifi_set_macaddr(SOFTAP_IF, &hostMacAdd[0]);. See my working example. – hcheung Jun 27 at 3:53
  • @hcheung Thanks for the help! Now I'm curious why you have to set the MAC address in the pattern you detailed. Shouldn't I be able to set the MAC address to whatever I want? – SD'Anc Jul 3 at 3:16
  • Connect with MAC is faster than connect with SSID, as SSID need to establish a connection which take up to 5 seconds or sometime even more. Another benefits of setting your own local-administrated MAC address is that if you for any reason to replace your board in future, you don't need to change the sketch to put in new MAC address of your board. If you looks at my example, you will see on the comment of the sketch on how to create a valid local administrated MAC address. – hcheung Jul 3 at 5:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.