Dans ce guide, nous allons créer un enregistreur de données ESP32 qui héberge également un serveur Web afin que vous puissiez accéder et télécharger les données à distance. L’ESP32 enregistrera les données dans un fichier hébergé sur une carte microSD. Vous pouvez accéder au serveur Web avec votre ordinateur ou smartphone et télécharger le fichier contenant les données à distance sans avoir besoin de retirer la carte microSD de l’ESP32.

Table des matières:
Aperçu du projet
Voici un bref aperçu des fonctionnalités de ce projet.

- L’ESP32 enregistrera les données et l’horodatage correspondant dans un fichier sur une carte microSD.
- Nous enregistrerons les données d’un capteur BME280, mais vous pouvez utiliser n’importe quel autre ou plusieurs autres capteurs.
- Nous enregistrerons l’horodatage à l’heure de l’époque. Ensuite, lors du traitement des données, vous pouvez les convertir à votre heure locale.
- L’ESP32 hébergera également un serveur Web auquel vous pourrez accéder sur votre ordinateur ou votre smartphone tant qu’ils sont sur le même réseau.
- Le serveur Web vous permet de visualiser les données enregistrées sur le fichier, de télécharger le fichier de données sur votre ordinateur ou de supprimer le fichier de la carte microSD.
- Le fichier HTML permettant de créer le serveur Web ESP32 sera également hébergé sur la carte microSD.
Dans cet exemple, nous obtiendrons l’heure d’Internet (serveur NTP), l’ESP32 doit donc être connecté à un routeur. Si la carte n’a pas accès à Internet, vous pouvez la définir comme point d’accès et obtenir l’heure à partir d’un module RTC (par exemple DS1307 ou DS3231).
Conditions préalables
Avant de continuer, assurez-vous de vérifier les conditions préalables suivantes.
EDI Arduino
Nous allons programmer l’ESP32 à l’aide de l’IDE Arduino. Assurez-vous donc que les cartes ESP32 sont installées. Vous pouvez utiliser Arduino IDE 2 ou la version héritée.
Bibliothèques
Vous devez également installer les bibliothèques suivantes.
Vous pouvez installer les deux premières bibliothèques à l’aide du gestionnaire de bibliothèques Arduino. Accédez à Sketch > Inclure la bibliothèque > Gérer les bibliothèques et recherchez le nom de la bibliothèque.
Les bibliothèques ESPAsyncWebServer et AsynTCP ne peuvent pas être installées via Arduino Library Manager. Vous devez télécharger le fichier .zip de la bibliothèque, puis, dans votre IDE Arduino, accédez à Sketch > Inclure une bibliothèque > Ajouter une bibliothèque .zip et sélectionnez les bibliothèques que vous venez de télécharger.
Formatage de la carte MicroSD
Avant de poursuivre le didacticiel, assurez-vous de formater votre carte microSD en FAT32. Suivez les instructions suivantes pour formater votre carte microSD ou utilisez un outil logiciel tel que SD Card Formatter (compatible avec Windows et Mac OS).
1. Insérez la carte microSD dans votre ordinateur. Accédez à Poste de travail et cliquez avec le bouton droit sur la carte SD. Sélectionnez Format comme indiqué dans la figure ci-dessous.

2. Une nouvelle fenêtre apparaît. Sélectionnez FAT32, appuyez sur Démarrer pour initialiser le processus de formatage et suivez les instructions à l’écran.

Pièces requises

Pour suivre ce tutoriel, vous avez besoin des pièces suivantes :
Vous pouvez utiliser les liens précédents ou vous rendre directement sur MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

Schéma de circuit
Pour cet exemple, connectez le module de carte microSD et le capteur BME280 à l’ESP32. Suivez le diagramme schématique suivant ou les tableaux ci-dessous pour câbler le circuit.

Vous pouvez également consulter les tableaux suivants :
| BME280 | ESP32 |
| NIV | 3V3 |
| GND | GND |
| SCL | GPIO22 |
| SDA | GPIO21 |
| module de carte microSD | ESP32 |
| 3V3 | 3,3 V |
| CS | GPIO5 |
| MOSI | GPIO23 |
| CLK | GPIO18 |
| MISO | GPIO19 |
| GND | GND |
Vous ne connaissez pas le capteur BME280 ? Lisez le guide suivant
Vous n’êtes pas familier avec l’utilisation d’une carte microSD avec l’ESP32 ? Consultez les didacticiels suivants :
Fichier HTML
Le fichier HTML suivant créera la page du serveur Web avec laquelle nous pouvons interagir pour gérer les données sur l’ESP32.
ESP32 Datalogger
Afficher le code brut
La page Web comporte trois boutons :

