// ============================================================
// STATION METEO IOT - NCARAI2E'26
// ESP32 + DHT22 + OLED + LED RGB + LDR + ThingSpeak
// Version Stable - Testée sur Wokwi
// ============================================================
#include <WiFi.h>
#include <ThingSpeak.h>
#include <DHT.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// ============================================================
// CONFIGURATION - REMPLACEZ PAR VOS IDENTIFIANTS
// ============================================================
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASS ""
#define THINGSPEAK_API_KEY "7Z5FBMRLBC25S5ZH"
#define THINGSPEAK_CHANNEL_ID 3413154
// ============================================================
// CONFIGURATION MATÉRIELLE
// ============================================================
#define DHTPIN 4
#define DHTTYPE DHT22
#define LDRPIN 34
#define OLED_RESET -1
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define READ_INTERVAL 5000
#define LED_RED 13
#define LED_GREEN 12
#define LED_BLUE 14
// ============================================================
// OBJETS
// ============================================================
DHT dht(DHTPIN, DHTTYPE);
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
WiFiClient client;
// ============================================================
// VARIABLES
// ============================================================
float temperature = 0;
float humidity = 0;
float pressure = 1013.25; // Simulée
int luminosity = 0;
unsigned long lastRead = 0;
int transmissionCount = 0;
int successCount = 0;
bool oledReady = false;
// ============================================================
// SETUP
// ============================================================
void setup() {
Serial.begin(115200);
Serial.println("\n===========================================");
Serial.println("🌤️ STATION METEO IOT - NCARAI2E'26");
Serial.println("===========================================\n");
// === LED RGB ===
pinMode(LED_RED, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
setLED(0, 255, 0); // Vert = Démarrage
Serial.println("✅ LED RGB initialisée");
// === DHT22 ===
dht.begin();
Serial.println("✅ DHT22 initialisé");
// === OLED ===
Serial.println("🔄 Initialisation OLED...");
Wire.begin();
Wire.setClock(100000);
delay(100);
// Test de présence I2C
bool i2cFound = false;
for (uint8_t addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.printf(" ✅ Périphérique I2C trouvé à 0x%02X\n", addr);
if (addr == 0x3C) {
i2cFound = true;
Serial.println(" 🖥️ OLED SSD1306 détecté !");
}
}
}
if (!i2cFound) {
Serial.println("❌ Aucun périphérique I2C trouvé !");
Serial.println(" Vérifiez les connexions SDA (21) et SCL (22)");
}
// Tentative d'initialisation de l'OLED
if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("✅ OLED initialisé avec succès !");
oledReady = true;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("🌤️ METEO IOT");
display.println("NCARAI2E'26");
display.display();
delay(1000);
} else {
Serial.println("❌ Échec de l'initialisation de l'OLED");
oledReady = false;
}
// === WiFi ===
Serial.print("📶 Connexion WiFi...");
WiFi.begin(WIFI_SSID, WIFI_PASS);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n✅ WiFi connecté");
Serial.println(" IP: " + WiFi.localIP().toString());
setLED(0, 0, 255); // Bleu = WiFi OK
} else {
Serial.println("\n❌ WiFi non connecté");
setLED(255, 255, 0); // Jaune = WiFi KO
}
// === ThingSpeak ===
ThingSpeak.begin(client);
Serial.println("✅ ThingSpeak initialisé\n");
Serial.println("📡 Lecture en cours...\n");
}
// ============================================================
// LOOP PRINCIPAL
// ============================================================
void loop() {
if (millis() - lastRead >= READ_INTERVAL) {
lastRead = millis();
// Lecture des capteurs
readSensors();
// Affichage
printDebug();
updateDisplay();
// Envoi ThingSpeak
sendToThingSpeak();
Serial.println("-------------------------------------------\n");
}
delay(10);
}
// ============================================================
// LECTURE DES CAPTEURS
// ============================================================
void readSensors() {
float t = dht.readTemperature();
float h = dht.readHumidity();
if (!isnan(t) && !isnan(h)) {
temperature = t;
humidity = h;
setLED(0, 255, 0); // Vert = données valides
} else {
Serial.println("⚠️ Erreur DHT22 - valeurs simulées");
temperature = 20.0 + random(-50, 50) / 10.0;
humidity = 60.0 + random(-100, 100) / 10.0;
setLED(255, 0, 0); // Rouge = erreur capteur
}
// Pression simulée
pressure = 1013.25 + random(-50, 50) / 10.0;
// LDR
luminosity = analogRead(LDRPIN);
}
// ============================================================
// AFFICHAGE SERIAL
// ============================================================
void printDebug() {
Serial.println("===========================================");
Serial.println("🌤️ DONNEES METEO - NCARAI2E'26");
Serial.println("-------------------------------------------");
Serial.printf("🌡️ Température : %.1f °C\n", temperature);
Serial.printf("💧 Humidité : %.1f %%\n", humidity);
Serial.printf("📊 Pression : %.1f hPa\n", pressure);
Serial.printf("☀️ Luminosité : %d\n", luminosity);
Serial.printf("📡 Transmissions : %d\n", transmissionCount);
Serial.printf("✅ Succès : %d\n", successCount);
Serial.printf("🖥️ OLED : %s\n", oledReady ? "OK" : "❌");
Serial.printf("📶 WiFi : %s\n", WiFi.status() == WL_CONNECTED ? "Connecté" : "Déconnecté");
Serial.println("===========================================");
}
// ============================================================
// AFFICHAGE OLED (SÉCURISÉ)
// ============================================================
void updateDisplay() {
if (!oledReady) {
// Tentative de réinitialisation de l'OLED
if (display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("✅ OLED réinitialisé !");
oledReady = true;
} else {
return; // Sortir si l'OLED n'est pas disponible
}
}
display.clearDisplay();
display.setCursor(0, 0);
display.println("🌤️ METEO IOT");
display.println("────────────");
display.printf("T:%.1f C\n", temperature);
display.printf("H:%.1f %%\n", humidity);
display.printf("P:%.1f hPa\n", pressure);
display.printf("L:%d", luminosity);
display.display();
}
// ============================================================
// LED RGB
// ============================================================
void setLED(int r, int g, int b) {
analogWrite(LED_RED, r);
analogWrite(LED_GREEN, g);
analogWrite(LED_BLUE, b);
}
// ============================================================
// THINGSPEAK
// ============================================================
void sendToThingSpeak() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("⚠️ WiFi déconnecté - données non transmises");
setLED(255, 255, 0); // Jaune
return;
}
transmissionCount++;
ThingSpeak.setField(1, temperature);
ThingSpeak.setField(2, humidity);
ThingSpeak.setField(3, pressure);
ThingSpeak.setField(4, luminosity);
int response = ThingSpeak.writeFields(THINGSPEAK_CHANNEL_ID, THINGSPEAK_API_KEY);
if (response == 200) {
successCount++;
Serial.println("✅ Données envoyées à ThingSpeak");
setLED(0, 255, 0); // Vert = Succès
} else {
Serial.printf("❌ Erreur ThingSpeak: %d\n", response);
setLED(255, 0, 0); // Rouge = Erreur
}
}