Lucas Tirand¶
Je suis stagiaire en 1re professionnelle, du 20 avril au 13 mai.
Stage¶
Activités réalisées¶
Installation de Debian¶
J’ai installé Debian 13.4.0 sur un ordinateur à l’aide d’une clé USB bootable, puis j’ai configuré le système.
Recherches d'armoire de séchage pour filament¶
J’ai ensuite effectué des recherches sur les armoires de séchage de filament pour l’impression 3D. Voici ce que j’ai trouvé :
Maintient la température autour de 35 °C et l’humidité entre 15 % et 20 %, contrôlées par un thermomètre d’intérieur.
Pour sécher les bobines, elle utilise un déshumidificateur de chambre, une tige de déshumidification et un déshydrateur alimentaire.
Le déshumidificateur et le déshydrateur sont placés en bas de l’armoire.
Utilise un déshumidificateur et des boîtes de déshydratation fixées au milieu de l’armoire pour garder le matériel sec.
Aucun contrôle de température n’est prévu.
Utilise 500 g de perles de silice placées en bas pour absorber l’humidité. Le dessicant doit être remplacé chaque mois.
La température est surveillée à l’aide d’un thermomètre d’intérieur placé en bas.
Maintient l’humidité grâce à un déshumidificateur placé à la même hauteur que les rouleaux, sur la droite.
Aucun contrôle de température n’est disponible.
Maintient automatiquement la température et l’humidité. Si ces paramètres sont trop élevés ou trop bas, l’armoire ajuste automatiquement.
Il est possible de choisir la température et l’humidité souhaitées via un écran numérique.
Montage prototype capteur de température¶
Montage Arduino et DHT22¶
J’ai réalisé un montage avec une carte Arduino et un capteur DHT22, qui mesure la température et l’humidité.

Voicimon code :mon code :
#include <DHT.h>
#define brocheDeBranchementDHT 6 // Le DHT22 est branché sur le pin D6
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
void setup() {
// Moniteur série
Serial.begin(9600);
dht.begin();
}
void loop() {
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (isnan(tauxHumidite) || isnan(tauxTemperature)) {
Serial.println("Problème DHT");
delay(2000);
return;
}
// Affichage sur le moniteur série
Serial.print(tauxHumidite);
Serial.print(",");
Serial.print(tauxTemperature);
Serial.println();
delay(2000);
}
Ce code permet de mesurer la température et l’humidité de l’air ambiant, puis d’envoyer les résultats sur le moniteur série et de les afficher sous forme de graphique.

J’ai eu des problèmes pour transférer le code sur la carte Arduino parce que l’IDE n’avait pas les permissions. J’ai donc donné les droits administrateur au compte.
Ajout d'un écran LCD¶
J’ai ajouté un écran LCD pour afficher les résultats directement sur le montage, au lieu d’utiliser le moniteur série.