- View Data : affichera le contenu du fichier de données – fait une requête sur le chemin /view-data ;
- Télécharger les données : télécharge le fichier de données sur votre appareil – fait une demande sur le chemin /download ;
- Supprimer les données : supprime le fichier de données de la carte microSD – fait une requête sur le chemin /delete.
Copiez le fichier HTML sur la carte microSD
- Créez un fichier appelé index.html et copiez le texte HTML que nous vous avons montré précédemment.
- Copiez ce fichier sur la carte microSD.
- Insérez la carte microSD dans le module de carte microSD qui doit être connecté à l’ESP32.
Code de l’enregistreur de données et du serveur Web
Le code suivant crée un enregistreur de données ESP32 qui enregistrera les données du capteur BME280 et l’horodatage correspondant dans un fichier appelé data.txt sur la carte microSD. En même temps, il héberge également un serveur Web et affiche une page Web (construite à partir du fichier HTML que vous avez copié sur la carte microSD) à laquelle vous pouvez accéder pour gérer les données.
/*********
Rui Santos & Sara Santos - Raspberryme.com
Complete project details at https://Raspberryme.com/esp32-datalogger-download-data-file/
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
#include
#include
#include
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include
#include
#include "time.h"
#include
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// NTP server to request epoch time
const char* ntpServer = "pool.ntp.org";
// Variable to save current epoch time
unsigned long epochTime;
// Variables to hold sensor readings
float temp;
float hum;
float pres;
String dataMessage;
// File name where readings will be saved
const char* dataPath = "/data.txt";
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)
Adafruit_BME280 bme;
// Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
// Init microSD card
void initSDCard(){
if(!SD.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
}
// Write to the SD card
void writeFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file) {
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
// Append data to the SD card
void appendFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file) {
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
// Delete file
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\r\n", path);
if(fs.remove(path)){
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
}
// Function that gets current epoch time
unsigned long getTime() {
time_t now;
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
//Serial.println("Failed to obtain time");
return(0);
}
time(&now);
return now;
}
// Function that initializes wi-fi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initWiFi();
initBME();
initSDCard();
configTime(0, 0, ntpServer);
// If the data.txt file doesn't exist
// Create a file on the SD card and write the data labels
File file = SD.open("/data.txt");
if(!file) {
Serial.println("File doesn't exist");
Serial.println("Creating file...");
writeFile(SD, "/data.txt", "Epoch Time, Temperature, Humidity, Pressure \r\n");
}
else {
Serial.println("File already exists");
}
file.close();
// Handle the root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/index.html", "text/html");
});
// Handle the download button
server.on("/download", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/data.txt", String(), true);
});
// Handle the View Data button
server.on("/view-data", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/data.txt", "text/plain", false);
});
// Handle the delete button
server.on("/delete", HTTP_GET, [](AsyncWebServerRequest *request){
deleteFile(SD, dataPath);
request->send(200, "text/plain", "data.txt was deleted.");
});
// Uncomment the following line if you need to serve more static files like CSS and javascript or favicon
//server.serveStatic("/", SD, "/");
server.begin();
}
void loop() {
if ((millis() - lastTime) > timerDelay) {
//Get epoch time
epochTime = getTime();
//Get sensor readings
temp = bme.readTemperature();
//temp = 1.8*bme.readTemperature() + 32;
hum = bme.readHumidity();
pres = bme.readPressure()/100.0F;
//Concatenate all info separated by commas
dataMessage = String(epochTime) + "," + String(temp) + "," + String(hum) + "," + String(pres)+ "\r\n";
Serial.print("Saving data: ");
Serial.println(dataMessage);
//Append the data to file
appendFile(SD, "/data.txt", dataMessage.c_str());
lastTime = millis();
}
}
Afficher le code brut
Avant de télécharger le code sur le tableau, vous devez insérer vos informations d’identification réseau sur les variables suivantes.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Comment fonctionne le code
Continuez à lire pour savoir comment fonctionne le code ou passez à la section Démonstration.
Y compris les bibliothèques
Commencez par inclure les bibliothèques requises. Nous incluons les bibliothèques pour se connecter au Wi-Fi, créer le serveur Web, gérer les fichiers, communiquer avec la carte microSD, communiquer avec le capteur BME280 et obtenir l’heure d’un serveur NTP.
#include
#include
#include
#include
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#include
#include
#include "time.h"
#include
Informations d’identification réseau
Insérez vos informations d’identification réseau sur les variables suivantes afin que l’ESP32 puisse se connecter à votre réseau local.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Initialiser les variables
Ensuite, nous initialisons certaines variables que nous utiliserons tout au long du code.
le ntpServer enregistre l’URL du serveur NTP que nous utiliserons pour obtenir l’heure.
const char* ntpServer = "pool.ntp.org";
Nous enregistrerons l’horodatage en heure d’époque sur la variable epochTime.
// Variable to save current epoch time
unsigned long epochTime;
Les variables suivantes contiendront les lectures du capteur BME280.
float temp;
float hum;
float pres;
La variable dataMessage contiendra la concaténation de toutes les lectures séparées par des virgules à insérer dans le fichier de données.
String dataMessage;
Les données seront enregistrées dans un fichier appelé data.txt à la root de la carte microSD. La variable dataPath enregistre le nom et le chemin de ce fichier.
const char* dataPath = "/data.txt";
Nous obtiendrons de nouvelles données toutes les 30 secondes (30 000 millisecondes). Vous pouvez modifier la période d’échantillonnage sur la variable timerDelay.
// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 30000;
Créez une instance AsyncWebServer sur le port 80.
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
Et créez un objet Adafruit_BME280 appelé bme. Il utilisera les broches I2C par défaut de l’ESP32 (GPIO 21 (SDA) et GPIO 22 (SCL))
// BME280 connect to ESP32 I2C (GPIO 21 = SDA, GPIO 22 = SCL)
Adafruit_BME280 bme;
Initialiser le capteur BME280
La fonction initBME() initialisera le capteur BME280. Nous définissons l’adresse I2C sur 0x76, qui est généralement l’adresse de ces capteurs. Cependant, cela pourrait être différent. Vous pouvez vérifier cela à l’aide d’un scanner I2C.
// Init BME280
void initBME(){
if (!bme.begin(0x76)) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
while (1);
}
}
Initialisez la carte MicroSD
La fonction suivante initialisera la communication avec la carte microSD sur les broches SPI par défaut de l’ESP32. Il imprimera également des informations sur le type et la taille de la carte microSD.
// Init microSD card
void initSDCard(){
if(!SD.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
}
Écrire des données dans un fichier
La fonction suivante nous permet d’écrire des données dans un fichier. Pour utiliser cette fonction vous devez passer en arguments le type de système de fichiers, le chemin du fichier et le message à écrire.
// Write to the SD card
void writeFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file) {
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)) {
Serial.println("File written");
} else {
Serial.println("Write failed");
}
file.close();
}
Ajouter des données à un fichier
La fonction writeFile() écrase toutes les données existantes sur un fichier. Pour ajouter des données à un fichier, nous avons la fonction appendFile(). Cela fonctionne comme la fonction précédente, mais ajoutera des données au lieu de les écraser.
// Append data to the SD card
void appendFile(fs::FS &fs, const char * path, const char * message) {
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file) {
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)) {
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
file.close();
}
Supprimer un fichier
La fonction deleteFile() supprime un fichier du système de fichiers et du chemin spécifiés.
// Delete file
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\r\n", path);
if(fs.remove(path)){
Serial.println("- file deleted");
} else {
Serial.println("- delete failed");
}
}
Obtenir du temps
La fonction suivante obtient et renvoie l’heure actuelle.
// Function that gets current epoch time
unsigned long getTime() {
time_t now;
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
//Serial.println("Failed to obtain time");
return(0);
}
time(&now);
return now;
}
Initialiser le Wi-Fi
La fonction initWiFi() connectera votre ESP32 à votre réseau local en utilisant le SSID et le mot de passe que vous avez insérés au début du code.
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
installation()
Dans setup(), initialisez le Serial Monitor, connectez l’ESP32 au Wi-Fi, initialisez le capteur BME280 et la carte microSD et configurez le serveur de temps.
Serial.begin(115200);
initWiFi();
initBME();
initSDCard();
configTime(0, 0, ntpServer);
Ensuite, nous créons un nouveau fichier sur la carte microSD appelé data.txt où nous enregistrerons les données (si elles n’existent pas encore) et nous écrirons les en-têtes de données dans le fichier.
// If the data.txt file doesn't exist
// Create a file on the SD card and write the data labels
File file = SD.open("/data.txt");
if(!file) {
Serial.println("File doesn't exist");
Serial.println("Creating file...");
writeFile(SD, "/data.txt", "Epoch Time, Temperature, Humidity, Pressure \r\n");
}
else {
Serial.println("File already exists");
}
file.close();
Gérer les demandes
Enfin, nous devons gérer ce qui se passe lorsque nous cliquons sur les boutons de la page Web. Comme nous l’avons vu précédemment :
- Afficher les données : affichera le contenu du fichier de données – fait une requête sur le chemin /view-data ;
- Télécharger les données : télécharge le fichier de données sur votre appareil – fait une demande sur le chemin /download ;
- Supprimer les données : supprime le fichier de données de la carte microSD – fait une requête sur le chemin /delete.
La ligne suivante servira le fichier index.html enregistré sur la carte microSD pour afficher la page Web.
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/index.html", "text/html");
});
Vous aimerez peut-être aussi lire : Hébergement de fichiers sur le serveur Web ESP32 à partir d’une carte MicroSD
Lorsque nous cliquons sur le bouton Télécharger, l’ESP32 reçoit une requête sur l’URL /download, lorsque cela se produit, nous traitons la requête comme suit.
// Handle the download button
server.on("/download", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, "/data.txt", String(), true);
});
Pour télécharger le fichier, nous devons transmettre les arguments suivants à la fonction send() : filesystem, filepath, String() et une variable booléenne qui indique true = download). Pour plus d’informations, vous pouvez consulter ce cas d’utilisation dans la documentation de la bibliothèque ici.
Lorsque l’ESP32 reçoit une requête sur le chemin /view-data, nous répondrons avec le contenu du fichier data.txt comme suit :
// Handle the View Data button
server.on("/view-data", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, “/data.txt”, “text/plain”, false);
});
Enfin, lorsque vous cliquez sur le bouton Supprimer, nous appellerons la fonction deleteFile() pour détecter le fichier de la carte microSD.
server.on("/delete", HTTP_GET, [](AsyncWebServerRequest *request){
deleteFile(SD, dataPath);
request->send(200, "text/plain", "data.txt was deleted.");
});
A la fin de setup(), nous devons initialiser le serveur avec server.begin().
server.begin();
boucle()
Dans la boucle(), nous obtenons l’heure et les nouvelles données du capteur toutes les 30 secondes et les ajoutons au fichier data.txt sur la carte microSD.
void loop() {
if ((millis() - lastTime) > timerDelay) {
//Get epoch time
epochTime = getTime();
//Get sensor readings
temp = bme.readTemperature();
//temp = 1.8*bme.readTemperature() + 32;
hum = bme.readHumidity();
pres = bme.readPressure()/100.0F;
//Concatenate all info separated by commas
dataMessage = String(epochTime) + "," + String(temp) + "," + String(hum) + "," + String(pres)+ "\r\n";
Serial.print("Saving data: ");
Serial.println(dataMessage);
//Append the data to file
appendFile(SD, "/data.txt", dataMessage.c_str());
lastTime = millis();
}
}
Démonstration
Après avoir inséré vos informations d’identification réseau dans le code, vous pouvez le télécharger sur votre carte ESP32.
Après le téléchargement, ouvrez le moniteur série à un débit en bauds de 115 200 et appuyez sur le bouton RST intégré de l’ESP32. Il se connectera au Wi-Fi et imprimera son adresse IP.
Après cela, il créera le fichier sur la carte microSD et devrait commencer à ajouter des données au fichier toutes les 30 secondes.

Laissez le code s’exécuter pendant un moment jusqu’à ce que l’ESP32 collecte des données. Ensuite, vous pouvez gérer les données sur la carte microSD à laquelle l’ESP32 est connecté en accédant au serveur Web. Ouvrez un navigateur sur votre réseau local et saisissez l’adresse IP ESP32.
Vous devriez obtenir la page suivante.

Vous pouvez cliquer sur le bouton Afficher les données pour voir les données brutes sur le navigateur Web.

Vous pouvez également télécharger le fichier sur votre ordinateur sans avoir besoin de retirer la carte microSD de l’adaptateur et de l’insérer dans votre ordinateur. Il vous suffit de cliquer sur le bouton Télécharger les données.

Ensuite, vous pouvez ouvrir le fichier sur votre ordinateur et traiter les données comme vous le souhaitez.

Enfin, vous pouvez également supprimer le fichier de la carte microSD en cliquant sur le bouton Supprimer les données.


Et c’est essentiellement ainsi que fonctionne le projet. N’hésitez pas à adapter ce que vous avez appris ici à vos propres projets.
Conclusion
Dans ce didacticiel, vous avez appris à télécharger un fichier stocké sur une carte microSD sur votre ordinateur à l’aide d’un serveur Web sur l’ESP32. Ceci est très utile car vous n’avez pas besoin d’un accès physique à la carte pour récupérer les fichiers sur votre ordinateur.
Nous espérons que vous avez trouvé ce tutoriel utile. Voici une liste d’articles connexes qui pourraient vous plaire :
Si vous souhaitez en savoir plus sur l’ESP32, consultez nos ressources :
Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

-
2 pièces 38 Broches USB C ESP32 NodeMCU WiFi Bluetooth Module ESP32 WROOM 32 Carte de développement avec CP2102 Compatible avec l'interface Arduino Type C
-
DUBEUYEW ESP32-DevKitC Core Board Type C ESP32 Development Board ESP32-WROOM-32U pour Arduino avec Antenne et Câble(2pcs)
