Problèmes communications ESP-NOW avec 3 ESP8266

Bonjour,
Grace au programme joint, je fait communiquer 3 x D1 mini(esp8266), qui pour l'instant transmettent leur numéro respectif . Au setup(), elle entrent toutes dans une boucle infinie : pour en sortir ; soit appuie sur un bouton (Pin D2) soit activé par réception message qui change état de la pin D3, ensuite les cartes activés par pin D3 envoie un message pour fournir leur numéro. Chaque carte enregistre dans un tableau le numéro des cartes dont elle a eu réception.
Le problème est : instabilité des réceptions .
Il arrive que j'ai les bon tableau : chaque carte a 3 présent avec leur numéro
puis a l'essai suivant, une carte n'est pas reçu par les deux autres (ceci quelque soit la carte employé pour appuyer sur le bouton)
Nb ; j'ai volontairement omis la fonction onDataSend() car elle est toujours a "success" avec l'utilisation de l'adresse MAC universelle 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
La documentation vente la stabilité, l'efficacité du protocole esp_now, mais j'avoue que je n'y arrive pas, outre que les exemples internet donne des exemples ou informations avec des bibliothèques qui ont peut être beaucoup évoluées, et aussi très différentes entre esp8266 et esp32
Quelqu'un a t il déjà été confronté a ce problème, et existe t il une solution ?

/**
 * @file main.cpp
 * 
 * @brief Programme de test de l'ESP_NOW sur ESP8266
 * avec des modules ESP8266 D1 mini en trois exemplaires.(le nombre de carte peut etre modifié dans le tableau tabJoueur[]) limite 20 cartes
 * Il n'y a pas de "master", pas de "slave", pas de "controller"
 * chaque carte est autonome et peut envoyer et recevoir des données  (mode combo)
 * Au démarrage du set up, chaque carte est bloqué par une boucle infinie : pour
 * en sortir, on met PIN_BOUTON à la masse  sur l'une des cartes, ce qui déclenche l' envoie d'un message de type Message
 * sur les autre cartes, qui reçoivent le message et se débloquent par changement d'état de la pin D3 (PIN_PRESENCE),
 * ce qui déclenche pour ces cartes l'envoie d'un message de type Message.
 * Le message contient uniquement le numéro de la carte qui a envoyé le message.
 * Au final, chaque carte a le numéro de toutes les cartes qui sont présentes.
 * a l'issue de la boucle d'attente, on a le tableau tabJoueur[] qui contient le numéro de toutes les cartes présentes.
 * 
 */


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

// Universal MAC Address
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

// #define NUMERO_CARTE 1
// #define NUMERO_CARTE 2 
#define NUMERO_CARTE 3

#define PIN_BOUTON D2   // le bouton joueur est sur la pin D2 de la D1 mini
#define PIN_PRESENCE D3 // Pin D3 de la D1 mini : rien n'est branché dessus
#define LED_BUILDIN D4  // Pin D4 de la D1 mini : led de presence

#define PROGRAMME_NAME "Pong"
#define VER "1.0"     // version du programme
#define VERSION "1.0" // version du programme
//********************************************************* variables ***********************************************************************
typedef struct
{
  uint8_t _numeroCarte = 0;
} Message;
Message OutgoingDatas;                       // structure pour envoyer les données
Message IncomingDatas;                       // structure pour recevoir les données
uint8_t tabJoueur[] = {NUMERO_CARTE, 0, 0,0}; // tableau pour les joueurs
uint8_t nbJoueur = 1;                        // nombre de joueurs
bool InDatas = false;                        // si je recois des donnees ou pas
bool isBtnPressed = false;                   // variable pour savoir si le bouton est appuyé ou pas
unsigned long timer = 0;
unsigned long delayTime = 3000;

bool new_data = 0; // Flag to send data only once
//********************************************************* Declarations fonctions ***********************************************************************
void init_programme(void);
void OnDataSend(uint8_t *mac_addr, uint8_t sendStatus);
void OnDataRecv(uint8_t *mac_addr, uint8_t *incomingData, uint8_t len);
void allumeLedBuiltIn(bool action); // allume ou eteint la led de presence
void dumpTabJoueur();
void halte(void);
bool attenteMode(void);
//********************************************************* SETUP() ***********************************************************************
void setup()
{
  init_programme();
  isBtnPressed = attenteMode(); // on lance le mode attente
  if (isBtnPressed == true)     // si le bouton est appuyé, on copntinue
  {
    Serial.printf("Bouton presse par : %d\n", NUMERO_CARTE);
  }
  else
  {
    Serial.println("J'ai ete actionne par une autre carte.");
    if (InDatas == true) // si je recois des donnees, je les traite
    {
      Serial.println("Je recois des donnees.");
      digitalWrite(PIN_PRESENCE, HIGH); // pour arreter attentmode sur les autre cartes
    }
  }
  allumeLedBuiltIn(false); // eteint la led de presence
  OutgoingDatas._numeroCarte = NUMERO_CARTE;
  esp_now_send(broadcastAddress, (uint8_t *)&OutgoingDatas, sizeof(OutgoingDatas));

  timer = millis();                    // on initialise le timer pour le delay
  while (millis() - timer < delayTime) // on attend quelques secondes pour les reponses ,avant de lancer le jeu
  {
    yield(); // on laisse le temps à l'ESP de faire son boulot
  }
  dumpTabJoueur(); // on affiche les valeurs de la structure
  halte();         // on arrete le programme ici pour ne pas faire de conneries
}
//********************************************************* LOOP() ***********************************************************************
void loop()
{
  // put your main code here, to run repeatedly:
}
//********************************************************* Definitions fonctions ***********************************************************************
void allumeLedBuiltIn(bool action)
{
  if (action == false)
  {
    digitalWrite(LED_BUILTIN, HIGH); // eteint  la led de presence
  }
  else
  {
    digitalWrite(LED_BUILTIN, LOW); // allume la led de presence
  }
} // allume ou eteint la led de presence

