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à:
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
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).