ESP32 : ESP-NOW et tableau de bord du serveur Web Wi-Fi (Arduino)

ESP32 : ESP-NOW et tableau de bord du serveur Web Wi-Fi (Arduino)

Dans ce projet, vous apprendrez à héberger un serveur Web ESP32 et à utiliser le protocole de communication ESP-NOW en même temps. Vous pouvez avoir plusieurs cartes ESP32 envoyant des lectures de capteurs via ESP-NOW à un récepteur ESP32 qui affiche toutes les lectures sur un serveur Web. Les cartes seront programmées à l’aide de l’IDE Arduino.

ESP32 : tableau de bord de capteur de serveur Web ESP-NOW utilisant Arduino IDE (ESP-NOW et Wi-Fi simultanément)

Nous avons d’autres guides liés à ESP-NOW qui pourraient vous intéresser :

Regardez le didacticiel vidéo

YouTube video

Remarque : nous avons mis à jour ce didacticiel avec une meilleure méthode pour utiliser ESP-NOW et le Wi-Fi simultanément. La vidéo n’utilise pas cette méthode actuelle. Vous pouvez toujours regarder la vidéo pour voir comment tout fonctionne, mais nous vous recommandons de jeter un œil à l’article écrit.

Utilisation simultanée d’ESP-NOW et du Wi-Fi

Utilisation simultanée d'ESP-NOW et du Wi-Fi : serveur Web du récepteur ESP-NOW et cartes d'envoi ESP-NOW

Il y a quelques éléments dont vous devez tenir compte si vous souhaitez utiliser le Wi-Fi pour héberger un serveur Web et utiliser ESP-NOW simultanément pour recevoir les lectures des capteurs d’autres cartes :

  • Les cartes émettrices ESP32 doivent utiliser le même canal Wi-Fi de la carte réceptrice.
  • Le canal Wi-Fi de la carte récepteur est automatiquement attribué par votre routeur Wi-Fi.
  • Le mode Wi-Fi de la carte réceptrice doit être point d’accès et station (WIFI_AP_STA).
  • Vous pouvez configurer le même canal Wi-Fi manuellement, ou vous pouvez ajouter une simple colonne vertébrale de code sur l’expéditeur pour définir son canal Wi-Fi sur le même que celui de la carte réceptrice.

Aperçu du projet

Le diagramme suivant montre une vue d’ensemble de haut niveau du projet que nous allons construire.

Serveur Web du récepteur ESP-NOW et cartes ESP32 envoyant des lectures de température et d'humidité avec ESP-NOW
  • Il y a deux cartes émettrices ESP32 qui envoient DHT22 lectures de température et d’humidité via ESP-NOW vers une carte récepteur ESP32 (configuration ESP-NOW plusieurs à un);
  • La carte réceptrice ESP32 reçoit les paquets et affiche les lectures sur un serveur Web ;
  • Le serveur Web est mis à jour automatiquement chaque fois qu’il reçoit une nouvelle lecture à l’aide des événements envoyés par le serveur (SSE).

Conditions préalables

Avant de poursuivre ce projet, assurez-vous de vérifier les prérequis suivants.

EDI Arduino

Nous allons programmer les cartes ESP32 à l’aide de l’IDE Arduino, donc avant de poursuivre ce tutoriel, assurez-vous que la carte ESP32 est installée dans votre IDE Arduino.

Bibliothèques DHT

La carte d’envoi ESP32 enverra les lectures de température et d’humidité à partir d’un capteur DHT22.

Pour lire à partir du capteur DHT, nous utiliserons le Bibliothèque DHT d’Adafruit. Pour utiliser cette bibliothèque, vous devez également installer le Bibliothèque de capteurs unifiés Adafruit. Suivez les étapes suivantes pour installer ces bibliothèques.

1. Ouvrez votre IDE Arduino et accédez à Sketch > Inclure la bibliothèque > Gérer les bibliothèques. Le gestionnaire de bibliothèque devrait s’ouvrir.

2. Recherchez « DHT » dans la zone de recherche et installez la bibliothèque DHT d’Adafruit.

Installation de la bibliothèque Adafruit DHT

3. Après avoir installé la bibliothèque DHT d’Adafruit, saisissez « Adafruit Unified Sensor » dans la zone de recherche. Faites défiler vers le bas pour trouver la bibliothèque et installez-la.

