Создание и настройка сети Mesh на ESP8266

Creare e configurare con codice una rete mesh con 4 schede esp8266. E' possibile?
Homi

Certamente! Creare e configurare una rete mesh con 4 schede ESP8266 è assolutamente possibile. Esistono diverse librerie e approcci per realizzare questo tipo di rete.

Ti illustrerò un metodo comune e relativamente semplice da implementare utilizzando la libreria ESP-NOW per la comunicazione diretta tra i nodi e una libreria per la gestione della mesh, come EasyMesh.

Requisiti:

  • 4x schede ESP8266 (es. NodeMCU, Wemos D1 Mini)
  • Arduino IDE installato con il supporto per le schede ESP8266
  • Cablaggio di base (alimentazione, eventuali connessioni seriali per debug)

Concetto della Rete Mesh:

Una rete mesh permette ai dispositivi di comunicare tra loro direttamente o passando attraverso altri nodi. Questo aumenta la portata e la robustezza della rete. In questo caso, utilizzeremo ESP-NOW per una comunicazione rapida e a basso consumo, e EasyMesh per semplificare la gestione dei ruoli dei nodi (master, slave) e la propagazione dei dati.

Librerie Necessarie:

  1. ESP-NOW: Solitamente inclusa nel core ESP8266 per Arduino IDE.
  2. EasyMesh: Dovrai installarla tramite il Library Manager dell'Arduino IDE. Cerca "EasyMesh".

Implementazione (Esempio con EasyMesh):

L'approccio con EasyMesh è il seguente:

  • 1 Nascosto (Master): Questo nodo funge da "punto di accesso" o router. Gli altri nodi si connettono ad esso.
  • 3 Slave (Nodi): Questi nodi si connettono al master e possono inviare/ricevere dati attraverso di esso.

Ecco un esempio di codice. Dovrai caricare versioni leggermente modificate su ciascun ESP8266, specificando il ruolo (master o slave).

Codice Base (da adattare per ogni nodo)

CPP
#include <ESP8266WiFi.h>
#include <easy-mesh.h>

// --- Impostazioni Configurabili ---
const char* ssid = "MiaReteMesh"; // Nome della rete mesh (non serve password per ESP-NOW)
const char* password = "";        // Password per la connessione WiFi (se necessario)

// Indirizzi MAC dei nodi (scoperti o predefiniti)
// In una rete reale, questi indirizzi dovrebbero essere dinamici o configurati
// MAC address del Master (per gli slave da connettere)
uint8_t masterMAC[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX}; // Inserisci il MAC del master qui

// --- Variabili EasyMesh ---
EasyMesh mesh;

// --- Callback per messaggi ricevuti ---
void onReceive(uint8_t* mac, uint8_t* receivedData, uint8_t dataLen) {
  Serial.print("Messaggio da: ");
  for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", mac[i]);
    if (i < 5) Serial.print(":");
  }
  Serial.print("\t");

  char buffer[dataLen + 1];
  memcpy(buffer, receivedData, dataLen);
  buffer[dataLen] = '\0';
  Serial.println(buffer);

  // Qui puoi aggiungere logica per gestire i messaggi ricevuti
}

// --- Setup ---
void setup() {
  Serial.begin(115200);
  Serial.println();

  // Inizializza WiFi
  WiFi.mode(WIFI_STA); // Ogni nodo opera come Station
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connesso!");
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());

  // Inizializza EasyMesh
  // Il ruolo (master/slave) viene definito nel codice specifico per ogni nodo
  if (mesh.init(ssid, password, "1.0", MESH_CLIENT, WIFI_AP_SSID, WIFI_AP_PASS, 0)) {
    Serial.println("EasyMesh inizializzato con successo!");
  } else {
    Serial.println("Errore inizializzazione EasyMesh.");
    ESP.restart();
  }

  // Registra la callback per i messaggi ricevuti
  mesh.onReceive(&onReceive);
}

// --- Loop ---
void loop() {
  mesh.update(); // Aggiorna lo stato della mesh

  // Esempio: invia un messaggio ogni 10 secondi (solo per dimostrazione)
  static unsigned long lastMsgTime = 0;
  if (millis() - lastMsgTime > 10000) {
    lastMsgTime = millis();

    // Invia a tutti i nodi connessi
    // Nota: Questo invio è da adattare in base al ruolo del nodo.
    // Un master potrebbe inviare un messaggio di broadcast, uno slave potrebbe inviare al master.
    String message = "Ciao dalla mia ESP8266!";
    Serial.print("Invio messaggio: ");
    Serial.println(message);
    mesh.sendBroadcast(message.c_str(), message.length());
  }
}

