#include <WiFi.h>
#include <PubSubClient.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define SDA_PIN 23 // SDA (D23)
#define SCL_PIN 22 // SCL (D22)
#define OLED_RESET -1 // Non utilisé avec I2C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// Configuration WiFi
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const int pinBuzzer = 12; // GPIO12 pour le buzzer
// Configuration ThingsBoard
const char* mqtt_server = "thingsboard.cloud";
const int mqtt_port = 1883;
const char* access_token = "1x87S7fKTypmp6e6HPem";
// Alertes WhatsApp (CallMeBot)
String phoneNumber = "+212696160741";
String wapKey = "4749822";
// Alertes Telegram
String botToken = "8042190456:AAHoMqHjhXjRdBZ-MAhw-n8HfNU58gRgZ50";
String chatId = "1522070172";
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastSend = 0;
int cycle = 0;
bool alerteEnvoyee = false;
void setup_wifi() {
Serial.print("Connexion au WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connecté");
}
void reconnect() {
while (!client.connected()) {
Serial.print("Connexion à ThingsBoard...");
if (client.connect("ESP32", access_token, NULL)) {
Serial.println("connecté !");
} else {
Serial.print("Échec, rc=");
Serial.print(client.state());
Serial.println(" nouvelle tentative dans 5s...");
delay(5000);
}
}
}
String getQualite(int c) {
if ((c / 5) % 3 == 0) return "Bon";
else if ((c / 5) % 3 == 1) return "Moyen";
else return "Mauvais";
}
String urlencode(String str) {
str.replace(" ", "%20");
return str;
}
void sendWhatsApp(String message) {
HTTPClient http;
String url = "https://api.callmebot.com/whatsapp.php?phone=" + phoneNumber + "&text=" + urlencode(message) + "&apikey=" + wapKey;
http.begin(url);
int httpCode = http.GET();
http.end();
Serial.println("WhatsApp code retour : " + String(httpCode));
}
void sendTelegram(String message) {
HTTPClient http;
String url = "https://api.telegram.org/bot" + botToken + "/sendMessage?chat_id=" + chatId + "&text=" + urlencode(message);
http.begin(url);
int httpCode = http.GET();
http.end();
Serial.println("Telegram code retour : " + String(httpCode));
}
void setup() {
Serial.begin(115200);
delay(1000);
setup_wifi();
client.setServer(mqtt_server, mqtt_port);
pinMode(pinBuzzer, OUTPUT);
digitalWrite(pinBuzzer, LOW);
// Initialisation I2C et écran OLED
Wire.begin(SDA_PIN, SCL_PIN);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("Échec de l'initialisation de l'écran OLED"));
while (true);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Surveillance Qualite:");
display.display();
reconnect();
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
if (millis() - lastSend > 5000) {
lastSend = millis();
float co2 = 400 + (50 * (cycle % 24)) + random(-20, 20);
float co = (random(10, 50) / 10.0) * 1.145;
float temperature = 20 + (cycle % 3);
float humidity = 40 + (cycle % 10);
String qualite = getQualite(cycle);
// Buzzer
if (qualite != "Mauvais") {
tone(pinBuzzer, 1000); // ON
} else {
noTone(pinBuzzer); // OFF
}
// OLED Affichage
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.println("Qualite de l'air:");
display.setTextSize(2);
display.setCursor(0, 20);
display.println(qualite);
display.display();
// JSON Payload
String payload = "{";
payload += "\"co2\": " + String(co2, 2) + ",";
payload += "\"co\": " + String(co, 2) + ",";
payload += "\"temperature\": " + String(temperature, 1) + ",";
payload += "\"humidity\": " + String(humidity, 1) + ",";
payload += "\"qualite\": \"" + qualite + "\",";
payload += "\"cycle\": " + String(cycle);
payload += "}";
Serial.println("Envoi des données : " + payload);
client.publish("v1/devices/me/telemetry", payload.c_str());
// Alertes
if (qualite != "Mauvais" && !alerteEnvoyee) {
String message = "🚨 ALERTE : qualité de l'air MAUVAISE !";
sendWhatsApp(message);
sendTelegram(message);
alerteEnvoyee = true;
}
if (qualite == "Mauvais") {
alerteEnvoyee = false;
}
cycle++;
}
}