Installation de la bibliothèque de pilotes Adafruit Unified Sensor

Après avoir installé les bibliothèques, redémarrez votre IDE Arduino.

Pour en savoir plus sur le capteur de température DHT11 ou DHT22, lisez notre guide : ESP32 avec capteur de température et d’humidité DHT11/DHT22 utilisant Arduino IDE.

Bibliothèques de serveurs Web asynchrones

Pour construire le serveur Web, vous devez installer les bibliothèques suivantes :

Ces bibliothèques ne peuvent pas être installées via le gestionnaire de bibliothèque Arduino, vous devez donc copier les fichiers de bibliothèque dans le dossier Bibliothèques d’installation Arduino. Alternativement, dans votre IDE Arduino, vous pouvez aller à Sketch> Inclure la bibliothèque> Ajouter une bibliothèque .zip et sélectionner les bibliothèques que vous venez de télécharger.

Bibliothèque Arduino_JSON

Vous devez installer la bibliothèque Arduino_JSON. Vous pouvez installer cette bibliothèque dans le gestionnaire de bibliothèque Arduino IDE. Accédez simplement à Sketch > Inclure la bibliothèque > Gérer les bibliothèques et recherchez le nom de la bibliothèque comme suit :

Installer la bibliothèque Arduino JSON Arduino IDE

Pièces requises

Pour suivre ce tutoriel, vous avez besoin de plusieurs cartes ESP32. Nous utiliserons trois cartes ESP32. Tu as aussi besoin:

Vous pouvez utiliser les liens précédents ou accéder directement à MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

1680549977 808 ESP32 ESP NOW et tableau de bord du serveur Web Wi Fi

Obtention de l’adresse MAC de la carte du récepteur

Pour envoyer des messages via ESP-NOW, vous devez connaître l’adresse MAC de la carte réceptrice. Chaque carte a une adresse MAC unique (découvrez comment obtenir et modifier l’adresse MAC ESP32).

Téléchargez le code suivant sur votre carte récepteur ESP32 pour obtenir son adresse MAC.

// Complete Instructions to Get and Change ESP MAC Address: https://Raspberryme.com/get-change-esp32-esp8266-mac-address-arduino/

#ifdef ESP32
  #include <WiFi.h>
#else
  #include <ESP8266WiFi.h>
#endif

void setup(){
  Serial.begin(115200);
  Serial.println();
  Serial.print("ESP Board MAC Address:  ");
  Serial.println(WiFi.macAddress());
}
 
void loop(){

}

Afficher le code brut

Après avoir téléchargé le code, appuyez sur le bouton RST/EN et l’adresse MAC devrait s’afficher sur le moniteur série.

Adresse MAC de la carte ESP32 avec moniteur série Arduino IDE

Récepteur ESP32 (ESP-NOW + Serveur Web)

La carte réceptrice ESP32 reçoit les paquets des cartes émettrices et héberge un serveur Web pour afficher les dernières lectures reçues.

Téléchargez le code suivant sur votre carte réceptrice – le code est préparé pour recevoir des lectures de deux cartes différentes.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-esp-now-wi-fi-web-server/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <Arduino_JSON.h>

// Replace with your network credentials (STATION)
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Structure example to receive data
// Must match the sender structure
typedef struct struct_message {
  int id;
  float temp;
  float hum;
  unsigned int readingId;
} struct_message;

struct_message incomingReadings;

JSONVar board;

AsyncWebServer server(80);
AsyncEventSource events("/events");