void OnDataSend(uint8_t *mac_addr, uint8_t sendStatus)
{
  Serial.print("\n\tDans OnDataSend()  ");
  Serial.println((sendStatus == 0) ? "\t -> Delivery success" : "\t -> Delivery Fail");
}

void OnDataRecv(uint8_t *mac_addr, uint8_t *DataEntrante, uint8_t len)
{
  memcpy(&IncomingDatas, DataEntrante, sizeof(IncomingDatas));
   Serial.printf("\n\tDans OnDataRecv() : Bytes received : %u de carte %d\n", len,IncomingDatas._numeroCarte);
 digitalWrite(PIN_PRESENCE, HIGH); // pour arreter attentMode
  if (IncomingDatas._numeroCarte != NUMERO_CARTE)
  {
    tabJoueur[nbJoueur++] = IncomingDatas._numeroCarte;
  }
}

bool attenteMode(void)
{
  bool fin = false;
  bool ret = false;
  while (fin == false)
  {
    if (digitalRead(PIN_BOUTON) == LOW) //  si le bouton est appuyé
    {
      fin = true;
      ret = true;
      break;
    }
    if (digitalRead(PIN_PRESENCE) == HIGH) // fin du mode attenteMode par reception message
    {
      fin = true;
      ret = false;
      break;
    }
    delay(10);
  }
  Serial.println("Fin du mode attente.");
  return ret;
}

void halte(void)
{
  Serial.println("Dans fct halte()");
  while (true)
  {
    yield();
  }
}

void dumpTabJoueur()
{
  Serial.printf("\n\tNombre de joueurs : %d\n\n\tDumping tabJoueur:\n", nbJoueur);
  for (int i = 0; i < nbJoueur; i++)
  {
    Serial.print("tabJoueur[");
    Serial.print(i);
    Serial.print("] : ");
    Serial.println(tabJoueur[i]);
  }
  Serial.println();
}

void init_programme(void)
{
  Serial.begin(115200);
  while (!Serial)
  {
    yield(); // wait for serial port to connect. Needed for native USB port only
  }
  pinMode(PIN_BOUTON, INPUT_PULLUP); // Etat hAUT par defaut
  pinMode(PIN_PRESENCE, OUTPUT);     // sert pour detection nombre de raquette presente et allumé
  digitalWrite(PIN_PRESENCE, LOW);
  pinMode(LED_BUILTIN, OUTPUT); // sert pour detection nombre de raquette presente et allumé
  allumeLedBuiltIn(true);       // allume la led de presence
  WiFi.mode(WIFI_STA);
  WiFi.disconnect(); // Onb a pas besoin d'établir de connection WiFi, juste ESP_NOW
  Serial.println("\n");
  Serial.print("\tProgramme : ");
  Serial.print(PROGRAMME_NAME);
  Serial.print(", VER : ");
  Serial.print(VER);
  Serial.print(", carte numero : ");
  Serial.print(NUMERO_CARTE);
  Serial.print(", macAddress : ");
  Serial.println(WiFi.macAddress()); // pour récupérer l'adresse MAC de la carte
  Serial.println();
  // init de l'ESP_NOW

  if (esp_now_init() != 0)
  {
    Serial.println("Erreur de l'initialisation de l'ESP_NOW");
    return;
  }
  else
  {
    Serial.println("ESP_NOW initialise.");
    //esp_now_register_send_cb(OnDataSend);
    esp_now_register_recv_cb(OnDataRecv);
    esp_now_set_peer_channel(broadcastAddress, 1);               // Set the channel to 1 for all peers
    esp_now_set_self_role(ESP_NOW_ROLE_COMBO);                   // Set the role to combo for self
    esp_now_set_peer_role(broadcastAddress, ESP_NOW_ROLE_COMBO); // Set the role to combo for peer
  }
}

