#include <WiFi.h>
#include <HTTPClient.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#include <NewPing.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// === WiFi ===
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* mqtt_server = "mqtt.thingsboard.cloud";
const char* mqtt_token = "gAqHxUDIXanmKYcSkbeC";
const char* mqtt_topic = "v1/devices/me/telemetry";
const char* rpc_topic = "v1/devices/me/rpc/request/+";
// === CallMeBot (WhatsApp) ===
const char* phone_number = "212609559636";
const char* apikey = "9482834";
// === Broches ===
#define HUMIDITY_PIN 34
#define PUMP_PIN 26
#define WIFI_LED 2
#define MQTT_LED 15
#define TRIGGER_PIN 5
#define ECHO_PIN 18
#define MAX_DISTANCE 400
// === OLED ===
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
// === Variables ===
const long interval = 1000;
const int humidityThreshold = 40;
unsigned int distance = 0;
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
bool alertSent = false;
bool pumpManualControl = false;
bool pumpState = false;
void setup_wifi() {
Serial.begin(115200);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connecté !");
}
void reconnect_mqtt() {
while (!client.connected()) {
Serial.print("Connexion à MQTT...");
if (client.connect("ESP32_Client", mqtt_token, "")) {
Serial.println("Connecté !");
client.subscribe(rpc_topic);
} else {
Serial.print("Échec, code = ");
Serial.println(client.state());
delay(5000);
}
}
}
void callback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
StaticJsonDocument<200> doc;
deserializeJson(doc, payload);
String method = doc["method"];
if (method == "togglePumpMode") {
if (!pumpManualControl) {
pumpManualControl = true;
pumpState = true;
Serial.println("Mode: MANUEL (ON)");
} else if (pumpState) {
pumpState = false;
Serial.println("Mode: MANUEL (OFF)");
} else {
pumpManualControl = false;
Serial.println("Mode: AUTOMATIQUE");
}
digitalWrite(PUMP_PIN, pumpManualControl && pumpState ? HIGH : LOW);
}
}
void checkWiFiLED() {
digitalWrite(WIFI_LED, WiFi.status() == WL_CONNECTED ? HIGH : LOW);
}
void checkMQTTLED() {
digitalWrite(MQTT_LED, client.connected() ? HIGH : LOW);
}
void sendWhatsAppAlert(const String& message) {
HTTPClient http;
String url = "https://api.callmebot.com/whatsapp.php?phone=" + String(phone_number) +
"&text=" + urlencode(message) + "&apikey=" + String(apikey);
http.begin(url);
int httpCode = http.GET();
http.end();
}
String urlencode(const String& str) {
String encoded = "";
char c, code0, code1;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (isalnum(c)) {
encoded += c;
} else {
code1 = (c & 0xf) + '0'; if ((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A';
code0 = ((c >> 4) & 0xf) + '0'; if (((c >> 4) & 0xf) > 9) code0 = ((c >> 4) & 0xf) - 10 + 'A';
encoded += '%'; encoded += code0; encoded += code1;
}
}
return encoded;
}
void updateOLED(float humidity, int distance, bool pump, String mode) {
display.clearDisplay();
display.setCursor(0, 0);
display.setTextSize(1);
display.print("Humidite: ");
display.print(humidity, 1);
display.println(" %");
display.print("Reserve: ");
display.print(distance);
display.println(" cm");
display.print("Pompe: ");
display.println(pump ? "ON" : "OFF");
display.print("Mode: ");
display.println(mode);
display.display();
}
void publishSensorData() {
int sensorValue = analogRead(HUMIDITY_PIN);
float voltage = sensorValue * (3.3 / 4095.0);
float humidityPercent = (voltage / 3.3) * 100.0;
humidityPercent = constrain(humidityPercent, 0, 100);
distance = sonar.ping_cm();
float distancePercent = ((400 - distance) * 100.0) / 400.0;
distancePercent = constrain(distancePercent, 0, 100);
// Serial.print("Humidite du sol: ");
// Serial.print(humidityPercent);
// Serial.println(" %");
if (!pumpManualControl) {
if (humidityPercent < humidityThreshold) {
digitalWrite(PUMP_PIN, HIGH);
if (!alertSent) {
sendWhatsAppAlert("🚨 Alerte : humidité critique. Pompe activée !");
alertSent = true;
}
} else {
digitalWrite(PUMP_PIN, LOW);
alertSent = false;
}
}
if (distance == 0) {
//Serial.println("Reserve plein");
} else if (distance > 300) {
sendWhatsAppAlert("🚨 Alerte : il reste moins de 1m dans le reserve du pompe");
} else {
//Serial.println("Reserve restante: " + String(distance) + " cm");
}
String modeText = pumpManualControl ? (pumpState ? "MANUEL_ON" : "MANUEL_OFF") : "AUTO";
String payload = "{\"humidity\": " + String(humidityPercent) +
", \"pump\": " + String(digitalRead(PUMP_PIN)) +
", \"mode\": \"" + modeText +
"\", \"water_level\": " + String(distancePercent) + "}";
client.publish(mqtt_topic, payload.c_str());
Serial.println("📤 Envoyé : " + payload);
updateOLED(humidityPercent, distance, digitalRead(PUMP_PIN), modeText);
}
void setup() {
pinMode(PUMP_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW);
pinMode(WIFI_LED, OUTPUT);
pinMode(MQTT_LED, OUTPUT);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
Wire.begin(21, 22); // I2C pins pour ESP32
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("Erreur OLED !");
while (true); // stop si erreur
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Systeme Irrigation");
display.display();
delay(2000);
}
void loop() {
checkWiFiLED();
if (!client.connected()) reconnect_mqtt();
client.loop();
checkMQTTLED();
unsigned long now = millis();
if (now - lastMsg > interval) {
lastMsg = now;
publishSensorData();
}
}