Protocollo ESP32-NOW Broadcast (Parte 3)

Introduzione

Questo articolo e’ la continuazione dei due precedenti post (parte1, parte2 ), analizzeremo il modo di funzionamento broadcast, cioè tutti i dispositivi possono  comunicare con gli altri.

In questo esempio useremo solo due schede ESP32, l’applicativo può comunque essere utilizzato anche per più dispositivi, il principio di funzionamento è simile.

Connettiamo un pulsante e un diodo LED alle due board coinvolte nella comunicazione, a differenza dell’esempio precedente tratteremo un’applicazione più realistica e di maggiore utilità pratica.

Ovviamente, lo scrittore non può trattare tutti gli argomenti possibili, e lo scopo di molti posts  è solo  divulgativo, affiche’ il lettore possa acquisire le  basi per  la realizzazione di progetti più complessi.

Analizziamo lo schema elettrico e la sua funzionalità:

Figura 1

Ad ogni pressione del pulsante il diodo LED cambia stato, ogni commutazione verrà inviata, tramite una trasmissione dati, alle altre borads che si allineeranno, allo stato ricevuto.  

Codice per la comunicazione broadcast

La comunicazione broadcast , prevede che ogni board ha la possibilità di trasmettere e ricevere dati, pertanto, il codice su ogni scheda è identico.

/*
  /****************************************************************
	Data  28-05-22
	scritto da Gennaro Vitiello
	codice per la comunicazione broadcast con il protocollo ESP32-NOW
    Maggiori informazioni sul sito www.quattrodispositivi.it
******************************************************************/

#include <WiFi.h>
#include <esp_now.h>

// definiamo le variabili booleane per lo sto del pulsante e del diodo LED
bool pulsante = false;
bool LED = false;

// definiamo i pins per il collegamento del LED e pulsante
#define STATO_LED 15
#define STATO_PULSANTE 5


void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength)
// Formattiamo l'indirizzo MAC
{
  snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}


void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int dataLen)
// Verra' chiamata quando un dato e' stato ricevuto
{
  // il protocollo prevede l'invio massimo di 250 byte
//  seguito dal carattere null, terminazione della trasmissione 
  
  char buffer[ESP_NOW_MAX_DATA_LEN + 1];
  int msgLen = min(ESP_NOW_MAX_DATA_LEN, dataLen);
  strncpy(buffer, (const char *)data, msgLen);

  
  buffer[msgLen] = 0;

  // formattiamo l'indirizzo MAC che abbiamo ricevuto
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);

  // Inviamo un messaggio sulla seriale di debug 
  Serial.printf("Messaggio ricevuto da: %s - %s\n", macStr, buffer);

  // controlliamo se arrivato il messaggio on del diodo LED
  if (strcmp("on", buffer) == 0)
  {
    LED = true;
  }
  else
  {
    LED = false;
  }
  digitalWrite(STATO_LED, LED);
}


void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status)
// chaimiamo questa funzione dopo l'invio dei dati.
{
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  Serial.print("Last Packet Sent to: ");
  Serial.println(macStr);
  Serial.print("Last Packet Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "i dati sono stati inviati": "La trasmssione e' fallita");
}

void broadcast(const String &message)
//funzioen che gestisce l'invio dei dati in modalita' broadcast
{
  // di seguito e' riportato l'indirizzo per la comunicazione in modalita' broadcast
  uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
  if (!esp_now_is_peer_exist(broadcastAddress))
  {
    esp_now_add_peer(&peerInfo);
  }
  // invio del messaggio 
  esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());

  // 
  if (result == ESP_OK)
  {
    Serial.println("Messaggio broadcast inviato con successo");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_INIT)
  {
    Serial.println("ESP-NOW non e' inizializzato.");
  }
  else if (result == ESP_ERR_ESPNOW_ARG)
  {
    Serial.println("Argomento non valido");
  }
  else if (result == ESP_ERR_ESPNOW_INTERNAL)
  {
    Serial.println("Errore interno");
  }
  else if (result == ESP_ERR_ESPNOW_NO_MEM)
  {
    Serial.println("ESP_ERR_ESPNOW_NO_MEM");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_FOUND)
  {
    Serial.println("Peer non trovato.");
  }
  else
  {
    Serial.println("errore sconosciuto");
  }
}