Voicimon code :mon code :
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define brocheDeBranchementDHT 6 // Le DHT22 est branché sur le pin D6
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
void setup() {
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(9600);
dht.begin();
}
void loop() {
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (isnan(tauxHumidite) || isnan(tauxTemperature)) {
Serial.println("Problème dht");
delay(2000);
return;
}
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
delay(2000);
}
J’ai eu des problèmes pour afficher le caractère "°", car il ne faisait pas partie des caractères acceptés par la bibliothèque. J’ai donc créé ma propre version avec du code binaire pour reproduire le signe des degrés.
Remplacement Arduino par ESP32¶
J’ai d’abord appris à utiliser un ESP32 et à connaître ses broches. Ensuite, comme mon code ne fonctionnait pas, j’ai fait quelques modifications demon code :mon code :
#define DHT1 4
Le DHT22 est branché sur le pin 4 et non pas sur le 6 car c'est un pin réserver au flash.
Wire.begin(21, 22);
SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32).
Serial.begin(115200);
L'ESP32 communique à une vitesse de 115200 bauds car 9600 est trop bas.
Essai avec un deuxième DHT22¶
J’ai fait un essai en ajoutant un deuxième capteur DHT22 et j’ai modifiéle code :le code :
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define DHT1 4 // Le premier DHT22 est branché sur le pin 4
#define DHT2 18 // Le deuxième DHT22 est branché sur le pin 18
#define typeDeDHT DHT22
DHT premierdht(DHT1, typeDeDHT);
DHT deuxiemedht(DHT2, typeDeDHT);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
void setup() {
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(92160);
premierdht.begin();
deuxiemedht.begin();
}
void loop() {
// Lecture des données
float tauxHumidite1 = premierdht.readHumidity(); // Lecture du taux d'humidité du premier DHT22 (en %)
float tauxTemperature1 = premierdht.readTemperature(); // Lecture de la température du premier DHT22 (en °C)
delay(200); // Attente de 0.2 seconde car sinon les données des deux capteurs se chevauchent
float tauxHumidite2 = deuxiemedht.readHumidity(); // Lecture du taux d'humidité du deuxième DHT22 (en %)
float tauxTemperature2 = deuxiemedht.readTemperature(); // Lecture de la température du deuxième DHT22 (en °C)
// Vérification des données du premier DHT
if (isnan(tauxHumidite1) || isnan(tauxTemperature1)) {
Serial.println("Problème DHT1");
delay(3000);
return;
}
// Vérification des données du deuxième DHT
if (isnan(tauxHumidite2) || isnan(tauxTemperature2)) {
Serial.println("Problème DHT2");
delay(3000);
return;
}
// Affichage sur le LCD
lcd.setCursor(0, 0);
lcd.print(tauxHumidite1);
lcd.print(";");
lcd.print(tauxHumidite2);
lcd.print(" %RH");
lcd.setCursor(1, 1);
lcd.print(tauxTemperature1);
lcd.print(";");
lcd.print(tauxTemperature2);
lcd.write(0);
lcd.print("C");
delay(3000);
}
Mes difficultés avec ce montage étaient :
- J’avais inversé les broches 5V et GND sur la carte.
- J’ai dû ajouter un petit délai entre la récupération des données des deux DHT22, sinon elles se chevauchaient et la lecture était impossible.

Ajout d'un ventilateur¶
J’ai ajouté un ventilateur au montage. Pour le moment, j’essaie simplement de programmer un ventilateur PWM de 12 V.
J’ai d’abord soudé un câble mâle sur l’alimentation 12 V, car l’un des câbles était dénudé. Ensuite, j’ai fait fonctionner le ventilateur directement sur la carte Arduino et l’alimentation 12 V.
J’ai rencontré des problèmes avec le câblage : j’ai essayé d’utiliser un MOSFET, une diode et des résistances, mais il a fallu changer de ventilateur, car le premier ne pouvait pas supporter le courant.
- Le premier ventilateur testé était le AFB0612L (4 broches).
- Le second ventilateur est le DS09225R12HP032 (4 broches).
Voicimon code de test :mon code de test :
int fanPin = 9; // Le ventilateur est branché sur le pin D9
// Définition du pin D9 comme sortie
void setup() {
pinMode(fanPin, OUTPUT);
}
// Le ventilateur fonctionne en boucle
void loop() {
for (int i = 0; i <= 255; i++) { // 0 correspond à aucun signal et 255 au maximum
analogWrite(fanPin, 10);
delay(1000);
analogWrite(fanPin, 100);
delay(1000);
analogWrite(fanPin, 175);
delay(1000);
analogWrite(fanPin, 255);
delay(2000);
analogWrite(fanPin, 175);
delay(1000);
analogWrite(fanPin, 100);
delay(1000);
analogWrite(fanPin, 10);
delay(1000);
}
}
Ce code permet de faire fonctionner le ventilateur en augmentant puis en diminuant sa puissance.

