Esp32/espnow et DHT22 pour contrôler l'ambiance dans une serre

Il s’agit d’un petit projet de contrôle de la température et de l’humidité dans une serre chauffée impliquant plusieurs protocoles de communication (esp-now, WifiUdp &Wifi)

Son but est d’estimer la facilité de mise en œuvre du protocole esp now entre deux esp32 wroom32-U dans un cas très pratique avec des distances émetteur-récepteur de l’ordre de 30 mètres impliquant murs de pierre et fenêtres mais en ligne directe.

La chaîne de mesure est composée de deux esp wroom32-U dialoguant en mode esp now. Le premier relié à un capteur DHT22 fournissant température et humidité installé dans la serre, le second, installé dans le domicile relevant les températures et redirigeant les données via le protocole UDP (bibliothèque WifiUdp) vers un rapsberry 3B+ . Celui-ci les stocke dans une base influxdb sur un SSD. Les données sont alors transmises par Wifi et visualisées et traitées dans la plateforme open-source de visualisation Grafana sur tablette, mobile ou ordi.

Par commodité, les wroom-32 sont installés sur une plateforme dédiée offrant plusieurs solutions de connexion. Ce qui évite l’usage d’un réducteur de tension xV –> 3.3V.

Chaque dispositif est placé dans un boitier réalisé par impression 3D.

Le principal problème rencontré est lié à la bibliothèque esp d’Espressif. Sans problème avec une des dernières version (3.3.3) sous ubuntu, message d’erreur sous windows 10 prof. Nécessité de choisir une version plus ancienne (2.0.12).

Voici les codes émetteur et récepteur :

Emetteur :

/*
  La partie électronique est composée de deux esp32 wroom32U.
  L'émetteur mesure la température et l'humidité via un DHT22 relié à la broche 4. 
  Celle-ci, elle-même reliée via une résistance de 10K à la broche 3.3V.
  Le signal est transmis via le protocole ESP_NOW au récepteur.
  Ce dernier renvoie les données à un rapsberry 3B+ via le protocole UDP.
  Les données sont alors stockées sur un SSD dans une base influxdb.
  Les données sont lues soit en terminal soit dans le visualisateur graphique Grafana.

  A noter que les données de température sont relevées toutes les minutes (les températures dans la serre peuvent changer rapidement)
  les données humidité sont lues et stockées toutes les 5 minutes (l'humidité change plus lentement).

  Les délais sont gérés par la commande millis() et non delay() de manière à rendre indépendantes les acquisitions des deux types de données.

  IMPORTANT : la compilation s'effectue avec la carte esp32 WROOM-DA et la bibliothèque 2.012 sur Windows. Sinon après mise à jour de la bibliothèque esp32 :
  Compilation error: invalid conversion from 'void ()(const uint8_t, esp_now_send_status_t)' 
  {aka 'void ()(const unsigned char, esp_now_send_status_t)'} to 'esp_now_send_cb_t' 
  {aka 'void ()(const wifi_tx_info_t, esp_now_send_status_t)'} [-fpermissive]
  Aucun souci avec ubuntu avec version 3.3.3.

*/
#include <esp_now.h>
#include <WiFi.h>
#include <DHT.h>

#define DHTPIN 4
#define DHTTYPE DHT22  // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE);

// Remplacer par l'adresse MCC du receveur
uint8_t broadcastAddress[] = { 0xXX, 0xXX, 0xXX, 0xXX, 0xXX, 0xXX }; // adresse de l'esp32 récepteur 

// Structure pour envoyer les données
// Doit correspondre à la structure du receveur
typedef struct struct_message {
  float temp;
  float hum;
} struct_message;

// Création du struct_message appelé GserreData (données de la grande serre)
struct_message GserreData;

esp_now_peer_info_t peerInfo;

// callback quand les données sont envoyées
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 ? "Envoi reussi !" : "Echec de l'envoi !");
}

void setup() {
  Serial.begin(115200);
  // Adapte le dispo en mode station
  WiFi.mode(WIFI_STA);
  dht.begin();

  // Initialisation de  ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Erreur d'initialisation de ESP-NOW");
    return;
  }

  // Après initialisation, on enregistre pour envoyer  le callback
  esp_now_register_send_cb(esp_now_send_cb_t(OnDataSent));

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

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

void loop() {

  GserreData.temp = dht.readTemperature();
  GserreData.hum = dht.readHumidity();

  Serial.println("Envoi des donnees de la serre: ");
  Serial.print(GserreData.temp);
  Serial.println("°C");
  Serial.print("Humidity:");
  Serial.print(GserreData.hum);
  Serial.println("%");

  delay(2000);
  // Envoi des messages via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&GserreData, sizeof(GserreData));

  if (result == ESP_OK) {
    Serial.println("Envoi avec succes");
  } else {
    Serial.println("Erreur d'envoi des donnees");
  }
  delay(2000);
}

Récepteur :