void setup()
{

  // impostiamo la seriale
  Serial.begin(115200);
  delay(1000);

  //  impostiamo il WIFI in modalita' STA
  WiFi.mode(WIFI_STA);
  Serial.println("ESP-NOW Broadcast ");

  // stampiamo l'indirizzo MAC
  Serial.print("Indirizzo MAC: ");
  Serial.println(WiFi.macAddress());

  // disconnessione del  WiFi
  WiFi.disconnect();

  // Inizializzazione ESP-NOW
  if (esp_now_init() == ESP_OK)
  {
    Serial.println("ESP-NOW Init Success");
    esp_now_register_recv_cb(receiveCallback);
    esp_now_register_send_cb(sentCallback);
  }
  else
  {
    Serial.println("ESP-NOW Init Failed");
    delay(3000);
    ESP.restart();
  }

  // inseriamo un pull-up sull'ingresso pulsante
  pinMode(STATO_PULSANTE, INPUT_PULLUP);

  // uscita diodo LED
  pinMode(STATO_LED, OUTPUT);
}

void loop()
{
  if (digitalRead(STATO_PULSANTE))
  {
    // verifichiamo se il pulsantee' commutato
    if (!pulsante)
    {
      pulsante = true;
      
      // Toggle del diodo LED
      LED = !LED;
      digitalWrite(STATO_LED, LED);
      
      // inviamo lo stato del diodo LED a tutti i dispositivi
      if (LED)
      {
        broadcast("on");
      }
      else
      {
        broadcast("off");
      }
    }
    
    // ritardo per il rimbalzo del pulsante
    delay(500);
  }
  else
  {
    // Reset dello stato del pulsante 
    pulsante = false;
  }
}

descriviamo di seguito in dettaglio il codice:

void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength)
// Formattiamo l'indirizzo MAC
{
  snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}

La funzione formatta l’indirizzo MAC correttamente.

void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int dataLen)
// Verra' chiamata quando un dato e' stato ricevuto
{
  // il protocollo prevede l'invio massimo di 250 byte
//  seguito dal carattere null, terminazione della trasmissione 
  
  char buffer[ESP_NOW_MAX_DATA_LEN + 1];
  int msgLen = min(ESP_NOW_MAX_DATA_LEN, dataLen);
  strncpy(buffer, (const char *)data, msgLen);

  
  buffer[msgLen] = 0;

  // formattiamo l'indirizzo MAC che abbiamo ricevuto
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);

  // Inviamo un messaggio sulla seriale di debug 
  Serial.printf("Messaggio ricevuto da: %s - %s\n", macStr, buffer);

  // controlliamo se arrivato il messaggio on del diodo LED
  if (strcmp("on", buffer) == 0)
  {
    LED = true;
  }
  else
  {
    LED = false;
  }
  digitalWrite(STATO_LED, LED);
}

La callback verrà chiamata dalla funzione di libreria di ESP32-NOW , definita di seguito “esp_now_register_recv_cb”, quest’ultima si attiva ogni volta che il modulo ESP32 riceve un dato insieme all’indirizzo MAC della board che ha inviato l’informazione.

La funzione di callback gestisce anche il messaggio ricevuto, in particolare, questa parte di codice verifica se nel messaggio c’è la stringa “on” , comando  per l’accensione del diodo LED.

