DIY Soil Moisture Monitoring System with ESP32

  • By
  • Published
  • 6 mins read

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:

  1. Place sensor in very dry soil (just watered, wait 1 hour) → note raw value
  2. Place sensor in fully saturated soil (recent heavy rain, or water trench) → note raw value
  3. 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

  1. Build one node first — test in your field, calibrate the sensor, verify readings make sense
  2. Place sensor at root zone — 6-8 inches deep near representative plants, not at field edges
  3. Set threshold values — e.g., irrigate when moisture < 30%, stop when > 60%
  4. Add Wi-Fi data sending — start with ThingsSpeak free account
  5. 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

Leave a Reply