Meta Description: Build ESP32-based real-time monitoring for hydroponics with TDS, pH, water level, and temperature sensors. Complete DIY guide with code, wiring diagrams, and cloud integration for smart farming.
Introduction: The 3:47 AM Alert That Changed Everything
The WhatsApp notification jolted Anna Petrov awake at 3:47 AM: “⚠️ CRITICAL ALERT: pH 8.2 (Target: 6.0) – Nutrient lockout imminent – 427 lettuce plants at risk.” Her ESP32 स्मार्ट मॉनिटरिंग सिस्टम (smart monitoring system) had detected a catastrophic pH spike 4.7 hours before her morning inspection would have discovered it—and 8-12 hours before visible plant damage would have appeared. Within 18 minutes, she had remotely adjusted pH dosing pumps from her smartphone, preventing what would have been a ₹2.4 lakh crop disaster.
Traditional hydroponic monitoring meant checking systems 2-3 times daily by physically visiting the grow area, reading analog gauges, manually logging numbers in notebooks, and hoping nothing went wrong between inspections. Anna’s ₹3,500 ESP32-based monitoring platform transformed agriculture from reactive crisis management to proactive real-time intelligence—continuously measuring TDS, pH, water level, and temperature every 30 seconds, transmitting data instantly to cloud storage, generating intelligent alerts before problems became disasters, and enabling remote monitoring and control from anywhere with internet access.
In the 14 months since deploying her ESP32 monitoring network across 2,400 hydroponic plants, Anna had solved agriculture’s visibility problem: knowing what’s happening in real-time, everywhere, always. Her system logged 4.2 million sensor readings, detected 47 critical issues before crop damage occurred, enabled 94% reduction in manual monitoring time (from 18 hours/week to 1 hour), and most remarkably—paid for itself in just 23 days through a single prevented crop failure.
The Traditional Hydroponic Monitoring Problem
Why Manual Systems Fail
The Standard Approach:
Most hydroponic growers rely on manual monitoring:
- Visit grow area 2-3 times daily
- Check pH with handheld meter (₹2,000-8,000)
- Test EC/TDS with separate meter (₹1,500-6,000)
- Measure temperature with thermometer
- Visually inspect water levels
- Write numbers in notebook or Excel
- React to problems after discovery
The Critical Failures:
1. Temporal Blindness (16-21 hours/day unmonitored)
- Check at 8 AM, 2 PM, 8 PM = 3 snapshots
- No data for 75% of the day
- Problems develop in blind periods
2. Delayed Problem Detection
- pH spike at 11 PM → discovered at 8 AM (9 hours later)
- By discovery time: Plant roots damaged, nutrient uptake blocked
- Recovery time: 5-14 days (if plants survive)
3. No Historical Analysis
- Notebook data hard to analyze
- No trending or pattern recognition
- Can’t identify recurring issues
4. No Remote Visibility
- Must physically visit to check status
- Can’t monitor while traveling
- No alerts during critical events
5. Labor Intensive
- 2-3 hours daily checking systems
- 18-22 hours weekly monitoring time
- Prevents scaling operation
Anna’s Pre-ESP32 Reality:
Daily Monitoring Routine:
- 7:00 AM: Walk to greenhouse, check pH (6.2), EC (1240 ppm), temp (21°C), water level (OK)
- 2:00 PM: Repeat measurements – pH 6.4, EC 1220, temp 24°C
- 8:00 PM: Final check – pH 6.6, EC 1200, temp 22°C
- Write in notebook, go to sleep
What She Missed:
- 11:30 PM: pH begins spiking (automated dosing pump failed)
- 3:00 AM: pH reaches 7.8 (critical)
- 7:00 AM: pH 8.2 discovered (16 hours after start)
- Damage: 187 plants showing nutrient deficiency, 8 days to recovery
- Loss: ₹84,000 (reduced marketability + delayed harvest)
The ESP32 Solution:
With real-time monitoring:
- System detects pH rising at 11:35 PM
- Alert sent at 12:10 AM (pH 7.1 – early warning)
- Critical alert at 3:47 AM (pH 8.2)
- Remote response: 18 minutes
- Damage: Zero
- Loss: ₹0
Understanding ESP32: The Agricultural IoT Brain
What is ESP32?
ESP32 Definition:
A low-cost microcontroller with built-in WiFi and Bluetooth, specifically designed for IoT (Internet of Things) applications. Think of it as a tiny computer (₹600-1,200) that can:
- Read sensors (pH, TDS, temperature, etc.)
- Make decisions based on sensor data
- Control devices (pumps, lights, fans)
- Connect to internet (send data to cloud)
- Communicate with smartphone (mobile app control)
Why ESP32 is Perfect for Hydroponics:
1. Built-in WiFi (vs Arduino requiring external WiFi module)
- Direct cloud connectivity
- No additional hardware needed
- Cost savings: ₹800-1,500
2. Dual-Core Processor (vs Arduino single-core)
- Core 1: Read sensors, control pumps
- Core 2: Handle WiFi communication
- Both run simultaneously without conflicts
3. Low Power Consumption
- Deep sleep mode: 10µA
- Active mode: 80mA average
- Can run on battery + solar panel
4. Large Memory
- 520 KB RAM (vs Arduino 2 KB)
- 4 MB flash storage
- Enough for complex programs + data logging
5. Multiple Communication Protocols
- I2C, SPI, UART, PWM, ADC
- Supports virtually any sensor
- Easy expansion
6. Low Cost
- ₹600-1,200 per board
- 10× cheaper than Raspberry Pi
- Same capabilities for monitoring
ESP32 vs Alternatives:
| Feature | Arduino Uno | ESP32 | Raspberry Pi 4 |
|---|---|---|---|
| Price | ₹400-800 | ₹600-1,200 | ₹4,500-6,500 |
| WiFi built-in | ❌ No | ✅ Yes | ✅ Yes |
| Power consumption | 50mA | 80mA | 500-1200mA |
| Processing power | 16 MHz, 1 core | 240 MHz, 2 cores | 1.5 GHz, 4 cores |
| Memory (RAM) | 2 KB | 520 KB | 2-8 GB |
| Complexity | Low | Medium | High |
| Best for | Basic automation | IoT monitoring | AI/ML, cameras |
Verdict: ESP32 = Perfect balance of cost, capability, and ease of use for hydroponic monitoring.
Building Your ESP32 Monitoring System
System Architecture Overview
┌─────────────────────────────────────────────────────────┐
│ Sensors (Reading Environment) │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ TDS │ │ pH │ │ Temp │ │ Water │ │
│ │ Sensor │ │ Sensor │ │ DS18B20 │ │ Level │ │
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
│ │ │ │ │ │
│ └────────────┴────────────┴────────────┘ │
└─────────────────────┬───────────────────────────────────┘
│
┌─────────▼──────────┐
│ ESP32 Board │
│ (WiFi Enabled) │
│ - Reads sensors │
│ - Processes data │
│ - Makes decisions │
└─────────┬──────────┘
│
┌─────────────┼─────────────┐
│ │ │
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌───────────┐
│ Cloud │ │ Mobile │ │ Local │
│ Storage │ │ App │ │ Display │
│ (Firebase,│ │ (Blynk, │ │ (OLED │
│ InfluxDB)│ │ Telegram)│ │ Screen) │
└───────────┘ └───────────┘ └───────────┘
Component List & Cost Breakdown
Core Components:
| Component | Specifications | Quantity | Unit Price | Total |
|---|---|---|---|---|
| ESP32 DevKit | 38-pin, WiFi+BT | 1 | ₹800 | ₹800 |
| TDS/EC Sensor | 0-5000 ppm, analog | 1 | ₹800 | ₹800 |
| pH Sensor | 0-14 pH, BNC probe | 1 | ₹1,500 | ₹1,500 |
| DS18B20 Temp | Waterproof, digital | 1 | ₹300 | ₹300 |
| Ultrasonic Level | HC-SR04 | 1 | ₹200 | ₹200 |
| 0.96″ OLED Display | 128×64, I2C | 1 | ₹400 | ₹400 |
| Breadboard + wires | Prototyping | 1 set | ₹250 | ₹250 |
| 5V Power Supply | 2A adapter | 1 | ₹300 | ₹300 |
| Enclosure | Waterproof box | 1 | ₹400 | ₹400 |
| Miscellaneous | Resistors, caps | 1 set | ₹150 | ₹150 |
| TOTAL: | ₹5,100 |
Optional Upgrades:
| Component | Purpose | Cost |
|---|---|---|
| DHT22 sensor | Air temp & humidity | ₹400 |
| Real-time clock (DS3231) | Accurate timestamps | ₹200 |
| MicroSD card module | Local data backup | ₹150 |
| Relay module (4-channel) | Control pumps/devices | ₹400 |
| Additional probes | Multiple zones | ₹800-2,500 |
Minimum System (Budget): ₹3,500
- ESP32 (₹800) + TDS (₹800) + DS18B20 (₹300) + Ultrasonic (₹200) + Power (₹300) + Enclosure (₹400) + Misc (₹200)
- Skip pH sensor initially (add later), no display (use phone app)
Professional System: ₹5,100 (as listed above)
Multi-Zone System (4 zones): ₹12,800
- 1× ESP32, 4× TDS, 4× pH, 4× Temp, 4× Level, display, power, enclosure
Step-by-Step Build Guide
Phase 1: Hardware Assembly
Step 1: Prepare ESP32 Board
ESP32 Pin Layout (38-pin DevKit):
┌─────────────────────────────────────┐
│ 3V3 EN VP VN D34 D35 D32 D33 │ (Left side)
│ GND D23 D22 TX0 RX0 D21 D19 D18 │
│ D5 D17 D16 D4 D0 D2 D15 SD1 │
│ SD0 CLK CMD D13 D12 D14 D27 D26 │
│ D25 D33 D32 D35 D34 VN VP GND │ (Right side)
│ VIN EN 3V3 │
└─────────────────────────────────────┘
Key Pins:
- 3V3: 3.3V output (max 600mA)
- GND: Ground (multiple pins available)
- VIN: 5V input from USB or external power
- GPIO pins: D0-D39 (not all available)
- ADC pins: VP(36), VN(39), D34, D35, D32, D33, D25, D26, D27, D14, D12, D13
Step 2: Connect TDS/EC Sensor
// TDS Sensor Wiring
TDS Sensor Module → ESP32
VCC (Red) → 5V (VIN pin)
GND (Black) → GND
Signal (Yellow) → GPIO 34 (ADC1_CH6)
// Physical Connection:
// 1. Insert sensor probe into nutrient solution
// 2. Secure probe with cable tie to tank edge
// 3. Ensure probe fully submerged (5cm minimum depth)
// 4. Keep away from air bubbles and heaters
TDS Sensor Calibration:
// Calibration with known standard solutions
// Use 1000 ppm TDS calibration solution (₹150-300)
float calibrateTDS() {
// Read known 1000 ppm solution
int rawValue = analogRead(34);
float voltage = rawValue * (3.3 / 4095.0); // ESP32 is 3.3V, 12-bit ADC
// TDS = k * voltage
// Solve for k: k = TDS / voltage
// Example: If reading 1.2V with 1000 ppm solution
// k = 1000 / 1.2 = 833.33
float calibrationFactor = 1000.0 / voltage;
// Store in EEPROM for permanent storage
EEPROM.writeFloat(0, calibrationFactor);
EEPROM.commit();
return calibrationFactor;
}
Step 3: Connect pH Sensor
// pH Sensor Wiring
pH Sensor Module → ESP32
VCC (Red) → 5V (VIN pin)
GND (Black) → GND
Signal (Blue) → GPIO 35 (ADC1_CH7)
// BNC Probe Care:
// 1. Remove protective cap, rinse with distilled water
// 2. Store in pH 4.0 storage solution when not in use
// 3. Never let probe dry out (damaged permanently)
// 4. Calibrate weekly for accuracy
pH Sensor Calibration (2-point):
// Use pH 4.0 and pH 7.0 buffer solutions (₹200-400)
struct pHCalibration {
float voltage_pH4;
float voltage_pH7;
float slope;
float intercept;
};
pHCalibration calibratePH() {
pHCalibration cal;
// Step 1: Read pH 4.0 buffer
Serial.println("Place probe in pH 4.0 buffer, wait 60 seconds");
delay(60000);
int raw1 = analogRead(35);
cal.voltage_pH4 = raw1 * (3.3 / 4095.0);
// Step 2: Rinse and read pH 7.0 buffer
Serial.println("Rinse probe, place in pH 7.0 buffer, wait 60 seconds");
delay(60000);
int raw2 = analogRead(35);
cal.voltage_pH7 = raw2 * (3.3 / 4095.0);
// Calculate slope and intercept: pH = slope * V + intercept
// Two-point formula: pH = [(pH7 - pH4) / (V7 - V4)] * V + intercept
cal.slope = (7.0 - 4.0) / (cal.voltage_pH7 - cal.voltage_pH4);
cal.intercept = 7.0 - (cal.slope * cal.voltage_pH7);
// Store calibration
EEPROM.writeFloat(4, cal.slope);
EEPROM.writeFloat(8, cal.intercept);
EEPROM.commit();
Serial.printf("Calibration complete: pH = %.2f * V + %.2f\n", cal.slope, cal.intercept);
return cal;
}
Step 4: Connect DS18B20 Temperature Sensor
// DS18B20 Wiring (Waterproof version)
DS18B20 → ESP32
Red wire (VCC) → 3V3
Black wire (GND) → GND
Yellow wire (Data) → GPIO 4 (with 4.7kΩ pull-up resistor to 3V3)
// Circuit Diagram:
// 3V3
// │
// 4.7kΩ Resistor (pull-up)
// │
// GPIO 4 ─── Yellow wire (Data)
//
// GND ─── Black wire
// 3V3 ─── Red wire
// Physical Installation:
// 1. Submerge probe directly in nutrient solution
// 2. Secure with cable tie
// 3. Position away from heater/chiller (measure solution, not device)
Step 5: Connect HC-SR04 Ultrasonic Water Level Sensor
// HC-SR04 Wiring
HC-SR04 → ESP32
VCC → 5V (VIN)
GND → GND
Trig → GPIO 5
Echo → GPIO 18
// Physical Mounting:
// 1. Mount sensor ABOVE water surface (5-30cm recommended)
// 2. Face sensor straight down (perpendicular to water)
// 3. Avoid foam, turbulence (causes false readings)
// 4. Keep dry (sensor is NOT waterproof)
Step 6: Connect OLED Display (Optional)
// 0.96" OLED Display Wiring (I2C)
OLED Display → ESP32
VCC → 3V3
GND → GND
SCL → GPIO 22 (I2C clock)
SDA → GPIO 21 (I2C data)
// I2C address: Usually 0x3C (check with I2C scanner if unsure)
Complete Wiring Diagram:
ESP32 DevKit
┌──────────────┐
TDS Signal ──── │ GPIO 34 │
pH Signal ──── │ GPIO 35 │
Temp Data ──── │ GPIO 4 │ (with 4.7kΩ pull-up)
Trig (Level)─── │ GPIO 5 │
Echo (Level)─── │ GPIO 18 │
OLED SDA ──── │ GPIO 21 │
OLED SCL ──── │ GPIO 22 │
│ │
5V Power ──── │ VIN │ ──── All sensor VCC (5V)
GND ──── │ GND │ ──── All sensor GND
│ 3V3 │ ──── DS18B20 VCC, OLED VCC
└──────────────┘
Phase 2: Software Programming
Complete Arduino Code
Install Required Libraries:
- Open Arduino IDE
- Go to Sketch → Include Library → Manage Libraries
- Install these libraries:
- WiFi (built-in for ESP32)
- OneWire (for DS18B20)
- DallasTemperature (for DS18B20)
- Adafruit_SSD1306 (for OLED)
- Adafruit_GFX (for OLED)
- PubSubClient (for MQTT – optional)
- FirebaseESP32 (for Firebase – optional)
Complete Monitoring System Code:
// ESP32 Hydroponic Monitoring System
// By Agriculture Novel - www.agriculturenovel.com
#include <WiFi.h>
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <EEPROM.h>
// ===== WiFi Configuration =====
const char* ssid = "YourWiFiName"; // Replace with your WiFi name
const char* password = "YourWiFiPassword"; // Replace with your WiFi password
// ===== Pin Definitions =====
#define TDS_PIN 34 // TDS sensor analog pin
#define PH_PIN 35 // pH sensor analog pin
#define TEMP_PIN 4 // DS18B20 data pin
#define TRIG_PIN 5 // Ultrasonic trigger pin
#define ECHO_PIN 18 // Ultrasonic echo pin
// ===== Sensor Objects =====
OneWire oneWire(TEMP_PIN);
DallasTemperature tempSensor(&oneWire);
// ===== OLED Display =====
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ===== Calibration Constants (stored in EEPROM) =====
float tdsCalibration = 833.33; // TDS calibration factor
float phSlope = -3.5; // pH slope (from 2-point calibration)
float phIntercept = 21.0; // pH intercept
// ===== Thresholds =====
struct Thresholds {
float tds_min = 800;
float tds_max = 1400;
float ph_min = 5.5;
float ph_max = 6.5;
float temp_min = 18.0;
float temp_max = 24.0;
float water_level_min = 15.0; // cm from sensor to water
} threshold;
// ===== Sensor Data Structure =====
struct SensorData {
float tds;
float ph;
float temperature;
float waterLevel;
unsigned long timestamp;
} currentData;
// ===== Alert Tracking =====
unsigned long lastAlertTime = 0;
const unsigned long ALERT_COOLDOWN = 3600000; // 1 hour between same alerts
void setup() {
Serial.begin(115200);
// Initialize sensors
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
tempSensor.begin();
// Initialize OLED
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("OLED initialization failed"));
}
display.display();
delay(1000);
display.clearDisplay();
// Initialize EEPROM
EEPROM.begin(512);
loadCalibration();
// Connect to WiFi
WiFi.begin(ssid, password);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("Connecting WiFi...");
display.display();
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Connected!");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
display.clearDisplay();
display.setCursor(0,0);
display.println("WiFi Connected!");
display.print("IP: ");
display.println(WiFi.localIP());
display.display();
delay(2000);
}
void loop() {
// Read all sensors
currentData.tds = readTDS();
currentData.ph = readPH();
currentData.temperature = readTemperature();
currentData.waterLevel = readWaterLevel();
currentData.timestamp = millis();
// Display on OLED
updateDisplay();
// Check thresholds and alert
checkThresholds();
// Send to cloud (every 5 minutes)
static unsigned long lastCloudUpdate = 0;
if (millis() - lastCloudUpdate > 300000) { // 5 minutes
sendToCloud();
lastCloudUpdate = millis();
}
// Serial output for debugging
printToSerial();
delay(30000); // Read every 30 seconds
}
// ===== TDS Reading Function =====
float readTDS() {
int rawValue = analogRead(TDS_PIN);
float voltage = rawValue * (3.3 / 4095.0); // ESP32 ADC: 12-bit, 3.3V reference
float tdsValue = tdsCalibration * voltage;
return tdsValue;
}
// ===== pH Reading Function =====
float readPH() {
int rawValue = analogRead(PH_PIN);
float voltage = rawValue * (3.3 / 4095.0);
// Apply calibration: pH = slope * voltage + intercept
float phValue = (phSlope * voltage) + phIntercept;
// Sanity check (pH must be 0-14)
if (phValue < 0) phValue = 0;
if (phValue > 14) phValue = 14;
return phValue;
}
// ===== Temperature Reading Function =====
float readTemperature() {
tempSensor.requestTemperatures();
float temp = tempSensor.getTempCByIndex(0);
// Error check (-127 = sensor error)
if (temp == -127.0) {
Serial.println("Temperature sensor error!");
return 20.0; // Return safe default
}
return temp;
}
// ===== Water Level Reading Function =====
float readWaterLevel() {
// Send ultrasonic pulse
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// Read echo
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // Timeout 30ms
if (duration == 0) {
Serial.println("Ultrasonic sensor timeout!");
return 0;
}
// Calculate distance in cm
float distance = duration * 0.034 / 2;
return distance;
}
// ===== Update OLED Display =====
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
// Line 1: TDS
display.setCursor(0, 0);
display.print("TDS: ");
display.print(currentData.tds, 0);
display.println(" ppm");
// Line 2: pH
display.setCursor(0, 12);
display.print("pH: ");
display.println(currentData.ph, 2);
// Line 3: Temperature
display.setCursor(0, 24);
display.print("Temp: ");
display.print(currentData.temperature, 1);
display.println(" C");
// Line 4: Water Level
display.setCursor(0, 36);
display.print("Level: ");
display.print(currentData.waterLevel, 1);
display.println(" cm");
// Line 5: WiFi Status
display.setCursor(0, 48);
if (WiFi.status() == WL_CONNECTED) {
display.print("WiFi: OK");
} else {
display.print("WiFi: LOST");
}
// Line 6: Last Update
display.setCursor(0, 56);
display.print(millis() / 1000);
display.print(" sec");
display.display();
}
// ===== Check Thresholds & Send Alerts =====
void checkThresholds() {
String alerts = "";
// TDS out of range
if (currentData.tds < threshold.tds_min) {
alerts += "⚠️ TDS LOW (" + String(currentData.tds, 0) + " ppm) - Add nutrients\\n";
}
if (currentData.tds > threshold.tds_max) {
alerts += "⚠️ TDS HIGH (" + String(currentData.tds, 0) + " ppm) - Dilute solution\\n";
}
// pH out of range
if (currentData.ph < threshold.ph_min) {
alerts += "🔴 pH LOW (" + String(currentData.ph, 2) + ") - CRITICAL\\n";
}
if (currentData.ph > threshold.ph_max) {
alerts += "🔴 pH HIGH (" + String(currentData.ph, 2) + ") - CRITICAL\\n";
}
// Temperature out of range
if (currentData.temperature < threshold.temp_min) {
alerts += "❄️ TEMP LOW (" + String(currentData.temperature, 1) + "°C) - Risk of slow growth\\n";
}
if (currentData.temperature > threshold.temp_max) {
alerts += "🔥 TEMP HIGH (" + String(currentData.temperature, 1) + "°C) - Root stress\\n";
}
// Water level low
if (currentData.waterLevel > threshold.water_level_min) {
alerts += "💧 WATER LOW - Refill reservoir\\n";
}
// Send alerts if any (with cooldown)
if (alerts.length() > 0 && (millis() - lastAlertTime > ALERT_COOLDOWN)) {
sendTelegramAlert(alerts);
lastAlertTime = millis();
}
}
// ===== Send Data to Cloud =====
void sendToCloud() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
// Example: Send to custom server or Firebase
String serverURL = "http://your-server.com/api/data";
// Create JSON payload
String jsonData = "{";
jsonData += "\"tds\":" + String(currentData.tds, 2) + ",";
jsonData += "\"ph\":" + String(currentData.ph, 2) + ",";
jsonData += "\"temperature\":" + String(currentData.temperature, 2) + ",";
jsonData += "\"water_level\":" + String(currentData.waterLevel, 2) + ",";
jsonData += "\"timestamp\":" + String(currentData.timestamp);
jsonData += "}";
http.begin(serverURL);
http.addHeader("Content-Type", "application/json");
int httpResponseCode = http.POST(jsonData);
if (httpResponseCode > 0) {
Serial.println("Data sent to cloud: " + String(httpResponseCode));
} else {
Serial.println("Cloud upload failed: " + String(httpResponseCode));
}
http.end();
}
}
// ===== Send Telegram Alert =====
void sendTelegramAlert(String message) {
// Telegram Bot API configuration
String botToken = "YOUR_BOT_TOKEN"; // Get from @BotFather
String chatID = "YOUR_CHAT_ID"; // Get from @userinfobot
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
String url = "https://api.telegram.org/bot" + botToken + "/sendMessage";
url += "?chat_id=" + chatID;
url += "&text=" + urlEncode(message);
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0) {
Serial.println("Alert sent via Telegram");
} else {
Serial.println("Telegram alert failed");
}
http.end();
}
}
// ===== Serial Print (Debugging) =====
void printToSerial() {
Serial.println("===== Sensor Readings =====");
Serial.print("TDS: "); Serial.print(currentData.tds, 2); Serial.println(" ppm");
Serial.print("pH: "); Serial.println(currentData.ph, 2);
Serial.print("Temperature: "); Serial.print(currentData.temperature, 1); Serial.println(" °C");
Serial.print("Water Level: "); Serial.print(currentData.waterLevel, 1); Serial.println(" cm");
Serial.println("==========================\n");
}
// ===== Load Calibration from EEPROM =====
void loadCalibration() {
EEPROM.readFloat(0, tdsCalibration);
EEPROM.readFloat(4, phSlope);
EEPROM.readFloat(8, phIntercept);
// Sanity check (if EEPROM empty, use defaults)
if (isnan(tdsCalibration) || tdsCalibration == 0) {
tdsCalibration = 833.33;
}
if (isnan(phSlope)) {
phSlope = -3.5;
}
if (isnan(phIntercept)) {
phIntercept = 21.0;
}
Serial.println("Calibration loaded from EEPROM");
}
// ===== URL Encoding Helper =====
String urlEncode(String str) {
String encoded = "";
char c;
char code0;
char code1;
for (int i = 0; i < str.length(); i++) {
c = str.charAt(i);
if (c == ' ') {
encoded += '+';
} else if (isalnum(c)) {
encoded += c;
} else {
code1 = (c & 0xf) + '0';
if ((c & 0xf) > 9) {
code1 = (c & 0xf) - 10 + 'A';
}
c = (c >> 4) & 0xf;
code0 = c + '0';
if (c > 9) {
code0 = c - 10 + 'A';
}
encoded += '%';
encoded += code0;
encoded += code1;
}
}
return encoded;
}
Upload Instructions:
- Connect ESP32 to computer via USB
- Select board: Tools → Board → ESP32 Arduino → ESP32 Dev Module
- Select port: Tools → Port → COMx (Windows) or /dev/ttyUSB0 (Linux)
- Edit WiFi credentials in code (lines 14-15)
- Click Upload button
- Wait for “Done uploading” message
- Open Serial Monitor (115200 baud) to see sensor readings
Phase 3: Cloud Integration & Mobile App
Option 1: Blynk IoT (Easiest – Recommended for Beginners)
Why Blynk:
- No coding required for mobile app
- Drag-and-drop interface builder
- Real-time graphs
- Push notifications
- Free tier available
Setup Steps:
1. Create Blynk Account
- Download Blynk app (iOS/Android)
- Sign up at blynk.io
- Create new template for “Hydroponic Monitor”
2. Add Datastreams
- TDS (Virtual Pin V0, 0-3000 ppm)
- pH (Virtual Pin V1, 0-14)
- Temperature (Virtual Pin V2, 0-40°C)
- Water Level (Virtual Pin V3, 0-50 cm)
3. Design Mobile Dashboard
- Add Gauge widget for TDS → Link to V0
- Add Gauge widget for pH → Link to V1
- Add Gauge widget for Temperature → Link to V2
- Add Level widget for Water → Link to V3
- Add Chart widget for historical trends
4. Add to ESP32 Code:
// Install Blynk library first
#include <BlynkSimpleEsp32.h>
char auth[] = "Your_Blynk_Auth_Token"; // From Blynk app
// In setup()
Blynk.begin(auth, ssid, password);
// In loop() - send data to Blynk
Blynk.run();
Blynk.virtualWrite(V0, currentData.tds);
Blynk.virtualWrite(V1, currentData.ph);
Blynk.virtualWrite(V2, currentData.temperature);
Blynk.virtualWrite(V3, currentData.waterLevel);
Cost: Free (up to 2 devices), ₹1,800/year for unlimited devices
Option 2: Firebase (Google Cloud – Free, Scalable)
Advantages:
- Completely free (generous quota)
- Real-time database
- Unlimited data storage
- Web + mobile access
- Google infrastructure reliability
Setup:
// Install FirebaseESP32 library
#include <FirebaseESP32.h>
#define FIREBASE_HOST "your-project.firebaseio.com"
#define FIREBASE_AUTH "your-database-secret"
FirebaseData firebaseData;
// In setup()
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
Firebase.reconnectWiFi(true);
// In loop() - send data
Firebase.setFloat(firebaseData, "/sensors/tds", currentData.tds);
Firebase.setFloat(firebaseData, "/sensors/ph", currentData.ph);
Firebase.setFloat(firebaseData, "/sensors/temperature", currentData.temperature);
Firebase.setFloat(firebaseData, "/sensors/waterLevel", currentData.waterLevel);
Web Dashboard: Create simple HTML page reading Firebase database
Cost: Free (up to 10 GB/month storage, 360 MB/day downloads)
Option 3: Telegram Bot (Free Alerts)
Why Telegram:
- Completely free
- Instant push notifications
- Works worldwide
- No app development needed
- Can control system via commands
Setup Telegram Bot:
- Open Telegram, search “@BotFather”
- Send
/newbot - Choose name: “MyHydroponicBot”
- Get bot token:
1234567890:ABCdefGHIjklMNOpqrsTUVwxyz - Start conversation with your bot
- Get your chat ID from:
https://api.telegram.org/bot<TOKEN>/getUpdates
Code Already Included (see sendTelegramAlert() function)
Real-World Results: Anna’s 14-Month Journey
Performance Metrics
Monitoring Reliability:
| Metric | Manual | ESP32 System | Improvement |
|---|---|---|---|
| Monitoring frequency | 3× daily | 2,880× daily (30 sec) | 960× more frequent |
| Coverage | 25% of day | 100% (24/7) | 4× better |
| Response time | 1-16 hours | 1-5 minutes | 96% faster |
| Data points/month | 2,700 | 86,400 | 32× more data |
| Historical analysis | Difficult | Easy (graphs) | Transformative |
Problem Detection:
14-Month Period:
- Critical issues detected: 47 (avg 3.4/month)
- Issues detected before crop damage: 44 (93.6%)
- Average detection time: 2.1 hours after onset
- Average response time: 18 minutes
- Prevented crop losses: ₹8.4 lakh total
Notable Incidents:
1. pH Spike Event (Month 3)
- Detection: 3:47 AM, pH 8.2 (started 11:30 PM)
- Response: Remote pH dosing adjustment via phone
- Time to resolution: 18 minutes
- Saved: 427 plants, ₹2.4 lakh
2. Temperature Failure (Month 7)
- Detection: 1:23 PM, temp rising (heater stuck on)
- Alert: “🔥 TEMP 29.1°C – CRITICAL”
- Response: Disabled heater circuit, added ice
- Saved: Entire 2,400 plant operation
3. Low Water (Month 11)
- Detection: 6:15 AM, level 18cm (critical 15cm)
- Alert: “💧 WATER LOW – Refill in 2 hours”
- Response: Scheduled water delivery
- Prevented: Pump damage (₹12,000), crop stress
Economic Impact
System Cost Breakdown:
Initial Investment:
- ESP32 + sensors + display: ₹5,100
- Enclosure + installation: ₹800
- Backup power (UPS): ₹2,400
- Total Initial: ₹8,300
Operating Costs (Annual):
- Electricity (5W × 24h × 365d): ₹315/year
- Internet (shared): ₹0 (existing WiFi)
- Cloud services (Blynk): ₹1,800/year
- Probe replacements (pH): ₹1,500/year (every 12 months)
- Calibration solutions: ₹400/year
- Total Annual: ₹4,015/year
Benefits Delivered (14 months):
1. Prevented Losses:
- Critical events prevented: 47
- Average loss per event: ₹18,000
- Total losses prevented: ₹8.46 lakh
2. Labor Savings:
- Manual monitoring time: 18 hours/week
- ESP32 monitoring time: 1 hour/week (checking alerts)
- Time saved: 17 hours/week × 60 weeks = 1,020 hours
- Value at ₹200/hour: ₹2.04 lakh
3. Optimization Gains:
- Better nutrient management: ₹14,000/year savings
- Improved growth rates: ₹28,000/year increased revenue
- Reduced waste: ₹8,000/year
Total 14-Month Value: ₹10.54 lakh
ROI Calculation:
- Investment: ₹8,300
- 14-month benefit: ₹10.54 lakh
- Net gain: ₹10.46 lakh
- ROI: 12,602%
- Payback period: 23 days (first prevented crisis)
Cost per Day:
- Initial: ₹8,300 / 420 days = ₹19.76/day
- Operating: ₹4,015 / 365 days = ₹11.00/day
- Total: ₹30.76/day (₹924/month)
Value per Day:
- Prevented losses: ₹8.46L / 420 days = ₹2,014/day
- Labor savings: ₹2.04L / 420 days = ₹486/day
- Total: ₹2,500/day (₹75,000/month)
Value-to-Cost Ratio: 81:1
Scaling Economics
Multi-Zone System (4 zones on 1 ESP32):
Components:
- 1× ESP32: ₹800
- 4× TDS sensors: ₹3,200
- 4× pH sensors: ₹6,000
- 4× DS18B20: ₹1,200
- 4× Ultrasonic: ₹800
- 1× 16-channel multiplexer: ₹400
- Display, enclosure, power: ₹1,400
- Total: ₹13,800
Cost per Zone: ₹3,450 (73% cheaper than separate systems)
10-Zone Farm (₹34,500 total):
- 3× ESP32 boards (each monitoring 3-4 zones)
- Centralized dashboard showing all zones
- Cost per zone: ₹3,450
Troubleshooting Guide
Common Problems & Solutions
Problem: TDS readings erratic (jumping 200+ ppm)
Causes:
- Poor probe contact
- Air bubbles on probe
- Electrical noise from pumps
Solutions:
- Ensure probe fully submerged (5cm minimum)
- Install probe away from pumps (30cm minimum)
- Add 100nF ceramic capacitor across sensor signal and ground
- Average 10 readings:
tds = (reading1 + reading2 + ... + reading10) / 10
Problem: pH readings drift over time
Causes:
- Probe dried out
- Probe contamination
- Need recalibration
Solutions:
- Store probe in pH 4.0 storage solution between uses
- Clean probe monthly: Soak in distilled water 30 min, gentle brush
- Calibrate weekly with pH 4.0 and 7.0 buffers
- Replace probe annually (₹1,200-1,800)
Problem: Temperature sensor returns -127.0°C
Causes:
- Loose connection
- Missing pull-up resistor
- Damaged sensor
Solutions:
- Check wiring: Data, VCC, GND all secure
- Verify 4.7kΩ resistor between data pin and 3V3
- Test with different sensor (₹300 replacement)
Problem: WiFi disconnects frequently
Causes:
- Weak signal
- Router issues
- ESP32 power brownout
Solutions:
- Move ESP32 closer to router or add WiFi extender
- Use external antenna on ESP32 (₹200)
- Increase power supply to 5V 2A (not 1A)
- Add auto-reconnect code:
void checkWiFi() {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("WiFi lost, reconnecting...");
WiFi.reconnect();
delay(5000);
}
}
// Call in loop()
checkWiFi();
Problem: System reboots randomly
Causes:
- Insufficient power
- Watchdog timer reset
- Memory overflow
Solutions:
- Use quality 5V 2A power supply (not phone charger)
- Add watchdog disable:
disableCore0WDT();in setup() - Check memory usage:
Serial.println(ESP.getFreeHeap());
Advanced Features & Upgrades
1. Automated Control (Relay Integration)
Add Control Capability:
// Add relay control
#define PUMP_RELAY 27
#define HEATER_RELAY 26
#define PH_UP_PUMP 25
#define PH_DOWN_PUMP 33
void setup() {
pinMode(PUMP_RELAY, OUTPUT);
pinMode(HEATER_RELAY, OUTPUT);
pinMode(PH_UP_PUMP, OUTPUT);
pinMode(PH_DOWN_PUMP, OUTPUT);
}
void automatedControl() {
// Auto pH adjustment
if (currentData.ph < 5.8) {
digitalWrite(PH_UP_PUMP, HIGH);
delay(1000); // 1 second dose
digitalWrite(PH_UP_PUMP, LOW);
}
if (currentData.ph > 6.2) {
digitalWrite(PH_DOWN_PUMP, HIGH);
delay(1000);
digitalWrite(PH_DOWN_PUMP, LOW);
}
// Auto temperature control
if (currentData.temperature < 19.0) {
digitalWrite(HEATER_RELAY, HIGH); // Turn on heater
} else if (currentData.temperature > 23.0) {
digitalWrite(HEATER_RELAY, LOW); // Turn off heater
}
}
Cost: ₹400 (4-channel relay module)
2. Data Logging to SD Card (Offline Backup)
#include <SD.h>
#include <SPI.h>
#define SD_CS 5 // SD card chip select pin
void setup() {
if (!SD.begin(SD_CS)) {
Serial.println("SD card initialization failed!");
}
}
void logToSD() {
File dataFile = SD.open("hydro_log.csv", FILE_APPEND);
if (dataFile) {
// Write CSV format: timestamp,tds,ph,temp,level
dataFile.print(millis());
dataFile.print(",");
dataFile.print(currentData.tds);
dataFile.print(",");
dataFile.print(currentData.ph);
dataFile.print(",");
dataFile.print(currentData.temperature);
dataFile.print(",");
dataFile.println(currentData.waterLevel);
dataFile.close();
Serial.println("Data logged to SD card");
}
}
Cost: ₹150 (MicroSD module + 16GB card)
3. Battery Backup with Solar
Solar Power System:
- 10W solar panel: ₹850
- 18650 Li-ion battery (3× 3.7V): ₹450
- TP4056 charging module: ₹80
- DC-DC boost converter (5V): ₹120
- Total: ₹1,500
Runtime: 24-48 hours on battery, indefinite with solar
Conclusion: The Real-Time Revolution
At 8:42 PM, as Anna reviewed her weekly monitoring dashboard from her smartphone while attending her daughter’s school play 45km away, the ESP32 Smart Monitoring System displayed something extraordinary: across 14 months and 4.2 million sensor readings, the ₹8,300 platform had detected 47 critical issues averaging 2.1 hours after onset, enabled remote responses within 18 minutes average, prevented ₹8.46 lakh in crop losses, and fundamentally transformed hydroponics from reactive guesswork to proactive data-driven precision.
The Monitoring Transformation Reality:
Modern agriculture isn’t about expensive commercial monitoring systems costing ₹50,000-₹2,00,000—it’s about intelligent DIY platforms built with ₹3,500-8,300 in components delivering equivalent functionality through open-source software, cloud connectivity, and real-time visibility that eliminates the blind periods where disasters develop unseen. The ESP32 represents democratization of agricultural technology: professional-grade monitoring accessible to every grower, regardless of budget.
The Economic Imperative:
Anna’s ESP32 implementation required:
- Capital: ₹8,300 (hardware + installation)
- Time: 6-8 hours (assembly + programming)
- Skills: Basic electronics knowledge (learnable in 2-3 days)
- Operating Cost: ₹4,015/year (electricity + cloud + maintenance)
The transformation delivered:
- 24/7 Monitoring: 2,880 readings/day vs 3 manual checks
- Early Detection: 2.1 hours average vs 1-16 hours manual
- Response Speed: 18 minutes vs 4-12 hours
- Prevented Losses: ₹8.46 lakh (14 months)
- ROI: 12,602%
- Payback: 23 days
The Strategic Insight:
ESP32-based monitoring transforms agriculture from blind intervals of uncertainty to continuous intelligent surveillance. Problems are detected before they cause damage. Trends are identified before they become crises. Remote management enables oversight from anywhere. Data-driven optimization replaces guesswork. The result: consistent yields, prevented disasters, and operational confidence impossible with manual monitoring alone.
As Erik checked the evening sensor readings remotely from a business meeting 120km away—noting pH 6.1, TDS 1180 ppm, temperature 21.4°C, water level optimal—Anna reflected on the fundamental shift: “We’re no longer farmers who check systems. We’re data-driven operators who are alerted when intervention is needed. The ESP32 watches 24/7 so we can focus on growing better crops, not constantly monitoring sensors.”
The real-time monitoring revolution isn’t coming to hydroponics. It’s already here, watching over crops for ₹8,300.
Technical Resources & Support
Hardware Suppliers (India)
ESP32 Boards:
- RoboElements.in: ₹750-900
- Robu.in: ₹650-850
- Amazon.in: ₹700-1,200
Sensors:
- pH/TDS sensors: RoboMall.in, Amazon.in
- Temperature sensors: Robu.in
- Complete kits: Agriculture Novel (₹4,500-6,500)
Software Resources
Arduino IDE: arduino.cc/en/software (free) ESP32 Libraries: github.com/espressif/arduino-esp32 Blynk: blynk.io Firebase: firebase.google.com Telegram Bot: core.telegram.org/bots
Agriculture Novel Support
Contact Information:
- ESP32 Consulting: esp32@agriculturenovel.com
- Technical Support: +91-9876543210
- WhatsApp: Get instant hydroponic monitoring help
- Website: www.agriculturenovel.com/esp32-monitoring
Services Offered:
- Pre-assembled ESP32 monitoring kits
- Custom sensor configurations
- Programming and setup assistance
- Cloud platform integration
- On-site installation (select areas)
- 24/7 technical support
ESP32 Monitoring Packages:
- Basic Kit (₹4,500): ESP32 + TDS + Temp + Level sensors
- Professional Kit (₹6,500): Full system with pH + display
- Multi-Zone Kit (₹13,800): 4-zone monitoring
- Installation Service (₹2,500): Professional setup + training
Tags: #ESP32Hydroponics #RealTimeMonitoring #TDSSensor #pHSensor #TemperatureSensor #WaterLevel #IoTAgriculture #SmartFarming #DIYAutomation #HydroponicMonitoring #AgTech #Arduino #CloudMonitoring #TelegramAlerts #BlynkIoT #Firebase #AgricultureNovel #PrecisionAgriculture #SensorIntegration #RemoteMonitoring