void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status)
// chaimiamo questa funzione dopo l'invio dei dati.
{
  char macStr[18];
  formatMacAddress(macAddr, macStr, 18);
  Serial.print("Last Packet Sent to: ");
  Serial.println(macStr);
  Serial.print("Last Packet Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "i dati sono stati inviati" : "La trasmssione e' fallita");
}

Come abbiamo visto in precedenza anche questa callback,  verrà chiamata da una funzione di libreria dell’ESP32-NOW “esp_now_register_send_cb”, effettua un controllo sul buon esito della trasmissione dei dati e lo stampa sul terminale della seriale.

void broadcast(const String &message)
//funzioen che gestisce l'invio dei dati in modalita' broadcast
{
  // di seguito e' riportato l'indirizzo per la comunicazione in modalita' broadcast
  uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
  esp_now_peer_info_t peerInfo = {};
  memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
  if (!esp_now_is_peer_exist(broadcastAddress))
  {
    esp_now_add_peer(&peerInfo);
  }
  // invio del messaggio 
  esp_err_t result = esp_now_send(broadcastAddress, (const uint8_t *)message.c_str(), message.length());

  // 
  if (result == ESP_OK)
  {
    Serial.println("Messaggio broadcast inviato con successo");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_INIT)
  {
    Serial.println("ESP-NOW non e' inizializzato.");
  }
  else if (result == ESP_ERR_ESPNOW_ARG)
  {
    Serial.println("Argomento non valido");
  }
  else if (result == ESP_ERR_ESPNOW_INTERNAL)
  {
    Serial.println("Errore interno");
  }
  else if (result == ESP_ERR_ESPNOW_NO_MEM)
  {
    Serial.println("ESP_ERR_ESPNOW_NO_MEM");
  }
  else if (result == ESP_ERR_ESPNOW_NOT_FOUND)
  {
    Serial.println("Peer non trovato.");
  }
  else
  {
    Serial.println("errore sconosciuto");
  }
}

La funzione ha il compito di inviare  i dati in modalità broadcast, infatti verrà usato l’indirizzo MAC con tutti valori impostati con  0xFF.

Invia  il comando  per settare il diodo LED connesso al ricevitore.

void loop()
{
  if (digitalRead(STATO_PULSANTE))
  {
    // verifichiamo se il pulsantee' commutato
    if (!pulsante)
    {
      pulsante = true;
      
      // Toggle del diodo LED
      LED = !LED;
      digitalWrite(STATO_LED, LED);
      
      // inviamo lo stato del diodo LED a tutti i dispositivi
      if (LED)
      {
        broadcast("on");
      }
      else
      {
        broadcast("off");
      }
    }
    
    // ritardo per il rimbalzo del pulsante
    delay(500);
  }
  else
  {
    // Reset dello stato del pulsante 
    pulsante = false;
  }
}

Nel loop ogni volta che si preme il pulsante connesso all’ingresso dell’ESP32 si effettua un toggle dell’uscita connessa al diodo LED  e verra’ chiamata la funzione broadcast con  l’impostazione del diodo LED del ricevitore.

Con questo esempio s’è conclusa la terza parte della descrizione del protocollo ESP32-NOW, se avete dei quesiti, non esitate a scrivere nel  form, sarò lieto di rispondervi.

Se volete essere aggiornati su ogni nuova pubblicazione, iscrivetevi alla newsletter link

2 commenti

  1. Con l’esempio che descritto con il sistema broadcast quando tu invii un comando (accensione o spegnimento led) lo invii a tutti però non sai se l’hanno ricevuto tutti quindi occorrerebbe una conferma rispondendo magari con indirizzo Mac di la ricevuto, è possibile avere questa modifica, grazie buona serata e buon lavoro Rik

    • Ciao Rik,
      Ti ringrazio di avermi contattati e fornito un nuovo spunto per un altro posto. La risposta è molto semplice, quando ricevi un messaggio ed è corretto puoi chiamare la funzione per inviare un messaggio al dispositivo che t’ha spedito l’informazione (guarda post1 e post2).

Lascia una risposta

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Ti sei iscritto alla newsletter

There was an error while trying to send your request. Please try again.

Quattrodispositivi utilizzerà le informazioni fornite in questo modulo per restare in contatto con te e fornire aggiornamenti del sito