// callback function that will be executed when data is received
void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) { 
  // Copies the sender mac address to a string
  char macStr[18];
  Serial.print("Packet received from: ");
  snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
           mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
  Serial.println(macStr);
  memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));
  
  board["id"] = incomingReadings.id;
  board["temperature"] = incomingReadings.temp;
  board["humidity"] = incomingReadings.hum;
  board["readingId"] = String(incomingReadings.readingId);
  String jsonString = JSON.stringify(board);
  events.send(jsonString.c_str(), "new_readings", millis());
  
  Serial.printf("Board ID %u: %u bytes\n", incomingReadings.id, len);
  Serial.printf("t value: %4.2f \n", incomingReadings.temp);
  Serial.printf("h value: %4.2f \n", incomingReadings.hum);
  Serial.printf("readingID value: %d \n", incomingReadings.readingId);
  Serial.println();
}

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP-NOW DASHBOARD</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
  <link rel="icon" href="data:,">
  <style>
    html {font-family: Arial; display: inline-block; text-align: center;}
    p {  font-size: 1.2rem;}
    body {  margin: 0;}
    .topnav { overflow: hidden; background-color: #2f4468; color: white; font-size: 1.7rem; }
    .content { padding: 20px; }
    .card { background-color: white; box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5); }
    .cards { max-width: 700px; margin: 0 auto; display: grid; grid-gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
    .reading { font-size: 2.8rem; }
    .packet { color: #bebebe; }
    .card.temperature { color: #fd7e14; }
    .card.humidity { color: #1b78e2; }
  </style>
</head>
<body>
  <div class="topnav">
    <h3>ESP-NOW DASHBOARD</h3>
  </div>
  <div class="content">
    <div class="cards">
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #1 - TEMPERATURE</h4><p><span class="reading"><span id="t1"></span> &deg;C</span></p><p class="packet">Reading ID: <span id="rt1"></span></p>
      </div>
      <div class="card humidity">
        <h4><i class="fas fa-tint"></i> BOARD #1 - HUMIDITY</h4><p><span class="reading"><span id="h1"></span> &percnt;</span></p><p class="packet">Reading ID: <span id="rh1"></span></p>
      </div>
      <div class="card temperature">
        <h4><i class="fas fa-thermometer-half"></i> BOARD #2 - TEMPERATURE</h4><p><span class="reading"><span id="t2"></span> &deg;C</span></p><p class="packet">Reading ID: <span id="rt2"></span></p>
      </div>
      <div class="card humidity">
        <h4><i class="fas fa-tint"></i> BOARD #2 - HUMIDITY</h4><p><span class="reading"><span id="h2"></span> &percnt;</span></p><p class="packet">Reading ID: <span id="rh2"></span></p>
      </div>
    </div>
  </div>
<script>
if (!!window.EventSource) {
 var source = new EventSource('/events');
 
 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);
 
 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);
 
 source.addEventListener('new_readings', function(e) {
  console.log("new_readings", e.data);
  var obj = JSON.parse(e.data);
  document.getElementById("t"+obj.id).innerHTML = obj.temperature.toFixed(2);
  document.getElementById("h"+obj.id).innerHTML = obj.humidity.toFixed(2);
  document.getElementById("rt"+obj.id).innerHTML = obj.readingId;
  document.getElementById("rh"+obj.id).innerHTML = obj.readingId;
 }, false);
}
</script>
</body>
</html>)rawliteral";

void setup() {
  // Initialize Serial Monitor
  Serial.begin(115200);

  // Set the device as a Station and Soft Access Point simultaneously
  WiFi.mode(WIFI_AP_STA);
  
  // Set device as a Wi-Fi Station
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Setting as a Wi-Fi Station..");
  }
  Serial.print("Station IP Address: ");
  Serial.println(WiFi.localIP());
  Serial.print("Wi-Fi Channel: ");
  Serial.println(WiFi.channel());

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }
  
  // Once ESPNow is successfully Init, we will register for recv CB to
  // get recv packer info
  esp_now_register_recv_cb(OnDataRecv);

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html);
  });
   
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();
}
 
void loop() {
  static unsigned long lastEventTime = millis();
  static const unsigned long EVENT_INTERVAL_MS = 5000;
  if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
    events.send("ping",NULL,millis());
    lastEventTime = millis();
  }
}

Afficher le code brut

Comment fonctionne le code

Tout d’abord, incluez les bibliothèques nécessaires.

#include <esp_now.h>
#include <WiFi.h>
#include "ESPAsyncWebServer.h"
#include <Arduino_JSON.h>

Le Bibliothèque Arduino_JSON est nécessaire car nous allons créer une variable JSON avec les données reçues de chaque carte. Cette variable JSON sera utilisée pour envoyer toutes les informations nécessaires à la page Web, comme vous le verrez plus tard dans ce projet.

Insérez vos informations d’identification réseau sur les lignes suivantes afin que l’ESP32 puisse se connecter à votre réseau local.

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

Structure de données