J’ai ensuite intégré ce ventilateur au montage. Pour commencer, j’ai repris le montage avec la carte Arduino, le DHT22 et le LCD. Mon objectif était de mettre le ventilateur en marche si le taux d’humidité devient trop élevé.
voicimon code:mon code:
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define brocheDeBranchementDHT 6 // Le DHT22 est branché sur le pin D6
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
int fanPin = 9; // Le ventilateur est branché sur le pin D9
int fanSpeed = 0; // La vitesse du ventilateur est 0 par définition
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajFan = 0; // Dernier moment où la vitesse du ventilateur a été mise à jour
const unsigned long IntervalleFan = 1000; // Intervalle de mise à jour du ventilateur en millisecondes
void setup() {
pinMode(fanPin, OUTPUT);
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(9600);
dht.begin();
}
void loop() {
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (isnan(tauxHumidite) || isnan(tauxTemperature)) {
Serial.println("Problème DHT");
return;
}
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
// Gestion ventilateur
if (tauxHumidite >= 30) { // Seuil pour activer le ventilateur (30% d'humidité)
// Augmentation progressive de la vitesse du ventilateur
if (millisActuels - dernierMajFan >= IntervalleFan) {
dernierMajFan = millisActuels;
if (fanSpeed < 255) {
fanSpeed += 100; // Augmentation de la vitesse par étapes de 100 (max 255 pour PWM)
if (fanSpeed > 255) fanSpeed = 255;
analogWrite(fanPin, fanSpeed);
}
}
} else {
fanSpeed = 0; // Humidité < 30%, ventilateur arrêté
analogWrite(fanPin, fanSpeed);
}
}
}

J’ai eu des difficultés avec le câblage du ventilateur par rapport à l’Arduino et à l’alimentation 12 V.
Il suffisait simplement de relier tous les GND ensemble, de brancher le positif du ventilateur au positif de l’alimentation et de connecter le ventilateur sur la broche D9, car c’est une broche PWM.
J’ai également eu des difficultés pour coder le ventilateur en fonction du taux d’humidité.
J’ai remplacé la carte Arduino par un ESP32. Cela a nécessité quelques modifications de mon code (voir ce lien Lucas_Tirand pour en savoir plus).
Ajout du système PID¶
J’ai installé la librairie PID dans l’IDE Arduino.
J’ai ensuite appris ce qu’est le PID et comment le calculer, car je ne connaissais pas ce concept.
J’ai intégré ce système àmon code :mon code :
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1_bc.h>
#define brocheDeBranchementDHT 4 // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
int fanPin = 18; // Le ventilateur est branché sur le pin 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajPID = 0; // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300; // Intervalle de lecture PID en millisecondes
// Variable PID
double Setpoint = 50; // Humidité ciblée
double Input;
double Output;
double Kp = 2.5; // Proportionnel
double Ki = 4.38; // Intégral
double Kd = 0.16; // Dérivé
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
void setup() {
pinMode(fanPin, OUTPUT);
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(115200);
dht.begin();
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0, 255); // PMW correspond à une valeur entre 0 et 255
}
void loop() {
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
Input = tauxHumidite;
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
}
}
// Lecture PID toutes les 300 ms
if (millisActuels - dernierMajPID >= IntervallePID) {
dernierMajPID = millisActuels;
pid.Compute(); // Calcule PID
analogWrite(fanPin, (int)Output);
Serial.print("Vitesse du ventilateur : ");
Serial.println(Output);
}
}
Mes difficultés avec ce code étaient :
- Le réglage des trois variables du PID (Proportionnel, Intégral et Dérivé).
- Le ventilateur ne faisait qu’augmenter sa vitesse, au lieu d’être correctement régulé par le PID.
Ajout d'une page web¶
J’ai ajouté une page web via l’ESP32 pour afficher la température, l’humidité et la vitesse du ventilateur.
Pour commencer, j’ai créé une page web simple qui comptait le nombre de visiteurs. Chaque fois que la page était actualisée, le compteur augmentait de 1.
Voicimon code :mon code :
#include <WiFi.h>
#include <WebServer.h>
// Nom et mot de passe du Wifi
const char* ssid = "coh@bit";
const char* password = "lewifidecohabit";
WebServer server(80); // HTML correspond au port 80
int nombre_visite = 0;
void setup() {
Serial.begin(115200);
Serial.println("Connexion à ");
Serial.println(ssid);
// Connexion au Wifi local
WiFi.begin(ssid, password);
// Verification si le Wifi est connecté à internet
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("Wifi Connecté");
Serial.print("IP : ");
Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("Server HTTP en marche");
}
void loop() {
server.handleClient();
}
void handle_OnConnect() {
nombre_visite++;
server.send(200, "text/html", createHTML());
}
//Création page d'erreur
void handle_NotFound() {
server.send(404, "text/plain", "Not found");
}
// Création page HTML
String createHTML() {
String html = "<!DOCTYPE html> <html>";
html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
html += "<style>";
html += "body {font-family: Arial, sans-serif; color: #444; text-align: center;}";
html += ".title {font-size: 30px; font-weight: bold; letter-spacing: 2px; margin: 80px 0 55px;}";
html += ".nombre_visite {font-size: 80px; font-weight: 300; line-height: 1; margin: 0px; color: #4285f4;}";
html += "</style>";
html += "</head>";
html += "<body>";
html += "<h1 class=\"title\">NOMBRE DE VISITEUR</h1>";
html += "<div class=\"nombre_visite\">";
html += nombre_visite;
html += "</div>";
html += "</body>";
html += "</html>";
return html;
}

