Découvrez comment créer un serveur Web ESP32 qui affiche des graphiques avec des données chargées à partir d’un fichier .csv enregistré sur une carte microSD.
Dans ce projet, nous allons construire un enregistreur de données ESP32 utilisant un capteur BME280. Il prend des mesures de température, d’humidité et de pression et enregistre ces valeurs avec un horodatage dans un fichier .cvs sur une carte microSD. L’ESP32 héberge également un serveur Web avec des graphiques en temps réel qui charge les données stockées dans le fichier .csv. La carte ESP32 sera programmée à l’aide de l’IDE Arduino.

Vous aimerez peut-être lire : Construire un serveur Web ESP32 : le guide complet pour les débutants (Arduino IDE).
Aperçu du projet
L’image suivante montre la page Web que vous allez créer pour ce projet.

Voici les principales caractéristiques de ce projet :
- L’ESP32 est équipé d’un capteur BME280 qui prend des mesures toutes les 60 secondes et les stocke sur une carte microSD dans un fichier .csv ;
- L’ESP32 héberge une page Web qui affiche 3 graphiques en temps réel : température, humidité et pression ;
- Sur la page Web, vous pouvez télécharger ou supprimer le fichier .csv sur votre appareil ;
- Les graphiques peuvent être zoomés et mettre en évidence chaque valeur ;
- La page Web est entièrement réactive pour le Web, elle s’exécute donc sur n’importe quelle taille d’écran.
Pour plus de simplicité, nous stockerons le HTML et le CSS de la page Web dans une variable du croquis Arduino, mais vous pouvez utiliser le système de fichiers LittleFS si vous souhaitez des fichiers séparés.
Conditions préalables
Avant de poursuivre ce tutoriel, vous devez avoir installé le module complémentaire ESP32 dans votre IDE Arduino :
La lecture de ces autres guides pourrait également vous être utile :
Pièces requises
Pour 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 !

Diagramme schématique – ESP32 avec BME280 et carte MicroSD
Nous allons utiliser la communication I2C avec le module capteur BME280 et SPI pour la carte microSD.
Câblez le capteur et le module de carte microSD à l’aide du schéma suivant (ou utilisez les tableaux ci-dessous pour vérifier l’affectation des broches).

Connectez le capteur BME280 aux broches I2C par défaut de l’ESP32 :
| BME280 | ESP32 |
| SCK (broche SCL) | GPIO22 |
| SDI (broche SDA) | GPIO21 |
Le module de carte microSD communique à l’aide du protocole de communication SPI. Vous pouvez le connecter à l’ESP32 en utilisant les broches SPI par défaut.
| Module de carte MicroSD | ESP32 |
| 3V3 | 3,3 V |
| CS | GPIO5 |
| MOSI | GPIO23 |
| CLK | GPIO18 |
| MISO | GPIO19 |
| GND | GND |
Le circuit final devrait ressembler à ceci :

Avant de poursuivre le didacticiel, assurez-vous de formater votre carte microSD en FAT32 (en savoir plus sur notre guide de la carte microSD). Ensuite, insérez la carte microSD dans le module.
Installer les bibliothèques requises dans l’IDE Arduino
Pour ce projet, vous devez installer les bibliothèques suivantes :
Vous pouvez installer ces bibliothèques dans Arduino Library Manager. Ouvrez le gestionnaire de bibliothèque en cliquant sur l’icône Bibliothèque dans la barre latérale gauche.
Recherchez ESPAsyncWebServer et installez ESPAsyncWebServer par ESP32Async.

Recherchez AsyncTCP et installez AsyncTCP par ESP32Async.

Recherchez Adafruit BME280 et installez la bibliothèque :

Enfin, recherchez Adafruit Unified Sensor et installez cette bibliothèque.