/*
  Programme Lacuzon, destiné à mesurer la température et l'humidité dans une serre chauffée.
  Inspiré des sketches de Rui Santos & Sara Santos - Random Nerd Tutorials. Thanks !
  
  La partie électronique est composée de deux esp32 wroom32U.
  L'émetteur mesure la température et l'humidité via un DHT22 relié à la broche 4. 
  Celle-ci, elle-même reliée via une résistance de 10K à la broche 3.3V.
  Le signal est transmis via le protocole ESP_NOW au récepteur.
  Ce dernier renvoie les données à un rapsberry 3B+ via le protocole UDP.
  Les données sont alors stockées sur un SSD dans une base influxdb.
  Les données sont lues soit en terminal soit dans le visualisateur graphique Grafana.

  A noter que les données de température sont relevées toutes les minutes (les températures dans la serre peuvent changer rapidement)
  les données humidité sont lues et stockées toutes les 5 minutes (l'humidité change plus lentement).

  Les délais sont gérés par la commande millis() et non delay() de manière à rendre indépendantes les acquisitions des deux types de données.

  IMPORTANT : la compilation s'effectue avec la carte esp32 WROOM-DA et la bibliothèque 2.012 sur Windows. Sinon après mise à jour de la bibliothèque esp32 :
  Compilation error: invalid conversion from 'void ()(const uint8_t, esp_now_send_status_t)' 
  {aka 'void ()(const unsigned char, esp_now_send_status_t)'} to 'esp_now_send_cb_t' 
  {aka 'void ()(const wifi_tx_info_t, esp_now_send_status_t)'} [-fpermissive]
  Aucun souci avec ubuntu avec version 3.3.3.
  
*/

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

//************Parametrage du WiFi, le mot de passe est la clé WIFI**********
const char* ssid = "XXX";  // Le nom de la box
const char* pass = "XXXX";  // Le mot de passe

// ***********Adresse IP de l'hôte InfluxDB*****************

byte host2[] = { XXX, XXX, XXX, XXX1 };  // Raspberry 3B+

int localport;  // port de l'UDP

WiFiUDP udp;

/*structure pour recevoir les données
(la struture est une collection de données qui inclut des int,
des float, des Char, des bool...)
*/
// Doit s'accorder avec la structure de l'émetteur.
typedef struct struct_message {
  float temp;
  float hum;
} struct_message;
float tempdata;  //Données de température
float humdata;   //Données d'humidité

unsigned long tempsprecedentT = millis();  //Pour la température
unsigned long tempspresentT = millis();    //Pour la température
unsigned long tempsprecedentH = millis();  //Pour l'humidité
unsigned long tempspresentH = millis();    //Pour l'humidité
const unsigned long delaiT = 60000;        //Lance l'envoi des données températures toutes les minutes
const unsigned long delaiH = 300000;       //Lance l'envoi des données humidité toutes les 5 minutes


// Creation d'un struct_message appelé ici GserreData (données de la grande serre)
struct_message GserreData;

// Fonction callback (info de retour)
void OnDataRecv(const uint8_t* mac, const uint8_t* incomingData, int len) {
  memcpy(&GserreData, incomingData, sizeof(GserreData));

  tempdata = GserreData.temp;
  humdata = GserreData.hum;

  Serial.print("Température: ");
  Serial.print(GserreData.temp);
  Serial.println("°C");
  Serial.print("Humidité: ");
  Serial.print(GserreData.hum);
  Serial.println("%");
}

void setup() {
  Serial.begin(57600);

  WiFi.begin(ssid, pass);
  Serial.println();
  Serial.println("Attente WiFi... ");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.println(".");
    delay(100);
  }
  Serial.println("Addresse ip: ");
  Serial.println(WiFi.localIP());
  Serial.println();
  delay(100);

  //Le esp32 est défini en station Wifi
  WiFi.mode(WIFI_STA);

  // Initialisation de ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Erreur d'initialiation de ESP-NOW");
    return;
  }

  // Dès que ESPNow est initialisé avec succès, on l'enregistre pour recevoir le callback
  esp_now_register_recv_cb(esp_now_recv_cb_t(OnDataRecv));
}


void loop() {
  tempspresentT = millis();
  if (tempspresentT - tempsprecedentT > delaiT) {
    sendUdp_temp();
    tempsprecedentT = tempspresentT;
  }

  tempspresentH = millis();
  if (tempspresentH - tempsprecedentH > delaiH) {
    sendUdp_hum();
    tempsprecedentH = tempspresentH;
  }
}

void sendUdp_temp() {
  udp.begin(localport);
  String line, GSwroom;  // défini le nom des séries de données enregistrées dans influxdb
  line = String("température value=" + String(tempdata));
  // exemple en terminal :  influx --> use GSwroom --> select * from "température"; les "" sont nécessaires si on utilise la francisation.
  Serial.println(line);
  // Envoi du paquet de données UDP
  Serial.print("localport :");
  Serial.println(8191);  // Choix à vérifier concernant sa disponibilité (site https://www.frameip.com/liste-des-ports-tcp-udp/)
  udp.beginPacket(host2, 8191);
  udp.print(line);
  udp.endPacket();
}

void sendUdp_hum() {
  udp.begin(localport);
  String line, GSwroom; // définit le nom des séries de données enregistrées dans influxdb
  line = String("humidité value=" + String(humdata));  
  // exemple en terminal :  influx --> use GSwroom --> select * from "humidité"; les "" sont nécessaires si on utilise la francisation.
  Serial.println(line);
  // Envoi du paquet de données UDP
  Serial.println("Envoi des paquets UDP...");
  Serial.print("localport :");
  Serial.println(8191); // Choix à vérifier concernant sa disponibilité (site https://www.frameip.com/liste-des-ports-tcp-udp/)
  udp.beginPacket(host2, 8191);
  udp.print(line);
  udp.endPacket();
}

Tourne sans problème et sans valeurs aberrantes depuis quelques jours.

Pour terminer, voici la réalisation par impression 3D . Les fichiers stl sont disponibles sur cults à l’adresse :

1 Like

Bravo! Le projet est utile et le rendu est vraiment propre! :clap:

Merci pour le commentaire.

Le forum arduino m’a beaucoup appris, beaucoup aidé. Je ne fais que rendre un peu ce qui m’a été donné.

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