J’ai ensuite intégré cette page web au montage pour afficher les données en temps réel.
Voicimon code :mon code :
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// Nom et mot de passe du Wifi
const char* ssid = "coh@bit";
const char* password = "lewifidecohabit";
WebServer server(80); // HTML correspond au port 80
#define brocheDeBranchementDHT 4 // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
float tauxHumidite = 0;
float tauxTemperature = 0;
float OutputRPM = 0;
int fanPin = 18; // Le ventilateur est branché sur le pin 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajPID = 0; // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300; // Intervalle de lecture PID en millisecondes
// Variables PID
double Setpoint = 50; // Humidité ciblée
double Input;
double Output;
double Kp = 1.5; // Proportionnel
double Ki = 1; // Intégral
double Kd = 0.16; // Dérivé
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
void setup() {
pinMode(fanPin, OUTPUT);
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(921600);
dht.begin();
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0, 255); // PMW correspond à une valeur entre 0 et 255
// Connexion au Wifi local
WiFi.begin(ssid, password);
// Verification de la connexion
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.print("IP de la carte : ");
Serial.println(WiFi.localIP());
// Message de communication client/serveur
server.on("/", connexion_Serveur);
server.on("/dataDHT", donnees_DHT);
server.on("/dataRPM", donnees_RPM);
server.on("/setHumidity", donnees_Set_Humidite);
server.onNotFound(echec_Connexion);
server.begin();
}
void loop() {
server.handleClient();
OutputRPM = (Output / 255.0) * 4500.0;
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
Input = tauxHumidite;
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
}
}
// Lecture PID toutes les 300 ms
if (millisActuels - dernierMajPID >= IntervallePID) {
dernierMajPID = millisActuels;
pid.Compute(); // Calcule PID
analogWrite(fanPin, (int)Output);
}
}
// Création page HTML
void connexion_Serveur() {
// Style du texte
String html = "<!DOCTYPE html><html>";
html += "<head><meta charset=\"UTF-8\">";
html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
html += "<style>";
html += "body {font-family: bauhaus 93, sans-serif; color: #000; text-align: center;}";
html += ".title {font-size: 30px; font-weight: bold; margin: 40px 0 30px;}";
html += ".temperature, .humidity, .vitesse {font-size: 40px; font-weight: 300; line-height: 1; margin-bottom: 20px;}";
html += ".temperature {color: #00b3ff;}";
html += ".humidity {color: #ff404d;}";
html += ".vitesse {color: #1eff1e;}";
html += ".unit {font-size: 20px; vertical-align: top;}";
// Style du slider et de la valeur
html += "#valeurHumidite {";
html += "font-size: 20px;";
html += "font-weight: bold;";
html += "margin-left: 10px;";
html += "color: #ff404d;";
html += "cursor: pointer;"; // valeur cliquable
html += "}";
html += "#sliderHumidite {";
html += "display: none;"; // Le slider est caché par défaut
html += "margin-top: 10px;";
html += "margin-left: 100px;";
html += "}";
html += "</style>";
html += "<script>";
// Température et humidité toutes les 2s
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('dht-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataDHT',true);";
html += "xhttp.send();";
html += "},2000);";
// Vitesse ventilateur toutes les 300ms
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('rpm-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataRPM',true);";
html += "xhttp.send();";
html += "},300);";
// Fonction pour mettre à jour l'humidité via le slider
html += "function updateHumidity() {";
html += "var humidity = document.getElementById('sliderHumidite').value;";
html += "document.getElementById('valeurHumidite').innerText = humidity + '%';"; // Mise à jour instantanée de l'affichage
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/setHumidity?value=' + humidity, true);";
html += "xhttp.send();";
html += "}";
// Fonction pour basculer l'affichage du slider
html += "function toggleSlider() {";
html += "var slider = document.getElementById('sliderHumidite');";
html += "if (slider.style.display === 'none') {";
html += " slider.style.display = 'block';"; // Afficher le slider
html += "} else {";
html += " slider.style.display = 'none';"; // Cacher le slider
html += "}";
html += "}";
html += "</script>";
html += "</head><body>";
html += "<h1 class=\"title\">État de l'armoire</h1>";
html += "<div id='dht-container'></div>";
html += "<div id='rpm-container'></div>";
// Affichage de la valeur de l'humidité et du slider
html += "<div>";
html += "<label for='sliderHumidite'>Humidité cible: </label>";
html += "<span id='valeurHumidite' onclick='toggleSlider()'>" + String(Setpoint) + "%</span>";
html += "<input type='range' id='sliderHumidite' min='0' max='100' value='" + String(Setpoint) + "' oninput='updateHumidity()'>";
html += "</div>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Communication données DHT22 client/serveur
void donnees_DHT() {
String data = "<div class=\"temperature\">" + String(tauxTemperature, 1) + "<span class=\"unit\">°C</span></div>";
data += "<div class=\"humidity\">" + String(tauxHumidite, 1) + "<span class=\"unit\">%RH</span></div>";
server.send(200, "text/html", data);
}
// Communication données vitesse ventilateur client/serveur
void donnees_RPM() {
String data = "<div class=\"vitesse\">" + String(OutputRPM, 0) + "<span class=\"unit\">RPM</span></div>";
server.send(200, "text/html", data);
}
// Communication données humidité cible client/serveur
void donnees_Set_Humidite() {
if (server.hasArg("value")) {
Setpoint = server.arg("value").toDouble();
}
server.send(200, "text/plain", "Humidité cible mise à jour");
}
// Communication données page non trouvé client/serveur
void echec_Connexion() {
server.send(404, "text/plain", "Not found");
}
J’ai eu des difficultés pour mettre les valeurs à jour automatiquement sans avoir besoin d’actualiser la page.
Ajout d'un tachymètre¶
J'ai ajouté le tachymètre du ventilateur à mon code car, sur la page web, la vitesse indiqué est la vitesse théorique obtenue par un calcule. J'ai donc ajouté une ligne indiquant la valeur réelle de la vitesse de mon ventilateur.
Voicimon code :mon code :
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// Nom et mot de passe du Wifi
const char* ssid = "coh@bit";
const char* password = "lewifidecohabit";
WebServer server(80); // HTML correspond au port 80
#define brocheDeBranchementDHT 4 // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
float tauxHumidite = 0;
float tauxTemperature = 0;
float OutputRPM = 0;
int fanPin = 18; // Le ventilateur est branché sur le pin 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajPID = 0; // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300; // Intervalle de lecture PID en millisecondes
unsigned long dernierMajTach = 0; // dernier moment où le tachymètre a été lu
const unsigned long IntervalleTach = 300; // Intervalle de lecture tachymètre en millisecondes
// Variables PID
double Setpoint = 50; // Humidité ciblée
double Input;
double Output;
double Kp = 1.5; // Proportionnel
double Ki = 1; // Intégral
double Kd = 0.16; // Dérivé
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
const int tachPin = 16; // Pin du tachymètre
volatile unsigned long compteImpulsionsTach = 0; // Compteur d'impulsions du tachymètre
double tachRPM = 0; // RPM mesuré par tachymètre
void IRAM_ATTR tachISR() {
compteImpulsionsTach++;
}
void setup() {
pinMode(fanPin, OUTPUT);
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(921600);
dht.begin();
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0, 255); // PWM correspond à une valeur entre 0 et 255
// Connexion au Wifi local
WiFi.begin(ssid, password);
// Vérification de la connexion
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.print("IP de la carte : ");
Serial.println(WiFi.localIP());
// Message de communication client/serveur
server.on("/", connexion_Serveur);
server.on("/dataDHT", donnees_DHT);
server.on("/dataRPM", donnees_RPM);
server.on("/setHumidity", donnees_Set_Humidite);
server.onNotFound(echec_Connexion);
server.begin();
// Tachymètre
pinMode(tachPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(tachPin), tachISR, FALLING);
dernierMajTach = millis();
}
void loop() {
server.handleClient();
OutputRPM = (Output / 255.0) * 4500.0;
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
Input = tauxHumidite;
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
}
}
// Lecture PID toutes les 300 ms
if (millisActuels - dernierMajPID >= IntervallePID) {
dernierMajPID = millisActuels;
pid.Compute(); // Calcule PID
analogWrite(fanPin, (int)Output);
}
// Lecture Tachymètre toutes les 300 ms
if (millisActuels - dernierMajTach >= IntervalleTach) {
tachRPM = (compteImpulsionsTach * 60000UL) / (IntervalleTach * 2); // 2 implusions par révolution
compteImpulsionsTach = 0;
dernierMajTach = millisActuels;
}
}
// Création page HTML
void connexion_Serveur() {
// Style du texte
String html = "<!DOCTYPE html><html>";
html += "<head><meta charset=\"UTF-8\">";
html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
html += "<style>";
html += "body {font-family: bauhaus 93, sans-serif; color: #000; text-align: center;}";
html += ".title {font-size: 30px; font-weight: bold; margin: 40px 0 30px;}";
html += ".temperature, .humidity, .vitesse {font-size: 40px; font-weight: 300; line-height: 1; margin-bottom: 20px;}";
html += ".temperature {color: #00b3ff;}";
html += ".humidity {color: #ff404d;}";
html += ".vitesse {color: #1eff1e;}";
html += ".unit {font-size: 20px; vertical-align: top;}";
// Style du slider et de la valeur
html += "#valeurHumidite {";
html += "font-size: 20px;";
html += "font-weight: bold;";
html += "margin-left: 10px;";
html += "color: #ff404d;";
html += "cursor: pointer;"; // valeur cliquable
html += "}";
html += "#sliderHumidite {";
html += "display: none;"; // Le slider est caché par défaut
html += "margin-top: 10px;";
html += "margin-left: 100px;";
html += "}";
html += "</style>";
html += "<script>";
// Température et humidité toutes les 2s
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('dht-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataDHT',true);";
html += "xhttp.send();";
html += "},2000);";
// Vitesse ventilateur toutes les 300ms
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('rpm-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataRPM',true);";
html += "xhttp.send();";
html += "},300);";
// Fonction pour mettre à jour l'humidité via le slider
html += "function updateHumidity() {";
html += "var humidity = document.getElementById('sliderHumidite').value;";
html += "document.getElementById('valeurHumidite').innerText = humidity + '%';"; // Mise à jour instantanée de l'affichage
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/setHumidity?value=' + humidity, true);";
html += "xhttp.send();";
html += "}";
// Fonction pour basculer l'affichage du slider
html += "function toggleSlider() {";
html += "var slider = document.getElementById('sliderHumidite');";
html += "if (slider.style.display === 'none') {";
html += " slider.style.display = 'block';"; // Afficher le slider
html += "} else {";
html += " slider.style.display = 'none';"; // Cacher le slider
html += "}";
html += "}";
html += "</script>";
html += "</head><body>";
html += "<h1 class=\"title\">État de l'armoire</h1>";
html += "<div id='dht-container'></div>";
html += "<div id='rpm-container'></div>";
// Affichage de la valeur de l'humidité et du slider
html += "<div>";
html += "<label for='sliderHumidite'>Humidité cible: </label>";
html += "<span id='valeurHumidite' onclick='toggleSlider()'>" + String(Setpoint) + "%</span>";
html += "<input type='range' id='sliderHumidite' min='0' max='100' value='" + String(Setpoint) + "' oninput='updateHumidity()'>";
html += "</div>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Communication données DHT22 client/serveur
void donnees_DHT() {
String data = "<div class=\"temperature\">" + String(tauxTemperature, 1) + "<span class=\"unit\">°C</span></div>";
data += "<div class=\"humidity\">" + String(tauxHumidite, 1) + "<span class=\"unit\">%RH</span></div>";
server.send(200, "text/html", data);
}
// Communication données vitesse ventilateur client/serveur
void donnees_RPM() {
String data = "<div class=\"vitesse\">" + String(tachRPM, 0) + "<span class=\"unit\">RPM</span></div>";
data += "<div style='font-size:16px;color:#000;'>Vitesse cible: <span style='font-size:20px;color:#1eff1e;'>" + String(OutputRPM,0) + " RPM</span></div>";
server.send(200, "text/html", data);
}
// Communication données humidité cible client/serveur
void donnees_Set_Humidite() {
if (server.hasArg("value")) {
Setpoint = server.arg("value").toDouble();
}
server.send(200, "text/plain", "Humidité cible mise à jour");
}
// Communication données page non trouvée client/serveur
void echec_Connexion() {
server.send(404, "text/plain", "Not found");
}
Mes difficultés sur ce code étaient :
- J'avais du mal à comprendre comment coder le tachymètre.
- J'ai inversé les noms des variables de la vitesse calculée et du tachymètre sur l'affichage sur la page web ce qui faisait que j'affichai deux fois la vitesse calculé au lieu d'afficher la vitesse réelle puis la vitesse calculée.

Recherches de materiel pour l'armoire de séchage¶
J’ai ensuite effectué des recherches sur le materiel nécessaire pour l'armoire de séchage de filament Voici ce que j’ai trouvé :
Tension de 12V
Vitesse de rotation de 1500 tr/min
Dimension de 150mmx50mm
Puissance de 30W
Git¶
J'ai appris à me servir de Git. J'ai ensuite mis les fichiers du projet sur le Git du Fablab. Voir ce lien.
J'ai eu des difficultés pour apprendre à me servir de Git et pour créer le README car il faut l'écrire en langage Markdown.
Impression 3D¶
J'ai fait une impression 3D pour un cadeau de la fête des mères. J'ai fait le mot "I love You" avec un modèle trouvé " sur internet. J'ai ensuite utilisé Orcaslicer pour le connfigurer et le rendre prêt à l'impression avec les paramètres suivants :
- Filament : PLA
- Machine : Prusa Core One
- Hauteur de couche : 0.2mm
- Temps d'impression : 1h 35min
Tranchage : Orca Slicer

Création 3D de l'armoire à filaments¶
J’ai commencé à modéliser l’armoire à filaments en 3D sur FreeCAD. Pour cela, j’ai d’abord pris le temps d’apprendre à utiliser le logiciel. Ensuite, je suis partie d’un cube pour créer la structure de l’armoire.
J’ai ensuite modélisé les bobines de différentes couleurs ainsi que les portes vitrées.

J’ai également créé les charnières des portes.
J’ai rencontré quelques difficultés, notamment pour réaliser des charnières aux bonnes dimensions. Au début, j’avais fait une charnière très petite. Quand j’ai voulu l’agrandir avec l’outil « Mettre à l’échelle », toute la charnière s’est retrouvée déformée. J’ai donc dû la recommencer en définissant les bonnes dimensions dès le départ.

À un moment, j’ai accidentellement supprimé le fichier 3D de l’armoire. Heureusement, j’ai pu le récupérer grâce à une application de récupération de fichiers.
Enfin, j’ai modélisé les équerres de maintien de l’armoire pour compléter le projet.

J’ai ensuite commencé à modéliser les composants électroniques et leurs boîtiers. J’ai trouvé sur Internet les fichiers 3D de l’ESP32, du DHT22 et de l’écran LCD, ainsi que les boîtiers de l’ESP32 et du DHT22, mais pas celui du LCD. J’ai donc tenté de créer moi-même quelques boîtiers, en testant différentes idées, mais aucun n’a vraiment été satisfaisant. Cette étape m’a surtout permis de mieux comprendre les contraintes de chaque composant et de réfléchir à des solutions adaptées.