Ensuite, créez une structure qui contient les données que nous recevrons. Nous avons appelé cette structure struct_message et elle contient l’ID de la carte, les lectures de température et d’humidité et l’ID de lecture.

typedef struct struct_message {
    int id;
    float temp;
    float hum;
    int readingId;
} struct_message;

Créez une nouvelle variable de type struct_message qui s’appelle entrantReadings qui stockera les valeurs des variables.

struct_message incomingReadings;

Créez une variable JSON appelée board.

JSONVar board;

Créez un serveur Web asynchrone sur le port 80.

AsyncWebServer server(80);

Créer une source d’événement

Pour afficher automatiquement les informations sur le serveur Web lorsqu’une nouvelle lecture arrive, nous utiliserons Server-Sent Events (SSE).

La ligne suivante crée une nouvelle source d’événement sur /events.

AsyncEventSource events("/events");

Les événements envoyés par le serveur permettent à une page Web (client) d’obtenir des mises à jour d’un serveur. Nous l’utiliserons pour afficher automatiquement de nouvelles lectures sur la page du serveur Web lorsqu’un nouveau paquet ESP-NOW arrivera.

Important : les événements envoyés par le serveur ne sont pas pris en charge sur Internet Explorer.

Fonction OnDataRecv()

La fonction OnDataRecv() sera exécutée lorsque vous recevrez un nouveau paquet ESP-NOW.