Arduino Sketch – Graphiques du serveur Web ESP32 avec données historiques (charger le fichier .csv)
Le code suivant crée un serveur Web qui dessert une page Web qui charge les données du capteur stockées dans le fichier .csv de la carte microSD dans des graphiques en temps réel.
/*
Rui Santos & Sara Santos - Raspberryme.com
Complete project details at https://Raspberryme.com/esp32-web-server-charts-historical-data/
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
#include
#include
#include
// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// BME280 GPIOs
#define SDA_PIN 21
#define SCL_PIN 22
// MicroSD Card Module GPIOs
#define SD_CS 5
#define SD_MOSI 23
#define SD_MISO 19
#define SD_SCK 18
// NTP server
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600; // Change to your timezone
const int daylightOffset_sec = 0;
// Timer to take new readings
unsigned long previousMillis = 0;
const long interval = 60000; // 60 seconds
// CSV filename
const char* dataFile = "/bme280_log.csv";
// AsyncWebServer Web Server
AsyncWebServer server(80);
// BME280
Adafruit_BME280 bme;
// Get Time
String getTimeStr() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return "00:00:00";
char buf[9]; sprintf(buf, "%02d:%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec);
return String(buf);
}
// Get Date
String getDateStr() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) return "1970-01-01";
char buf[11]; sprintf(buf, "%04d-%02d-%02d", timeinfo.tm_year+1900, timeinfo.tm_mon+1, timeinfo.tm_mday);
return String(buf);
}
// Initialize MicroSD Card and create the .csv file
void initSD() {
SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS)) { Serial.println("SD Card Failed"); return; }
if (!SD.exists(dataFile)) {
File f = SD.open(dataFile, FILE_WRITE);
if (f) { f.println("temp_c,temp_f,humidity,pressure,time,day"); f.close(); }
}
}
// Log BME280 data on the MicroSD Card
void logData() {
float tempC = bme.readTemperature();
float tempF = tempC * 9.0 / 5.0 + 32.0;
float hum = bme.readHumidity();
float press = bme.readPressure() / 100.0F;
File file = SD.open(dataFile, FILE_APPEND);
if (file) {
file.printf("%.2f,%.2f,%.2f,%.2f,%s,%s\n",
tempC, tempF, hum, press, getTimeStr().c_str(), getDateStr().c_str());
file.close();
}
}
void setup() {
Serial.begin(115200);
// Initialize BME280 Sensor
Wire.begin(SDA_PIN, SCL_PIN);
if (!bme.begin(0x76)) {
Serial.println("BME280 not found!");
while(1);
}
// Start the Wi-Fi connection
WiFi.begin(ssid, password);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi Connected!");
// Print the ESP32 IP Address
Serial.print("Access ESP32 IP Address: http://");
Serial.println(WiFi.localIP());
// Configure NTP time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
delay(2000);
// Initialize MicroSD Card
initSD();
// Root URL handler for the mains HTML web page
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
String html = R"rawliteral(
ESP32 Charts with Data Logger
New readings are added to your chart automatically, you don't need to refresh the web page.
Refresh Charts
Download CSV
Delete All Data
Reset All Zoom
Humidity
Pressure
Latest Reading
)rawliteral";
request->send(200, "text/html; charset=UTF-8", html);
});
// Download .csv file stored on MicroSD Card
server.on("/download", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(SD, dataFile, "text/csv", true);
});
// Delete .csv file stored on MicroSD Card
server.on("/delete", HTTP_POST, [](AsyncWebServerRequest *request){
if (SD.exists(dataFile)) SD.remove(dataFile);
File f = SD.open(dataFile, FILE_WRITE);
if (f) { f.println("temp_c,temp_f,humidity,pressure,time,day"); f.close(); }
request->send(200);
});
server.begin();
Serial.println("ESP32 Web Server: Charts with Historical Data Ready!");
}
void loop() {
// Timer
if (millis() - previousMillis >= interval) {
previousMillis = millis();
logData();
}
delay(10);
}
Afficher le code brut
Avec les bibliothèques mentionnées précédemment installées dans votre IDE Arduino, il vous suffit d'insérer vos informations d'identification réseau dans les lignes suivantes du code, et cela fonctionnera immédiatement.
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_SSID";
Comment fonctionne le code
Continuez à lire pour découvrir comment fonctionne le code ou passez à la section Démonstration.
Y compris les bibliothèques
Tout d'abord, incluez les bibliothèques requises pour vous connecter au Wi-Fi, créer le serveur Web, lire le capteur BME280 et communiquer avec la carte SD.
#include
#include
#include
#include
#include
#include
#include
#include
Informations d'identification réseau
Insérez vos informations d'identification réseau dans les variables suivantes afin que l'ESP32 se connecte à votre réseau.
// REPLACE WITH YOUR NETWORK CREDENTIALS
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_SSID";
GPIO
Définissez les GPIO qui seront utilisés pour la communication I2C avec le capteur BME280 et la communication SPI avec le module de carte microSD.
// BME280 GPIOs
#define SDA_PIN 21
#define SCL_PIN 22
// MicroSD Card Module GPIOs
#define SD_CS 5
#define SD_MOSI 23
#define SD_MISO 19
#define SD_SCK 18
Serveur NTP
Nous demanderons l'heure à pool.ntp.org, qui est un cluster de serveurs de temps que tout le monde peut utiliser pour demander l'heure (lisez notre guide Client-Serveur NTP ESP32 : Obtenir la date et l'heure).
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 3600; // Change to your timezone
const int daylightOffset_sec = 0;
Minuteur
Cette minuterie prendra de nouvelles lectures toutes les 60 secondes ; vous pouvez augmenter ce nombre pour une application réelle. À des fins de test et pour collecter plus de valeurs dans un court laps de temps, cette durée est définie sur 60 secondes.
unsigned long previousMillis = 0;
const long interval = 60000; // 60 seconds
Fichier CSV
Le fichier stocké sur la carte microSD porte le nom suivant : bme280_log.csv.
const char* dataFile = "/bme280_log.csv";
Création d'un objet serveur
Créez un objet AsyncWebServer appelé serveur sur le port 80.
AsyncWebServer server(80);
Création d'un objet BME280
Le BME280 lira les valeurs à l'aide du protocole de communication I2C. Il vous suffit de créer un objet Adafruit_BME280 appelé bme comme suit.
Adafruit_BME280 bme;
installation()
Dans le setup(), nous commençons par initialiser le moniteur série et initialiser le capteur BME280.
Serial.begin(115200);
// Initialize BME280 Sensor
Wire.begin(SDA_PIN, SCL_PIN);
if (!bme.begin(0x76)) {
Serial.println("BME280 not found!");
while(1);
}
Démarrez la connexion Wi-Fi et imprimez l'adresse IP ESP32 dans le moniteur série. Vous en aurez besoin plus tard pour accéder au serveur Web.
WiFi.begin(ssid, password);
Serial.print("Connecting to Wi-Fi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWi-Fi Connected!");
// Print the ESP32 IP Address
Serial.print("Access ESP32 IP Address: http://");
Serial.println(WiFi.localIP());
Configurez l'heure avec les paramètres que vous avez définis précédemment :
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Appelez la fonction pour initialiser la carte microSD.
initSD();
Voici la fonction initSD() :
void initSD() {
SPI.begin(SD_SCK, SD_MISO, SD_MOSI, SD_CS);
if (!SD.begin(SD_CS)) { Serial.println("SD Card Failed"); return; }
if (!SD.exists(dataFile)) {
File f = SD.open(dataFile, FILE_WRITE);
if (f) { f.println("temp_c,temp_f,humidity,pressure,time,day"); f.close(); }
}
}
URL root /
Ensuite, gérez le serveur Web. Lorsque vous recevez une requête sur l'URL root (/) (cela se produit lorsque vous accédez à l'adresse IP ESP), envoyez le texte HTML stocké dans la variable html String pour afficher la page Web :
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
(...)
request->send(200, "text/html; charset=UTF-8", html);
});
La variable html contient le texte avec le HTML, CSS et JavaScript pour créer la page Web.
ESP32 Charts with Data Logger
New readings are added to your chart automatically, you don't need to refresh the web page.
Refresh Charts
Download CSV
Delete All Data
Reset All Zoom
Humidity
Pressure
Latest Reading
Nombre de points de données
Par défaut, dans cet exemple, les graphiques afficheront un maximum de 1 200 points de données. Vous pouvez modifier cela dans la ligne suivante.
const displayData = allData.slice(-1200);
Notez que si vous augmentez beaucoup cette valeur, le chargement de toutes les données dans les graphiques peut prendre plus de temps.
Télécharger le fichier CSV /télécharger
Cette route envoie le fichier .csv stocké dans la carte microSD au client connecté (pour charger les données pour créer les graphiques).
server.on("/control", HTTP_GET, [](AsyncWebServerRequest *request) {
if (request->hasParam("state")) {
int state = request->getParam("state")->value().toInt();
digitalWrite(ledPin, state ? HIGH : LOW);
Serial.printf("LED set to %s\n", state ? "ON" : "OFF");
}
request->send(200, "text/plain", "OK");
});
Supprimer le fichier CSV/supprimer
Cette route supprime le fichier .csv stocké dans la carte microSD.
server.on("/delete", HTTP_POST, [](AsyncWebServerRequest *request){
if (SD.exists(dataFile)) SD.remove(dataFile);
File f = SD.open(dataFile, FILE_WRITE);
if (f) { f.println("temp_c,temp_f,humidity,pressure,time,day"); f.close(); }
request->send(200);
});
Initialiser le serveur
Enfin, appelez la méthode Begin() sur l'objet serveur pour initialiser le serveur.
server.begin();
boucle()
Dans la fonction loop(), nous avons une minuterie qui appelle la fonction logData() pour obtenir de nouvelles lectures à chaque valeur d'intervalle (par défaut toutes les 60 secondes).
if (millis() - previousMillis >= interval) {
previousMillis = millis();
logData();
}
La fonction logData() prend de nouvelles lectures du capteur BME280 et les stocke dans des variables auxiliaires avec un horodatage du serveur NTP. Enfin, il ajoute ces lectures à la dernière ligne du fichier .csv.
void logData() {
float tempC = bme.readTemperature();
float tempF = tempC * 9.0 / 5.0 + 32.0;
float hum = bme.readHumidity();
float press = bme.readPressure() / 100.0F;
File file = SD.open(dataFile, FILE_APPEND);
if (file) {
file.printf("%.2f,%.2f,%.2f,%.2f,%s,%s\n",
tempC, tempF, hum, press, getTimeStr().c_str(), getDateStr().c_str());
file.close();
}
}
Démonstration
Après avoir inséré vos informations d'identification réseau, téléchargez le code sur la carte ESP32. Après le téléchargement, ouvrez le moniteur série à une vitesse de transmission de 115 200 bauds et appuyez sur le bouton ESP32 RST.

L'adresse IP de l'ESP32 sera imprimée dans le moniteur série.

Ouvrez n'importe quel navigateur sur votre réseau local et saisissez l'adresse IP ESP32. La page Web suivante se chargera.

En haut de la page web, vous disposez de 4 boutons :
- Actualiser les graphiques : les graphiques sont mis à jour en temps réel, vous n'avez donc pas besoin d'utiliser ce bouton. Cependant, en cas d'échec du chargement du fichier .csv depuis la carte microSD, vous pouvez utiliser ce bouton ;
- Télécharger CSV : télécharge le fichier .csv stocké sur votre carte microSD ;
- Supprimer toutes les données : supprime toutes les données stockées dans le fichier .csv ;
- Réinitialiser tout le zoom : vous pouvez zoomer sur les graphiques pour voir les valeurs plus clairement, vous pouvez utiliser ce bouton pour effectuer un zoom arrière et revenir à la première vue.

Par défaut, le graphique de température affiche les valeurs en degrés Celsius. Il y a un bouton pour passer aux degrés Fahrenheit.

Avec votre curseur, vous pouvez sélectionner une section spécifique du graphique pour zoomer (cela fonctionne également sur les appareils dotés d'un écran tactile. Vous pouvez simplement pincer pour zoomer).

Ensuite, ce graphique sera agrandi. Vous pouvez également sélectionner les valeurs pour voir toutes les informations mises en évidence comme illustré ci-dessous. Pour effectuer un zoom arrière, vous pouvez double-cliquer sur le graphique ou utiliser le bouton Réinitialiser tout le zoom en haut de la page Web.

Ensuite, vous avez le graphique de pression, vous pouvez ignorer les données, car je testais juste le projet pendant quelques jours en l'allumant/éteignant.

Enfin, au bas de la page Web, il affiche uniquement les dernières lectures des capteurs.

Conclusion
Dans ce didacticiel, vous avez appris à créer un projet qui enregistre les données de température, d'humidité et de pression avec des horodatages dans un fichier .csv sur une carte microSD. Vous avez appris à faire en sorte que ces valeurs affichent des graphiques sur une page Web servie par l'ESP32.
Si vous avez aimé ce projet, vous aimerez peut-être également ces autres tutoriels :
Si vous souhaitez en savoir plus sur la construction de serveurs web avec l'ESP32 à partir de zéro, nous vous recommandons de jeter un œil à notre eBook dédié à ce sujet :
Merci d'avoir lu.
Cette vidéo vous emmène dans l'histoire de Raspberry Pi :

-
Ulegqin ESP32 S3 ESP-S3-Devkitc-1 N16R8 Carte mère avec IPEX Interface ESP32 S3 Module avec WiFi, Bluetooth 5.0 Extension de mémoire Externe Typ-C Interface Compatible avec Arduino(2 Pièces)
-
diymore Carte de développement pour ESP32-S3 CAM avec caméra OV3660, module ESP32-S3 N16R8, flash 16 Mo, PSRAM 8 Mo, double USB-C (OTG/TTL), WiFi, Bluetooth 5 LE, microSD, connecteur d'antenne IPEX