Configurazione per ogni Nodo:

Dovrai modificare la parte mesh.init() e la logica di invio per distinguere tra master e slave.

Nodo 1: Master

CPP
// ... (includi le stesse librerie e definizioni) ...

void setup() {
  // ... (setup WiFi come sopra) ...

  // Inizializza EasyMesh come AP (Access Point)
  // Questo nodo sarà il "router" della mesh
  if (mesh.init(ssid, password, "1.0", MESH_AP, WIFI_AP_SSID, WIFI_AP_PASS, 6)) { // 6 = numero massimo di client
    Serial.println("EasyMesh inizializzato come AP (Master)!");
  } else {
    Serial.println("Errore inizializzazione EasyMesh.");
    ESP.restart();
  }

  // ... (registra callback) ...
}

void loop() {
  mesh.update();

  // Il master può inviare messaggi di broadcast o messaggi specifici ai client
  static unsigned long lastMsgTime = 0;
  if (millis() - lastMsgTime > 10000) {
    lastMsgTime = millis();
    String message = "Messaggio dal Master!";
    Serial.print("Invio broadcast dal Master: ");
    Serial.println(message);
    mesh.sendBroadcast(message.c_str(), message.length());
  }
}

Nodi 2, 3, 4: Slave

CPP
// ... (includi le stesse librerie e definizioni) ...

// Indirizzo MAC del Master (devi trovarlo e inserirlo qui!)
uint8_t masterMAC[] = {0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX};

void setup() {
  // ... (setup WiFi come sopra) ...

  // Inizializza EasyMesh come Client
  // Questo nodo si connetterà al Master (AP)
  if (mesh.init(ssid, password, "1.0", MESH_CLIENT, WIFI_AP_SSID, WIFI_AP_PASS, 0)) { // 0 = nessun limite esplicito di client
    Serial.println("EasyMesh inizializzato come Client (Slave)!");
  } else {
    Serial.println("Errore inizializzazione EasyMesh.");
    ESP.restart();
  }

  // ... (registra callback) ...
}

void loop() {
  mesh.update();

  // Gli slave inviano tipicamente messaggi al master o ad altri nodi specifici
  static unsigned long lastMsgTime = 0;
  if (millis() - lastMsgTime > 10000) {
    lastMsgTime = millis();
    String message = "Ciao dal mio Slave!";
    Serial.print("Invio messaggio dal Slave: ");
    Serial.println(message);
    // Invia al master (se conosci il suo MAC) o tramite broadcast
    mesh.sendBroadcast(message.c_str(), message.length());
    // Oppure, per inviare al master specifico:
    // mesh.send(masterMAC, message.c_str(), message.length());
  }
}

Note Importanti:

  1. Indirizzi MAC: L'esempio assume che tu conosca l'indirizzo MAC del nodo master. In una rete più dinamica, potresti dover implementare un meccanismo di scoperta o registrazione dei nodi.
  2. Gestione dei Dati: La funzione onReceive è dove decidi cosa fare con i dati ricevuti. Potresti inoltrarli, usarli per controllare attuatori, ecc.
  3. Robustezza: EasyMesh gestisce la riconnessione e la stabilità della rete.
  4. Debug: Utilizza Serial.println() abbondantemente per capire cosa sta succedendo su ogni nodo.
  5. Alternative: Oltre a EasyMesh, esistono altre librerie come ESPAsyncMesh o puoi implementare una mesh più rudimentale basata solo su ESP-NOW e logica custom per il routing.

Questo è un punto di partenza. Dovrai adattare il codice alle tue specifiche esigenze e sperimentare per ottimizzare la comunicazione e la gestione dei dati nella tua rete mesh.

Forniscimi un esempio pratico di invio di dati da uno slave al master e viceversa in una rete mesh ESP8266.
Homi

Certamente! Ecco un esempio pratico che illustra l'invio di dati bidirezionale tra un nodo Master e uno Slave in una rete mesh ESP8266 utilizzando la libreria EasyMesh.

Scenario:

  • Master: Riceve un messaggio dallo Slave e invia un messaggio di "conferma" o "risposta" allo Slave.
  • Slave: Invia un messaggio al Master e poi attende una risposta.

