#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define SOIL_PIN 34
#define PH_PIN 35
#define DHT_PIN 4
#define PUMP_PIN 25
#define BUZZER_PIN 26
#define DHTTYPE DHT22
DHT dht(DHT_PIN, DHTTYPE);
LiquidCrystal_I2C lcd(0x27, 20, 4); //I2C LCD 20x4
int soilThresh = 500; //Soil moisture threshold (in ml)
float tempThresh = 32.0; //Temperature threshold (in Celsius degrees)
float tempColdThresh = 10.0; //Temperature threshold (when too cold)
float humidityThresh = 85.0; //Humidity threshold (%)
unsigned long dryStartTime = 0;
bool buzzerOn = false;
bool pumpOn = false;
void setup() {
Serial.begin(115200);
dht.begin();
lcd.init();
lcd.backlight();
pinMode(PUMP_PIN, OUTPUT);
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(PUMP_PIN, LOW);
digitalWrite(BUZZER_PIN, LOW);
//Show welcome screen once
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BotanIQ");
lcd.setCursor(0, 1);
lcd.print("by IoT Group 3");
lcd.setCursor(0, 2);
lcd.print("Taylor's University");
delay(3000);
}
void loop() {
int ph = analogRead(PH_PIN);
delay(10);
int soil = analogRead(SOIL_PIN);
float voltage = ph * (3.3 / 4095.0); //Convert to voltage
float pHValue = mapf(voltage, 0.0, 3.3, 0.0, 14.0); //Map voltage to pH range
float temp = dht.readTemperature();
float hum = dht.readHumidity();
//If DHT does not work
if (isnan(temp) || isnan(hum)) {
Serial.println("❌ Failed to read from DHT sensor!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("DHT Sensor Error!");
}
//Serial Monitor output
Serial.printf("Soil Moisture = %dml, pH Level = %.2f, Temperature = %.1f°C, Humidity = %.1f%%\n", soil, pHValue, temp, hum);
//LCD output
lcd.clear();
lcd.setCursor(0, 0);
lcd.printf("Soil: %dml", soil);
lcd.setCursor(0, 1);
lcd.printf("pH Level: %.2f", pHValue);
lcd.setCursor(0, 2);
lcd.printf("Temperature: %.1f%cC", temp, 223);
lcd.setCursor(0, 3);
lcd.printf("Humidity: %.1f%%", hum);
delay(3000);
//Status flags
bool isDry = (soil < soilThresh);
bool isHot = (temp >= tempThresh);
bool isCold = (temp < tempColdThresh);
bool isTooHumid = (hum >= humidityThresh);
bool isTooAcidic = (pHValue < 4.0);
bool isTooAlkaline = (pHValue > 10.5);
//Alert Priority System
//Soil moisture & water pump
if (isDry) {
if (!buzzerOn) {
tone(BUZZER_PIN, 2000, 300);
dryStartTime = millis();
buzzerOn = true;
pumpOn = false;
digitalWrite(PUMP_PIN, LOW);
Serial.println("🚨 Soil is dry!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Soil is dry!");
delay(3000);
}
if (buzzerOn && (millis() - dryStartTime >= 3000) && !pumpOn) { //3 seconds passed since Buzzer is on
digitalWrite(PUMP_PIN, HIGH); //Turn on LED
tone(BUZZER_PIN, 2000, 300);
pumpOn = true;
Serial.println("💧 Water Pump ON (LED)");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Watering the plant");
delay(3000);
}
} else { //Reset if soil is no longer dry
digitalWrite(PUMP_PIN, LOW);
noTone(BUZZER_PIN);
buzzerOn = false;
pumpOn = false;
}
//Critical alerts
//Temperature too hot
if (isHot) {
tone(BUZZER_PIN, 2000, 300);
Serial.println("🌡️ It's hot!");
lcd.clear();
lcd.setCursor(0, 2);
lcd.print("It's hot!");
delay(3000);
}
//Temperature too cold
if (isCold) {
tone(BUZZER_PIN, 2000, 300);
Serial.println("❄️ It's too cold!");
lcd.clear();
lcd.setCursor(0, 2);
lcd.print("It's too cold!");
delay(3000);
}
//Too humid for the plant
if (isTooHumid) {
tone(BUZZER_PIN, 2000, 300);
Serial.println("💦 Too humid!");
lcd.clear();
lcd.setCursor(0, 3);
lcd.print("Too humid!");
delay(3000);
}
//pH level too acidic
if (isTooAcidic) {
tone(BUZZER_PIN, 2000, 300);
Serial.println("⚠️ Soil too acidic!");
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Soil too acidic!");
delay(3000);
}
//pH level to alkaline
if (isTooAlkaline) {
tone(BUZZER_PIN, 2000, 300);
Serial.println("⚠️ Soil too alkaline!");
lcd.clear();
lcd.setCursor(0, 1);
lcd.print("Soil too alkaline!");
delay(3000);
}
}
//Function to map float values
float mapf(float x, float in_min, float in_max, float out_min, float out_max) {
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}