void OnDataRecv(const uint8_t * mac_addr, const uint8_t *incomingData, int len) {

Dans cette fonction, imprimez l’adresse MAC de l’expéditeur :

// Copies the sender mac address to a string
char macStr[18];
Serial.print("Packet received from: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
         mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.println(macStr);

Copiez les informations de la variable entrantData dans la variable de structure entranteReadings.

memcpy(&incomingReadings, incomingData, sizeof(incomingReadings));

Ensuite, créez une variable JSON String avec les informations reçues (variable jsonString) :

board["id"] = incomingReadings.id;
board["temperature"] = incomingReadings.temp;
board["humidity"] = incomingReadings.hum;
board["readingId"] = String(incomingReadings.readingId);
String jsonString = JSON.stringify(board);

Voici un exemple de ce à quoi la variable jsonString peut ressembler après avoir reçu les lectures :

board = {
  "id": "1",
  "temperature": "24.32",
  "humidity" = "65.85",
  "readingId" = "2"
}

Après avoir rassemblé toutes les données reçues sur la variable jsonString, envoyez ces informations au navigateur sous forme d’événement (« new_readings »).

events.send(jsonString.c_str(), "new_readings", millis());

Plus tard, nous verrons comment gérer ces événements côté client.

Enfin, imprimez les informations reçues sur le moniteur série Arduino IDE à des fins de débogage :

Serial.printf("Board ID %u: %u bytes\n", incomingReadings.id, len);
Serial.printf("t value: %4.2f \n", incomingReadings.temp);
Serial.printf("h value: %4.2f \n", incomingReadings.hum);
Serial.printf("readingID value: %d \n", incomingReadings.readingId);
Serial.println();

Construire la page Web

La variable index_html contient tout le HTML, CSS et JavaScript pour construire la page Web. Nous n’entrerons pas dans les détails du fonctionnement du HTML et du CSS. Nous allons juste voir comment gérer les événements envoyés par le serveur.

Gérer les événements

Créez un nouvel objet EventSource et spécifiez l’URL de la page qui envoie les mises à jour. Dans notre cas, il s’agit de /events.

if (!!window.EventSource) {
 var source = new EventSource('/events');

Une fois que vous avez instancié une source d’événement, vous pouvez commencer à écouter les messages du serveur avec addEventListener().

Ce sont les écouteurs d’événements par défaut, comme indiqué ici dans AsyncWebServer Documentation.

source.addEventListener('open', function(e) {
  console.log("Events Connected");
}, false);
source.addEventListener('error', function(e) {
 if (e.target.readyState != EventSource.OPEN) {
   console.log("Events Disconnected");
 }
}, false);

source.addEventListener('message', function(e) {
 console.log("message", e.data);
}, false);

Ensuite, ajoutez l’écouteur d’événement pour « new_readings ».

source.addEventListener('new_readings', function(e) {

Lorsque l’ESP32 reçoit un nouveau paquet, il envoie une chaîne JSON avec les lectures en tant qu’événement (« new_readings ») au client. Les lignes suivantes gèrent ce qui se passe lorsque le navigateur reçoit cet événement.

console.log("new_readings", e.data);
var obj = JSON.parse(e.data);
document.getElementById("t"+obj.id).innerHTML = obj.temperature.toFixed(2);
document.getElementById("h"+obj.id).innerHTML = obj.humidity.toFixed(2);
document.getElementById("rt"+obj.id).innerHTML = obj.readingId;
document.getElementById("rh"+obj.id).innerHTML = obj.readingId;

Fondamentalement, imprimez les nouvelles lectures sur la console du navigateur et placez les données reçues dans les éléments avec l’identifiant correspondant sur la page Web.

installation()

Dans le setup(), configurez le récepteur ESP32 comme point d’accès et station Wi-Fi :

WiFi.mode(WIFI_AP_STA);

Les lignes suivantes connectent l’ESP32 à votre réseau local et impriment l’adresse IP et le canal Wi-Fi :

// Set device as a Wi-Fi Station
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.println("Setting as a Wi-Fi Station..");
}
Serial.print("Station IP Address: ");
Serial.println(WiFi.localIP());
Serial.print("Wi-Fi Channel: ");
Serial.println(WiFi.channel());

Initialisez ESP-NOW.

if (esp_now_init() != ESP_OK) {
  Serial.println("Error initializing ESP-NOW");
  return;
}

Enregistrez-vous pour la fonction de rappel OnDataRecv, afin qu’elle soit exécutée lorsqu’un nouveau paquet ESP-NOW arrive.

esp_now_register_recv_cb(OnDataRecv);

Traiter les demandes

Lorsque vous accédez à l’adresse IP ESP32 sur la root/URL, envoyez le texte qui est stocké sur la variable index_html pour créer la page Web.

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/html", index_html);
});

Source d’événement du serveur

Configurez la source d’événement sur le serveur.

events.onConnect([](AsyncEventSourceClient *client){
  if(client->lastId()){
    Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
  }
  // send event with message "hello!", id current millis
  // and set reconnect delay to 1 second
  client->send("hello!", NULL, millis(), 10000);
 );
  server.addHandler(&events);

Enfin, démarrez le serveur.

server.begin();

boucle()

Dans la boucle(), envoyez un ping toutes les 5 secondes. Ceci est utilisé pour vérifier du côté client, si le serveur est toujours en cours d’exécution.

static unsigned long lastEventTime = millis();
static const unsigned long EVENT_INTERVAL_MS = 5000;
if ((millis() - lastEventTime) > EVENT_INTERVAL_MS) {
  events.send("ping",NULL,millis());
  lastEventTime = millis();
}

Le diagramme suivant résume le fonctionnement des événements envoyés par le serveur sur ce projet et comment il met à jour les valeurs sans actualiser la page Web.

Présentation du projet de tableau de bord de capteur de serveur Web ESP32 ESP-NOW

Après avoir téléchargé le code sur la carte du récepteur, appuyez sur le bouton EN/RST intégré. L’adresse IP ESP32 doit être imprimée sur le moniteur série ainsi que sur le canal Wi-Fi.

ESP-NOW obtient l'adresse IP ESP32 et le canal Wi-Fi

Circuit émetteur ESP32

Les cartes émettrices ESP32 sont connectées à un Capteur de température et d’humidité DHT22. La broche de données est connectée au GPIO 4. Vous pouvez choisir n’importe quel autre GPIO approprié (lisez le guide de brochage ESP32). Suivez le diagramme schématique suivant pour câbler le circuit.

Câblage ESP32 au capteur de température et d'humidité DHT22

Code d’expéditeur ESP32 (ESP-NOW)

Chaque carte émettrice enverra une structure via ESP-NOW qui contient l’ID de la carte (afin que vous puissiez identifier quelle carte a envoyé les lectures), la température, l’humidité et l’ID de lecture. L’ID de lecture est un nombre entier pour savoir combien de messages ont été envoyés.

Carte émetteur-récepteur ESP32 avec ESP-NOW utilisant Arduino IDE

Téléchargez le code suivant sur chacun de vos tableaux d’envoi. N’oubliez pas d’incrémenter le numéro d’id de chaque carte émettrice et d’insérer votre SSID dans la variable WIFI_SSID.

/*
  Rui Santos
  Complete project details at https://Raspberryme.com/esp32-esp-now-wi-fi-web-server/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1

// Digital pin connected to the DHT sensor
#define DHTPIN 4  

// Uncomment the type of sensor in use:
//#define DHTTYPE    DHT11     // DHT 11
#define DHTTYPE    DHT22     // DHT 22 (AM2302)
//#define DHTTYPE    DHT21     // DHT 21 (AM2301)

DHT dht(DHTPIN, DHTTYPE);

//MAC Address of the receiver 
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

//Structure example to send data
//Must match the receiver structure
typedef struct struct_message {
    int id;
    float temp;
    float hum;
    int readingId;
} struct_message;

//Create a struct_message called myData
struct_message myData;

unsigned long previousMillis = 0;   // Stores last time temperature was published
const long interval = 10000;        // Interval at which to publish sensor readings

unsigned int readingId = 0;

// Insert your SSID
constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
      for (uint8_t i=0; i<n; i++) {
          if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
              return WiFi.channel(i);
          }
      }
  }
  return 0;
}

float readDHTTemperature() {
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //float t = dht.readTemperature(true);
  // Check if any reads failed and exit early (to try again).
  if (isnan
    Serial.println("Failed to read from DHT sensor!");
    return 0;
  }
  else {
    Serial.println
    return t;
  }
}

float readDHTHumidity() {
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  if (isnan(h)) {
    Serial.println("Failed to read from DHT sensor!");
    return 0;
  }
  else {
    Serial.println(h);
    return h;
  }
}

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
 
void setup() {
  //Init Serial Monitor
  Serial.begin(115200);

  dht.begin();
 
  // Set device as a Wi-Fi Station and set channel
  WiFi.mode(WIFI_STA);

  int32_t channel = getWiFiChannel(WIFI_SSID);

  WiFi.printDiag(Serial); // Uncomment to verify channel number before
  esp_wifi_set_promiscuous(true);
  esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
  esp_wifi_set_promiscuous(false);
  WiFi.printDiag(Serial); // Uncomment to verify channel change after

  //Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Trasnmitted packet
  esp_now_register_send_cb(OnDataSent);
  
  //Register peer
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.encrypt = false;
  
  //Add peer        
  if (esp_now_add_peer(&peerInfo) != ESP_OK){
    Serial.println("Failed to add peer");
    return;
  }
}
 
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= interval) {
    // Save the last time a new reading was published
    previousMillis = currentMillis;
    //Set values to send
    myData.id = BOARD_ID;
    myData.temp = readDHTTemperature();
    myData.hum = readDHTHumidity();
    myData.readingId = readingId++;
     
    //Send message via ESP-NOW
    esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
    if (result == ESP_OK) {
      Serial.println("Sent with success");
    }
    else {
      Serial.println("Error sending the data");
    }
  }
}

Afficher le code brut

Comment fonctionne le code

Commencez par importer les bibliothèques requises :

#include <esp_now.h>
#include <esp_wifi.h>
#include <WiFi.h>
#include <Adafruit_Sensor.h>
#include <DHT.h>

Définir l’ID du tableau

Définissez l’ID de la carte d’envoi ESP32, par exemple, définissez BOARD_ID 1 pour ESP32 Sender #1, etc…

// Set your Board ID (ESP32 Sender #1 = BOARD_ID 1, ESP32 Sender #2 = BOARD_ID 2, etc)
#define BOARD_ID 1

Capteur DHT

Définissez la broche à laquelle le capteur DHT est connecté. Dans notre exemple, il est connecté au GPIO 4.

#define DHTPIN 4

Sélectionnez le type de capteur DHT que vous utilisez. Nous utilisons le DHT22.

// Uncomment the type of sensor in use:
//#define DHTTYPE    DHT11     // DHT 11
#define DHTTYPE    DHT22     // DHT 22 (AM2302)
//#define DHTTYPE    DHT21     // DHT 21 (AM2301)

Créez un objet DHT sur la broche et le type définis précédemment.

DHT dht(DHTPIN, DHTTYPE);

Adresse MAC du destinataire

Insérez l’adresse MAC du récepteur sur la ligne suivante (par exemple) :

uint8_t broadcastAddress[] = {0x30, 0xAE, 0xA4, 0x15, 0xC7, 0xFC};

Structure de données

Ensuite, créez une structure qui contient les données que nous voulons envoyer. Le struct_message contient l’ID de la carte, la lecture de la température, la lecture de l’humidité et l’ID de lecture.

typedef struct struct_message {
    int id;
    float temp;
    float hum;
    int readingId;
} struct_message;

Créez une nouvelle variable de type struct_message appelée myData qui stocke les valeurs des variables.

struct_message myData;

Intervalle de minuterie

Créez des variables de minuterie auxiliaires pour publier les lectures toutes les 10 secondes. Vous pouvez modifier le temps de retard sur la variable d’intervalle.

unsigned long previousMillis = 0;  // Stores last time temperature was published
const long interval = 10000;       // Interval at which to publish sensor readings

Initialisez la variable readingId – elle garde une trace du nombre de lectures envoyées.

unsigned int readingId = 0;

Changer de canal Wi-Fi

Maintenant, nous allons obtenir le canal Wi-Fi du récepteur. Ceci est utile car cela nous permet d’attribuer automatiquement le même canal Wi-Fi à la carte émettrice.

Pour cela, vous devez insérer votre SSID dans la ligne suivante :

constexpr char WIFI_SSID[] = "REPLACE_WITH_YOUR_SSID";

Ensuite, la fonction getWiFiChannel() recherche votre réseau et obtient son canal.

int32_t getWiFiChannel(const char *ssid) {
  if (int32_t n = WiFi.scanNetworks()) {
    for (uint8_t i=0; i<n; i++) {
      if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
        return WiFi.channel(i);
      }
    }
  }
  return 0;
}

Ce bout de code a été proposé par Stéphane (un de nos lecteurs). Vous pouvez voir son exemple complet ici.

Température de lecture

La fonction readDHTTemperature() lit et renvoie la température du capteur DHT. S’il n’est pas en mesure d’obtenir des relevés de température, il renvoie 0.

float readDHTTemperature() {
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  //float t = dht.readTemperature(true);
  // Check if any reads failed and exit early (to try again).
  if (isnan
    Serial.println("Failed to read from DHT sensor!");
    return 0;
  }
  else {
    Serial.println
    return t;
  }
}

Lecture de l’humidité

La fonction readDHTHumidity() lit et renvoie l’humidité du capteur DHT. S’il n’est pas en mesure d’obtenir des lectures d’humidité, il renvoie 0.

float readDHTHumidity() {
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  if (isnan(h)) {
    Serial.println("Failed to read from DHT sensor!");
    return 0;
  }
  else {
    Serial.println(h);
    return h;
  }
}

Remarque : pour en savoir plus sur l’obtention de la température et de l’humidité à partir des capteurs DHT22 ou DHT11, lisez : ESP32 avec capteur de température et d’humidité DHT11/DHT22 à l’aide de l’IDE Arduino.

Fonction de rappel OnDataSent

La fonction de rappel OnDataSent() sera exécutée lors de l’envoi d’un message. Dans ce cas, cette fonction imprime si le message a été livré avec succès ou non.

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

installation()

Initialisez le moniteur série.

Serial.begin(115200);

Définissez l’ESP32 comme station Wi-Fi.

WiFi.mode(WIFI_STA);

Réglez son canal pour qu’il corresponde au canal Wi-Fi du récepteur :

int32_t channel = getWiFiChannel(WIFI_SSID);

WiFi.printDiag(Serial); // Uncomment to verify channel number before
esp_wifi_set_promiscuous(true);
esp_wifi_set_channel(channel, WIFI_SECOND_CHAN_NONE);
esp_wifi_set_promiscuous(false);
WiFi.printDiag(Serial); // Uncomment to verify channel change after

Initialisez ESP-NOW.

if (esp_now_init() != ESP_OK) {
  Serial.println("Error initializing ESP-NOW");
  return;
}

Après avoir initialisé ESP-NOW avec succès, enregistrez la fonction de rappel qui sera appelée lors de l’envoi d’un message. Dans ce cas, enregistrez-vous pour la fonction OnDataSent() créée précédemment.

esp_now_register_send_cb(OnDataSent);

Ajouter un pair

Pour envoyer des données à une autre carte (le récepteur), vous devez la coupler en tant que pair. Les lignes suivantes enregistrent et ajoutent le récepteur en tant qu’homologue.

// Register peer
esp_now_peer_info_t peerInfo;
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.encrypt = false;

// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK){
  Serial.println("Failed to add peer");
  return;
}

boucle()

Dans la boucle (), vérifiez s’il est temps d’obtenir et d’envoyer de nouvelles lectures.

unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
  // Save the last time a new reading was published
  previousMillis = currentMillis;

Envoyer un message ESP-NOW

Enfin, envoyez la structure du message via ESP-NOW.

// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &myData, sizeof(myData));
if (result == ESP_OK) {
  Serial.println("Sent with success");
}
else {
  Serial.println("Error sending the data");
}

Lecture recommandée : Premiers pas avec ESP-NOW (ESP32 avec Arduino IDE)

Téléchargez le code sur vos tableaux d’envoi. Vous devriez remarquer que les cartes changent leur canal Wi-Fi pour le canal de la carte réceptrice. Dans notre cas, les cartes ont changé leur numéro de canal Wi-Fi en 6.

1680549977 992 ESP32 ESP NOW et tableau de bord du serveur Web Wi Fi

Manifestation

Après avoir téléchargé le code sur toutes les cartes et si tout se passe comme prévu, la carte réceptrice ESP32 devrait commencer à recevoir les lectures des capteurs des autres cartes.

Tableau de bord du capteur de serveur Web ESP32 ESP-NOW Lectures du capteur de démonstration ESP-NOW et Wi-Fi

Ouvrez un navigateur sur votre réseau local et saisissez l’adresse IP ESP32.

ESP32 ESP-NOW Web Server Sensor Dashboard Navigateur Web

Il devrait charger la température, l’humidité et les identifiants de lecture pour chaque carte. Lors de la réception d’un nouveau paquet, votre page Web se met à jour automatiquement sans actualiser la page Web.

Tableau de bord du capteur de serveur Web ESP32 ESP-NOW Mobile Responsive

Conclusion

Dans ce didacticiel, vous avez appris à utiliser ESP-NOW et Wi-Fi pour configurer un serveur Web afin de recevoir des paquets ESP-NOW de plusieurs cartes (configuration plusieurs à un).

De plus, vous avez également utilisé les événements envoyés par le serveur pour mettre automatiquement à jour la page Web chaque fois qu’un nouveau paquet est reçu sans actualiser la page Web.

Nous espérons que ce projet vous plaira. Autres projets/tutoriels que vous pourriez aimer :

En savoir plus sur l’ESP32 avec nos ressources :

Nous tenons à remercier nos lecteurs qui nous ont aidés à améliorer ce tutoriel, à savoir Stéphane Calderoni et Lee Davidson pour leurs précieuses contributions. Merci.

Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

YouTube video

  • AZDelivery 3 x LOLIN32 Lite Board avec ESP-32 Rev1, V1.0.0 WiFi et Module Bluetooth, ESP-32 4MB Flash, Compatible avec Arduino incluant Un E-Book!
    ✅ Obtenez maintenant trois AZDelivery LOLIN32 Lite V1.0.0 à un prix spécial avec remise sur quantité! ✅ Nouveauté absolue et Multi-fonctions: La carte AZDelivery LOLIN32 Lite V1.0.0 a un nouvel ESP-32 Rev1 et 4 Mo de mémoire flash et est équipé de WiFi et Bluetooth.Le module peut être utilisé via micro USB et offre une interface supplémentaire pour la connexion facile d'une batterie au lithium avec un courant de charge maximum de 500mA ✅ Excellente programmation: Le tableau de développement a 26 broches adaptées à la platine électrique. Programmation facile via le script Lua, dans Arduino-iDE ou avec MicroPython pour un prototypage rapide et facile ✅ Puissant débit: Débit en bauds série maximal: 256000bps ✅ Ce produit inclut un E-Book qui fournit des informations utiles sur la façon de commencer votre projet. Il permet une installation rapide et fait gagner du temps sur le processus de configuration. On y trouve une série d'exemples d'applications, des guides d'installation complets et des bibliothèques.