DIY Soil Moisture Monitoring System with ESP32
Published: August 29, 2026 | For Indian farmers | Practical and cost-effective
Why Soil Moisture Monitoring Matters
Water is the most limiting factor in Indian farming. Over-irrigation wastes water, energy, and money — typically 30-40% more than needed. Under-irrigation stresses crops and reduces yields. A simple soil moisture monitoring system helps you irrigate just enough.
I’ve helped many farmers in our region setup this system. The typical investment is ₹2,500-₹3,500 per node — and it pays for itself in one season through water savings alone.
Project Overview
| Component | Purpose | Estimated Cost |
|---|---|---|
| ESP32 Development Board | Microcontroller with Wi-Fi | ₹350-₹450 |
| Capacitive Soil Moisture Sensor | Measures soil water content | ₹200-₹300 |
| DS18B20 Temperature Sensor | Measures soil temperature | ₹50-₹80 + 4.7kΩ resistor |
| Power Supply | Solar or battery | ₹500-₹1,500 |
| PCB & Connectors | Proper wiring | ₹100-₹200 |
Circuit Diagram
Note: I’m describing the circuit in text since I can’t draw visual diagrams. You can find reference diagrams online for “ESP32 soil moisture sensor wiring”.
Connections:
- Capacitive Soil Moisture Sensor:
- VCC → ESP32 5V or 3.3V pin
- GND → ESP32 GND pin
- AOUT → ESP32 GPIO 34 (ADC1_CH6)
- DS18B20 Temperature Sensor:
- VCC → ESP32 5V pin
- GND → ESP32 GND pin
- DATA → ESP32 GPIO 25 (or any GPIO)
- Add 4.7kΩ resistor between VCC and DATA
- Power:
- Option A: USB power from power bank (5V)
- Option B: Solar panel (6V-9V) with charge controller
- Option C: 2x 18650 battery holder with 5V step-down module
Software & Source Code
Arduino IDE is used. Install the ESP32 board manager first.
Required Libraries:
- DallasTemperature (for DS18B20)
- OneWire (for DS18B20)
- Preferences (for saving data – built into ESP32 Arduino core)
Complete Arduino Code:
`cpp
/*
* ESP32 Soil Moisture + Temperature Monitor
* For Indian Farmers – Practical IoT
*/
#include
#include
// Pin definitions
#define ONE_WIRE_BUS 25 // DS18B20 data pin
#define MOISTURE_PIN 34 // Capacitive soil moisture sensor
// Setup oneWire instance
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Variables
float moisturePercent = 0;
float temperatureC = 0;
unsigned long lastReading = 0;
const long readingInterval = 30000; // 30 seconds between readings
void setup() {
// Initialize serial for debugging
Serial.begin(115200);
// Initialize temperature sensor
sensors.begin();
// Initialize preferences (internal flash memory)
preferences.begin(“soil-monitor”, false);
Serial.println(“Soil Moisture Monitor Started”);
delay(1000);
}
void loop() {
unsigned long currentMillis = millis();
// Take reading every readingInterval milliseconds
if (currentMillis – lastReading >= readingInterval) {
lastReading = currentMillis;
// Read soil moisture
// Note: Raw values need calibration – see below
int rawMoisture = analogRead(MOISTURE_PIN);
// Convert to percentage (calibrate for your conditions!)
// Dry soil: ~0-500, Wet soil: ~600-1023 (approximate)
// Adjust these values based on your field conditions
moisturePercent = map(rawMoisture, 0, 1023, 0, 100);
// Clamp to valid range
if (moisturePercent > 100) moisturePercent = 100;
if (moisturePercent < 0) moisturePercent = 0;
// Read temperature
sensors.requestTemperatures(); // Send the command to get temperatures
temperatureC = sensors.getTempCByIndex(0); // Get temperature in Celsius
// Check if temperature reading is valid
if(temperatureC == DEVICE_SENSOR_INVALID) {
temperatureC = 0; // Or handle error appropriately
}
// Print readings to serial monitor
Serial.print("Moisture: ");
Serial.print(moisturePercent);
Serial.print("% | Temperature: ");
Serial.print(temperatureC);
Serial.println("°C");
// Save to internal flash memory
preferences.putFloat("last_moisture", moisturePercent);
preferences.putFloat("last_temp", temperatureC);
}
// Optional: Add Wi-Fi sending code here
// This is where you'd send data to ThingsSpeak, Adafruit IO, or your own server
`
Calibration is Critical
The code above gives rough estimates. You must calibrate for your specific soil:
- Place sensor in very dry soil (just watered, wait 1 hour) → note raw value
- Place sensor in fully saturated soil (recent heavy rain, or water trench) → note raw value
- Calculate your own map() range:
Example: If dry = raw value 380, wet = raw value 620, then use:
moisturePercent = map(rawMoisture, 380, 620, 0, 100);
Data Visualization
You have three simple options to see your data:
Option 1: Arduino Serial Monitor
- Connect ESP32 to computer via USB
- Open Arduino IDE Serial Monitor (115200 baud)
- See real-time moisture % and temperature
Option 2: ThingsSpeak (Free IoT Dashboard)
Add these lines to the code to publish data:
`cpp
// After getting readings, add:
String thingspeak_url = “http://api.thingspeak.com/update?api_key=YOUR_WRITE_KEY”;
String post_data = “field1=” + String(moisturePercent) + “&field2=” + String(temperatureC);
client.print(String(“GET “) + thingspeak_url + ” ” + “HTTP/1.1\r\n” + “Host: api.thingspeak.com\r\n” + “Connection: close\r\n\r\n”);
`
Free account at thingspeak.com. View graphs on their website or mobile app.
Option 3: Blynk (Mobile App)
Install Blynk app on smartphone, create dashboard, use ESP32 Wi-Fi example. More visual but has free tier limits.
Power Options for Remote Farms
| Option | Cost | Pros | Cons |
|---|---|---|---|
| Solar Panel 5W + Charge Controller | ₹800-₹1,200 | Lifetime power, no battery replacement | Higher initial cost, needs sunlight |
| Power Bank 10,000mAh | ₹500-₹800 | Cheap, easy to start | Needs manual charging every 2-3 weeks |
| 2x 18650 Battery + Step-down Module | ₹300-₹500 | Good balance, reusable | Battery replacement every 6-12 months |
Estimated Total Cost
₹2,500-₹3,500 per monitoring node for basic setup.
What to Do Next
- Build one node first — test in your field, calibrate the sensor, verify readings make sense
- Place sensor at root zone — 6-8 inches deep near representative plants, not at field edges
- Set threshold values — e.g., irrigate when moisture < 30%, stop when > 60%
- Add Wi-Fi data sending — start with ThingsSpeak free account
- Build more nodes — one per 2-3 acres, or for different soil types
Farmer Friend Tips
- Sensor placement: Keep sensor away from fertilizer bands — fertilizers change soil conductivity and give false readings
- Rainy season: Remove sensor or protect from direct water exposure during monsoon
- Weekly check: Once a week, verify sensor is still reading correctly; dust can accumulate
- Neighbor sharing: One ESP32 can monitor 2-3 nearby fields if you share the data
Circuit Schematic
Text diagram:
+5V (or 3.3V) GND
| |
| |
+----+------------------+----+
| | | |
| | | |
[ESP32] [Capacitive]
| | Soil Moisture
| | Sensor VCC → 5V
| | AOUT → GPIO34 (ADC1_CH6)
| | GND → GND
| +------------------+----+
| |
| |
GPIO25 -----------+-- DS18B20 Temperature Sensor
| |
| 4.7 kΩ
| |--- to VCC (pull‑up)
|
GND -------------------------+
Mermaid diagram (copy-paste into a mermaid renderer):
graph TD
VCC[5V Power] --> ESP32[ESP32]
GND[GND] --> ESP32
GND --> SensorV[Soil Moisture VCC]
GND --> TempV[DS18B20 VCC]
ESP32 -->|AOUT GPIO34| Moisture[AOUT Soil Moisture]
ESP32 -->|DATA GPIO25| Temp[DS18B20 DATA]
Moisture -->|4.7kΩ Pull‑up| Pull[Resistor Network]
Temp -->|4.7kΩ Pull‑up| Pull2[Resistor Network]
style ESP32 fill:#b3e5fc,stroke:#0b5394
style Moisture fill:#c8e6c9,stroke:#2e7d32
style Temp fill:#ffe0b2,stroke:#bf360c
References & Further Reading
- ESP32 Arduino Core: github.com/espressif/arduino-esp32
- DallasTemperature Library: milesburton.com/DallasTemperatureLibrary
- ThingsSpeak Documentation: docs.thingspeak.com
- Typical Indian farm water usage studies: agricultural extension publications