#include <WiFi.h>
#include <PubSubClient.h>
#include <LiquidCrystal_I2C.h>
// WIFI
const char* ssid = "Wokwi-GUEST";
const char* password = "";
// ADAFRUIT
#define AIO_SERVER "io.adafruit.com"
#define AIO_PORT 1883
#define AIO_USERNAME "imen_a"
#define AIO_KEY "aio_ELhp01ZbLccULgsCRjLfVDo7P8o9"
WiFiClient espClient;
PubSubClient client(espClient);
// LCD
LiquidCrystal_I2C lcd(0x27, 16, 2);
// PINS
#define RELAY_PIN 14
#define SOIL_PIN 32
#define TANK_PIN 33
// FEEDS
String feed_soil;
String feed_tank;
String feed_relay;
String feed_alert;
String feed_weather;
// VARIABLES
bool pumpOn = false;
bool rain = false;
bool alertSoil = false;
bool alertTank = false;
bool alertRain = false;
unsigned long lastSend = 0;
// WIFI
void connectWiFi() {
lcd.clear();
lcd.print("WiFi...");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(300);
lcd.clear();
lcd.print("WiFi OK");
delay(1500);
}
// ALERT
void sendAlert(String msg) {
Serial.println(msg);
client.publish(feed_alert.c_str(), msg.c_str());
}
// MQTT CALLBACK (WEATHER)
void callback(char* topic, byte* payload, unsigned int length) {
String msg = "";
for (int i = 0; i < length; i++) msg += (char)payload[i];
if (String(topic) == feed_weather) {
if (msg == "RAIN") {
rain = true;
sendAlert("🌧️ RAIN DETECTED");
} else {
rain = false;
sendAlert("☀️ CLEAR WEATHER");
}
}
}
// MQTT
void reconnect() {
while (!client.connected()) {
if (client.connect("ESP32", AIO_USERNAME, AIO_KEY)) {
client.subscribe(feed_weather.c_str());
sendAlert("SYSTEM STARTED");
} else {
delay(2000);
}
}
}
// SETUP
void setup() {
Serial.begin(115200);
pinMode(RELAY_PIN, OUTPUT);
lcd.init();
lcd.backlight();
connectWiFi();
client.setServer(AIO_SERVER, AIO_PORT);
client.setCallback(callback);
// FEEDS
feed_soil = String(AIO_USERNAME) + "/feeds/moisture";
feed_tank = String(AIO_USERNAME) + "/feeds/tank";
feed_relay = String(AIO_USERNAME) + "/feeds/relay";
feed_alert = String(AIO_USERNAME) + "/feeds/alert";
feed_weather = String(AIO_USERNAME) + "/feeds/weather";
}
// LOOP
void loop() {
if (!client.connected()) reconnect();
client.loop();
// READ
int soil = map(analogRead(SOIL_PIN), 0, 4095, 0, 100);
int tank = map(analogRead(TANK_PIN), 0, 4095, 0, 100);
// -------- SMART LOGIC --------
if (rain) {
pumpOn = false;
if (!alertRain) {
sendAlert("🌧️ RAIN → STOP IRRIGATION");
alertRain = true;
}
}
else if (tank < 20) {
pumpOn = false;
if (!alertTank) {
sendAlert("⚠️ TANK EMPTY - REFILL");
alertTank = true;
}
}
else if (soil < 40) {
pumpOn = true;
if (!alertSoil) {
sendAlert("🚨 DRY SOIL → PUMP ON");
alertSoil = true;
}
}
else {
pumpOn = false;
alertSoil = false;
alertTank = false;
alertRain = false;
}
digitalWrite(RELAY_PIN, pumpOn ? HIGH : LOW);
// SEND DATA
if (millis() - lastSend > 5000) {
lastSend = millis();
char buf[10];
sprintf(buf, "%d", soil);
client.publish(feed_soil.c_str(), buf);
sprintf(buf, "%d", tank);
client.publish(feed_tank.c_str(), buf);
client.publish(feed_relay.c_str(), pumpOn ? "ON" : "OFF");
}
// LCD
lcd.clear();
lcd.setCursor(0,0);
lcd.print("S:");
lcd.print(soil);
lcd.print("% T:");
lcd.print(tank);
lcd.setCursor(0,1);
if (rain) {
lcd.print("RAIN -> OFF");
}
else if (tank < 20) {
lcd.print("REFILL WATER!");
}
else if (pumpOn) {
lcd.print("PUMP ON");
}
else {
lcd.print("PUMP OFF");
}
delay(1500);
}