// Home Automation for ESP32 (Wokwi Compatible)
// Includes LCD 16x2 I2C, DHT22 Sensor, and HTTP GET Upload
// Automated relays for lights, fans, and soil moisture
// Sends data to server via GET request
#include <WiFi.h>
#include <HTTPClient.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <DHT.h>
// ----- WiFi Credentials -----
const char* wifiSsid = "Wokwi-GUEST"; // Change if using real WiFi
const char* wifiPassword = "";
// ----- Server Config -----
String serverUrl = "https://vertifarm.pythonanywhere.com/uploaddata";
String username = "shruti"; // Change this as needed
// ----- Constants -----
#define DHT_TYPE DHT22
// Pin Mapping
const int relayPinR1 = 19;//L1 : water pump pin
const int relayPinR2 = 18;//LED glow
const int relayPinR3 = 17;//L2 : water pump pin
const int relayPinR4 = 16;//Exhaust Fan
const int moistMakerPin = 33;
const int ldrPin = 34;
const int dhtPin = 4;
const int soilMoistureL1Pin = 35;
const int soilMoistureL2Pin = 32;
// LCD & DHT
LiquidCrystal_I2C lcd(0x27, 16, 2);
DHT dht(dhtPin, DHT_TYPE);
// ----- Global States -----
bool relayStateR1 = false;
bool relayStateR2 = false;
bool relayStateR3 = false;
bool relayStateR4 = false;
float currentTemp = NAN;
float currentHumi = NAN;
int ldrValue = 0;
int soilMoistureL1Val = 0;
int soilMoistureL2Val = 0;
// Thresholds
const int lightThreshold = 2000;
const int smL1Threshold = 2000;
const int smL2Threshold = 2000;
// ----- Function Declarations -----
void readSensors();
void controlLights();
void controlSoilMoisture();
void controlFan();
void displayStatus();
void checkTemperatureAlert();
void sendDataToServer();
// ----- Setup -----
void setup() {
Serial.begin(115200);
pinMode(relayPinR1, OUTPUT);
pinMode(relayPinR2, OUTPUT);
pinMode(relayPinR3, OUTPUT);
pinMode(relayPinR4, OUTPUT);
pinMode(moistMakerPin, OUTPUT);
pinMode(ldrPin, INPUT);
pinMode(soilMoistureL1Pin, INPUT);
pinMode(soilMoistureL2Pin, INPUT);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.print("Verti Farm");
lcd.setCursor(0, 1);
lcd.print("Connecting WiFi...");
delay(1000);
WiFi.begin(wifiSsid, wifiPassword);
int wifiRetry = 0;
while (WiFi.status() != WL_CONNECTED && wifiRetry < 20) {
delay(500);
Serial.print(".");
wifiRetry++;
}
lcd.clear();
if (WiFi.status() == WL_CONNECTED) {
lcd.print("WiFi Connected");
Serial.println("\nWiFi connected!");
} else {
lcd.print("WiFi Failed!");
Serial.println("\nWiFi connection failed!");
}
delay(1000);
dht.begin();
readSensors(); // initial read
}
// ----- Loop -----
void loop() {
readSensors();
controlLights();
controlSoilMoisture();
controlFan();
checkTemperatureAlert();
displayStatus();
// sendDataToServer(); // Send updated data to server
sendDataToServerLayer1(); // Send updated data to server
sendDataToServerLayer2(); // Send updated data to server
delay(10000); // Send every 10 seconds (adjust as needed)
}
// ----- Function Definitions -----
// Reads all sensor data (DHT22, LDR, Soil)
void readSensors() {
ldrValue = analogRead(ldrPin);
soilMoistureL1Val = analogRead(soilMoistureL1Pin);
soilMoistureL2Val = analogRead(soilMoistureL2Pin);
float tempReading = dht.readTemperature();
float humiReading = dht.readHumidity();
if (!isnan(tempReading)) currentTemp = tempReading;
if (!isnan(humiReading)) currentHumi = humiReading;
}
// Controls light relay based on LDR value
void controlLights() {
if (ldrValue >= lightThreshold) {
relayStateR2 = false;
digitalWrite(relayPinR2, LOW);
} else {
relayStateR2 = true;
digitalWrite(relayPinR2, HIGH);
}
}
// Controls water pump relays based on soil moisture
void controlSoilMoisture() {
if (soilMoistureL1Val >= smL1Threshold) {
relayStateR1 = false;
digitalWrite(relayPinR1, LOW);
} else {
relayStateR1 = true;
digitalWrite(relayPinR1, HIGH);
}
if (soilMoistureL2Val >= smL2Threshold) {
relayStateR3 = false;
digitalWrite(relayPinR3, LOW);
} else {
relayStateR3 = true;
digitalWrite(relayPinR3, HIGH);
}
}
// Controls fan relay based on temperature
void controlFan() {
if (!isnan(currentTemp) && currentTemp > 30.0) {
relayStateR4 = true;
digitalWrite(relayPinR4, HIGH);
digitalWrite(moistMakerPin, HIGH);
} else {
relayStateR4 = false;
digitalWrite(relayPinR4, LOW);
digitalWrite(moistMakerPin, LOW);
}
}
// Displays key data on LCD
void displayStatus() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("R1"); lcd.print(relayStateR1 ? "*" : "-");
lcd.print(" R2"); lcd.print(relayStateR2 ? "*" : "-");
lcd.print(" R3"); lcd.print(relayStateR3 ? "*" : "-");
lcd.print(" R4"); lcd.print(relayStateR4 ? "*" : "-");
lcd.setCursor(0, 1);
lcd.print("T:"); lcd.print(currentTemp, 0); lcd.print("C ");
lcd.print(ldrValue >= lightThreshold ? "LIT" : "DRK");
Serial.print("LDR: "); Serial.print(ldrValue);
Serial.print(" | Temp: "); Serial.print(currentTemp);
Serial.print("C | Humi: "); Serial.print(currentHumi);
Serial.print("% | Soil1: "); Serial.print(soilMoistureL1Val);
Serial.print(" | Soil2: "); Serial.print(soilMoistureL2Val);
Serial.print(" | R1: "); Serial.print(relayStateR1 ? "ON" : "OFF");
Serial.print(" | R2: "); Serial.print(relayStateR2 ? "ON" : "OFF");
Serial.print(" | R3: "); Serial.print(relayStateR3 ? "ON" : "OFF");
Serial.print(" | R4: "); Serial.println(relayStateR4 ? "ON" : "OFF");
}
// Displays alert if temperature exceeds limit
void checkTemperatureAlert() {
if (!isnan(currentTemp) && currentTemp > 40.0) {
Serial.println("ALERT: Temperature exceeds 40C!");
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("!!! TEMP ALERT !!!");
lcd.setCursor(0, 1);
lcd.print("T:"); lcd.print(currentTemp, 1); lcd.print("C");
delay(1200);
}
}
// ------------------------------------------------------------
// Sends collected data to the server using GET method
// Inputs: uses global sensor and relay variables
// Output: prints response or error to Serial
// ------------------------------------------------------------
void sendDataToServerLayer1() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// Convert relay states to 0/1
int pumpVal = relayStateR1 ? 1 : 0;
int fanVal = relayStateR4 ? 1 : 0;
int lightVal = relayStateR2 ? 1 : 0;
// Construct full GET URL
String fullUrl = serverUrl +
"?username=" + username +
"&layername=1" +
"&solimoistureval=" + String(soilMoistureL1Val) +
"&lightval=" + String(lightVal) +
"&pumpval=" + String(pumpVal) +
"&tempval=" + String(currentTemp, 0) +
"&humval=" + String(currentHumi, 0) +
"&fanval=" + String(fanVal);
Serial.println("Sending GET request to:");
Serial.println(fullUrl);
http.begin(fullUrl);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
Serial.println("Response: " + payload);
} else {
Serial.print("Error sending request: ");
Serial.println(http.errorToString(httpCode));
}
http.end();
} else {
Serial.println("WiFi not connected. Skipping data upload.");
}
}
void sendDataToServerLayer2() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// Convert relay states to 0/1
int pumpVal = relayStateR1 ? 1 : 0;
int fanVal = relayStateR4 ? 1 : 0;
int lightVal = relayStateR2 ? 1 : 0;
// Construct full GET URL
String fullUrl = serverUrl +
"?username=" + username +
"&layername=2" +
"&solimoistureval=" + String(soilMoistureL2Val) +
"&lightval=" + String(lightVal) +
"&pumpval=" + String(pumpVal) +
"&tempval=" + String(currentTemp, 0) +
"&humval=" + String(currentHumi, 0) +
"&fanval=" + String(fanVal);
Serial.println("Sending GET request to:");
Serial.println(fullUrl);
http.begin(fullUrl);
int httpCode = http.GET();
if (httpCode > 0) {
String payload = http.getString();
Serial.println("Response: " + payload);
} else {
Serial.print("Error sending request: ");
Serial.println(http.errorToString(httpCode));
}
http.end();
} else {
Serial.println("WiFi not connected. Skipping data upload.");
}
}