AttenteMode pourrait déclencher le watchdog

Que voyez vous dans les consoles série ?

reponses console :

Sortie carte 3*****************************************************

       Programme : Pong, VER : 1.0, carte numero : 3, macAddress : 24:D7:EB:EF:55:CE

ESP_NOW initialise.
Fin du mode attente.
Bouton presse par : 3

        Dans OnDataRecv() : Bytes received : 1 de carte 1

        Nombre de joueurs : 2

        Dumping tabJoueur:
tabJoueur[0] : 3
tabJoueur[1] : 1

Dans fct halte()

Sortie carte 2**********************************************************

17:53:41.388 -> 	Programme : Pong, VER : 1.0, carte numero : 2, macAddress : 24:D7:EB:EF:58:FC
17:53:41.388 -> 
17:53:41.388 -> ESP_NOW initialise.
17:54:00.465 -> 
17:54:00.465 -> 	Dans OnDataRecv() : Bytes received : 1 de carte 3
17:54:00.465 -> Fin du mode attente.
17:54:00.465 -> J'ai ete actionne par une autre carte.
17:54:03.465 -> 
17:54:03.465 -> 	Nombre de joueurs : 2
17:54:03.465 -> 
17:54:03.465 -> 	Dumping tabJoueur:
17:54:03.465 -> tabJoueur[0] : 2
17:54:03.465 -> tabJoueur[1] : 3
17:54:03.465 -> 
17:54:03.465 -> Dans fct halte()

Sortie carte 1**********************************************************

17:53:38.722 -> 	Programme : Pong, VER : 1.0, carte numero : 1, macAddress : 24:D7:EB:EF:52:3D
17:53:38.722 -> 
17:53:38.722 -> ESP_NOW initialise.
17:54:02.769 -> 
17:54:02.769 -> 	Dans OnDataRecv() : Bytes received : 1 de carte 3
17:54:02.769 -> 
17:54:02.769 -> 	Dans OnDataRecv() : Bytes received : 1 de carte 2
17:54:02.769 -> Fin du mode attente.
17:54:02.769 -> J'ai ete actionne par une autre carte.
17:54:05.769 -> 
17:54:05.769 -> 	Nombre de joueurs : 3
17:54:05.769 -> 
17:54:05.769 -> 	Dumping tabJoueur:
17:54:05.769 -> tabJoueur[0] : 1
17:54:05.769 -> tabJoueur[1] : 3
17:54:05.769 -> tabJoueur[2] : 2
17:54:05.769 -> 
17:54:05.769 -> Dans fct halte()

Donc actionné par la carte 3, carte 1 a reçu 3 et 2, mais carte 2 n'a reçu que 3, et carte 3 n'a reçu que carte 1.
pas encore eu ce type de réponse. D'habitude j'ai plutôt 1 carte qui n'est perçu par personne.

je lis sur mon iPhone donc pas simple de voir tout le code d'un coup.

Vous pouvez décrire avec des phrases votre mode opératoire pour enregistrer les cartes / joueurs ?

Je vois que vous définissez une adresse MAC.
Dans un cas comme le vôtre, faisant du copier-coller d'une ESP à l'autre, il est très facile de se tromper d'adresse MAC ou d'oublier de mettre à jour lors du changement de module.

Bien vous assurez d'identifier vos modules ESP afin d'être en mesure de les distinguer visuellement.

Bien vous assurer d'utiliser les bonnes adresses MAC lors de l'envoi.

Si le code fonctionne bien pour un, il n'y a pas beaucoup d'autre option que l'adresse utilisée pour ce même code fonctionne bien avec les autres modules.

Pour ma part, afin de contourner les risques d'erreur, je copies toutes les adresses dans tous les fichiers et j'en sélectionne un seul, comme suit:

Exemple pour le module 1

//Les trois adresses sont
////Module 1
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1};
////Module 2
//uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2};
////Module 3
//uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3};

Exemple pour le module 2

//Les trois adresses sont
////Module 1
//uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1};
////Module 2
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2};
////Module 3
//uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3};

Exemple pour le module 3

//Les trois adresses sont
////Module 1
//uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF1};
////Module 2
//uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF2};
////Module 3
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF3};

Ça me sert aussi de note pour consultations ultérieures et m'évite d'avoir à reconnecter l'appareil pour en connaître la MAC.

C’est l’adresse de broadcast, quand un module veut parler à tous les autres….

Merci à tous de vos réponses.
La doc de chez Espressif , peu documenté pour esp8266(qui devient obsolète apparemment),
stipule que pour des communications de plusieurs ESP avec espnow, il faut gérer les envois dans le temps pour ne pas perturber les émissions et les réceptions.
Bref, j'ai résolu mon problème en utilisant les adresses Mac de chaque carte et en envoyant à chaque carte les datas de façons différée , et en différant aussi leurs réponses.
Du coup tous le monde reçois tout le monde.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.