Assunzioni:

  • Hai già configurato le 4 schede ESP8266 come descritto in precedenza, con un nodo impostato come Master (AP) e gli altri come Slave (Client).
  • Conosci l'indirizzo MAC del nodo Master (per gli Slave) e idealmente il MAC dello Slave (per il Master, se si vuole inviare direttamente). Per semplicità, in questo esempio, il Master userà sendBroadcast per raggiungere tutti gli Slave, e lo Slave userà send per inviare specificamente al Master (assumendo che il Master sia l'unico AP e quindi il destinatario più logico).

Codice per il Nodo Master

CPP
#include <ESP8266WiFi.h>
#include <easy-mesh.h>

// --- Impostazioni Configurabili ---
const char* ssid = "MiaReteMesh";
const char* password = "";
const char* ap_ssid = "MiaReteMesh_AP"; // Nome dell'AP creato dal Master
const char* ap_password = "";

// --- Variabili EasyMesh ---
EasyMesh mesh;
uint8_t slaveMAC[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; // Verrà aggiornato quando uno slave si connette
bool slaveFound = false;

// --- Callback per messaggi ricevuti ---
void onReceive(uint8_t* mac, uint8_t* receivedData, uint8_t dataLen) {
  char buffer[dataLen + 1];
  memcpy(buffer, receivedData, dataLen);
  buffer[dataLen] = '\0';

  Serial.print("<- [MASTER] Messaggio ricevuto da: ");
  for (int i = 0; i < 6; i++) {
    Serial.printf("%02X", mac[i]);
    if (i < 5) Serial.print(":");
  }
  Serial.print(" -> ");
  Serial.println(buffer);

  // Se il messaggio proviene da uno slave, invia una risposta
  // In questo esempio, assumiamo che qualsiasi messaggio ricevuto sia dallo slave
  // e che lo slave si connetta (quindi il suo MAC è salvato).
  // In una rete più complessa, potresti voler controllare il MAC.

  // Salva il MAC dello slave se non l'abbiamo ancora
  if (!slaveFound) {
      memcpy(slaveMAC, mac, 6);
      slaveFound = true;
      Serial.print("-> [MASTER] MAC dello slave salvato: ");
      for (int i = 0; i < 6; i++) { Serial.printf("%02X", slaveMAC[i]); if (i < 5) Serial.print(":"); }
      Serial.println();
  }

  // Invia una risposta allo slave
  String response = "Master ha ricevuto: '" + String(buffer) + "'";
  Serial.print("-> [MASTER] Invio risposta a Slave: ");
  Serial.println(response);
  // Invia solo al MAC specifico dello slave che ha inviato il messaggio
  if (slaveFound) {
    mesh.send(slaveMAC, response.c_str(), response.length());
  } else {
    Serial.println("-> [MASTER] Impossibile inviare risposta, MAC dello slave non noto.");
  }
}

// --- Setup ---
void setup() {
  Serial.begin(115200);
  Serial.println();

  WiFi.mode(WIFI_AP); // Il Master opera come Access Point
  WiFi.softAP(ap_ssid, ap_password); // Configura l'AP
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());

  // Inizializza EasyMesh come AP
  if (mesh.init(ssid, password, "1.0", MESH_AP, ap_ssid, ap_password, 6)) {
    Serial.println("EasyMesh inizializzato come AP (Master)!");
  } else {
    Serial.println("Errore inizializzazione EasyMesh.");
    ESP.restart();
  }

  mesh.onReceive(&onReceive);
  Serial.println("Master pronto. In attesa di connessioni da parte degli slave...");
}

// --- Loop ---
void loop() {
  mesh.update();

  // Il Master non ha bisogno di inviare messaggi attivamente in questo esempio,
  // risponde solo ai messaggi ricevuti dagli slave.
  // Potrebbe inviare comandi periodici se necessario.
}

Codice per il Nodo Slave

CPP
#include <ESP8266WiFi.h>
#include <easy-mesh.h>

// --- Impostazioni Configurabili ---
const char* ssid = "MiaReteMesh";
const char* password = "";
// Dettagli dell'AP a cui connettersi (quello creato dal Master)
const char* ap_ssid = "MiaReteMesh_AP";
const char* ap_password = "";

// --- Variabili EasyMesh ---
EasyMesh mesh;

// --- Callback per messaggi ricevuti ---
void onReceive(uint8_t* mac, uint8_t* receivedData, uint8_t dataLen) {
  char buffer[dataLen + 1];
  memcpy(buffer, receivedData, dataLen);
  buffer[dataLen] = '\0';

  Serial.print("<- [SLAVE] Messaggio ricevuto da Master: ");
  Serial.println(buffer);

  // Qui puoi aggiungere logica per gestire la risposta del master
}

// --- Setup ---
void setup() {
  Serial.begin(115200);
  Serial.println();

  // Inizializza WiFi come Station per connettersi all'AP del Master
  WiFi.mode(WIFI_STA);
  WiFi.begin(ap_ssid, ap_password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\nWiFi connesso all'AP del Master!");
  Serial.print("MAC Address Slave: ");
  Serial.println(WiFi.macAddress());

  // Inizializza EasyMesh come Client
  if (mesh.init(ssid, password, "1.0", MESH_CLIENT, ap_ssid, ap_password, 0)) {
    Serial.println("EasyMesh inizializzato come Client (Slave)!");
  } else {
    Serial.println("Errore inizializzazione EasyMesh.");
    ESP.restart();
  }

  mesh.onReceive(&onReceive);
}

// --- Loop ---
void loop() {
  mesh.update();

  // Invia un messaggio al Master ogni 10 secondi
  static unsigned long lastMsgTime = 0;
  if (millis() - lastMsgTime > 10000) {
    lastMsgTime = millis();

    String message = "Ciao dal mio Slave (" + String(WiFi.macAddress()) + ")!";
    Serial.print("-> [SLAVE] Invio messaggio al Master: ");
    Serial.println(message);

    // Invia un messaggio broadcast. Il Master lo riceverà.
    // Nota: EasyMesh gestisce l'inoltro. Inviando broadcast, il Master (che è un AP)
    // dovrebbe riceverlo. Se volessi inviare solo al master, dovresti conoscere
    // il suo MAC e usare mesh.send(masterMAC, ...).
    mesh.sendBroadcast(message.c_str(), message.length());
  }
}

Come Utilizzare:

  1. Compila e Carica:
    • Carica il codice del Master su una delle tue ESP8266.
    • Carica il codice dello Slave sulle altre tre ESP8266.
  2. Accendi i Dispositivi: Avvia prima il nodo Master, poi gli Slave.
  3. Monitor Seriali: Apri i monitor seriali per ogni ESP8266 per osservare la comunicazione.

Cosa Vedrai nei Monitor Seriali:

  • Master:
    • Indirizzo IP dell'AP.
    • Messaggi di inizializzazione.
    • Messaggi dal tipo: "<- [MASTER] Messaggio ricevuto da: XX:XX:XX:XX:XX:XX -> Ciao dal mio Slave (YY:YY:YY:YY:YY:YY)!"
    • Messaggi dal tipo: "-> [MASTER] Invio risposta a Slave: Master ha ricevuto: 'Ciao dal mio Slave (YY:YY:YY:YY:YY:YY)!'"
  • Slave:
    • Connessione all'AP del Master.
    • Messaggi di inizializzazione.
    • Messaggi dal tipo: "-> [SLAVE] Invio messaggio al Master: Ciao dal mio Slave (YY:YY:YY:YY:YY:YY)!"
    • Messaggi dal tipo: "<- [SLAVE] Messaggio ricevuto da Master: Master ha ricevuto: 'Ciao dal mio Slave (YY:YY:YY:YY:YY:YY)!'".

Considerazioni Aggiuntive:

  • Indirizzo MAC del Master: Nel codice dello Slave, per inviare messaggi specificamente al Master usando mesh.send(masterMAC, ...), dovresti conoscere il MAC del Master. Puoi trovarlo monitorando l'output seriale del Master durante l'avvio. Oppure, potresti implementare un meccanismo di "saluto" iniziale dove il Master comunica il suo MAC agli Slave appena si connettono.
  • Routing: EasyMesh gestisce il routing. Se uno Slave volesse inviare un messaggio a un altro Slave, il messaggio verrebbe probabilmente inoltrato attraverso il Master.
  • Gestione Errori: Questo è un esempio base. In una rete reale, dovresti aggiungere una gestione più robusta per disconnessioni, errori di invio, ecc.
  • Tipi di Dati: Nell'esempio inviamo stringhe. Puoi inviare dati binari serializzandoli in un array di byte, ma dovrai gestire la deserializzazione sul ricevitore.

Questo esempio dovrebbe darti una solida base per implementare la comunicazione bidirezionale nella tua rete mesh ESP8266.

Homi
Текст скопирован
Готово
Ошибка