OC
OceanRemote
Low-code IoT platform
← Back to Course

Soil Temperature Sensors - DS18B20 and NTC

Soil Temperature Sensors - DS18B20 and NTC

💧 Complete Guide to Soil Moisture Sensors

🌱 What You'll Learn in This Lesson:

  • How soil moisture sensors work (capacitive vs resistive)
  • Complete wiring diagrams for ESP32, ESP8266, and Pico W
  • Step-by-step code explanation with line-by-line breakdown
  • How to calibrate your sensor for accurate readings
  • Practical application: automating irrigation based on soil moisture

📊 How Soil Moisture Sensors Work

Soil moisture sensors measure the water content in soil. There are two main types:

Type How It Works Pros & Cons
Resistive Measures electrical resistance between two probes. Water conducts electricity, so wet soil = lower resistance. ✅ Cheap ($2-3)
❌ Corrodes over time
❌ Less accurate
Capacitive Measures dielectric constant of soil. Water has a higher dielectric constant than dry soil. ✅ Lasts longer (no exposed metal)
✅ More accurate
✅ Works for years
❌ Slightly more expensive ($8-12)
💡 Pro Tip:

For long-term agricultural projects, always choose capacitive sensors. They cost a bit more but will last for years without corroding. Resistive sensors may fail within months in constantly moist soil.

🔧 Sensor Comparison by Crop

Application Recommended Sensor Why
Greenhouse (short-term projects) Resistive (under $5) Controlled environment, less corrosion risk
Field crops (long-term) Capacitive ($8-12) Lasts for years, accurate readings
Budget learning / prototyping Resistive ($2-3) Good for learning, cheap to replace

🔌 Complete Wiring Guide

📡 For ESP32 (Recommended):

Capacitive Soil Moisture Sensor → ESP32
VCC (Red/Brown)              → 3.3V pin
GND (Black)                  → GND pin
AO (Analog Output) (Yellow/Blue) → GPIO32 (or any ADC pin)
    

📡 For ESP8266 (Budget Option):

⚠️ IMPORTANT for ESP8266:

ESP8266 ADC only accepts 0-1V! Most sensors output 0-3.3V. You MUST use a voltage divider:

Sensor AO → 10kΩ resistor → ESP8266 A0
Sensor AO → 5.6kΩ resistor → GND
(Output voltage: 3.3V * (5.6 / (10 + 5.6)) = 1.18V)
        

🍓 For Raspberry Pi Pico W:

Capacitive Soil Moisture Sensor → Pico W
VCC                           → 3.3V (pin 36)
GND                           → GND (pin 38)
AO (Analog Output)            → GP26 (ADC0, pin 31)
    

📖 Complete Arduino Code with Explanation

/*
 * Soil Moisture Sensor Monitor for ESP32/ESP8266
 * 
 * This code reads a soil moisture sensor and tells you:
 * - Raw analog value (0-4095 on ESP32)
 * - Moisture percentage (0-100%)
 * - When to water (alert when below 30%)
 * 
 * How to use:
 * 1. Connect sensor to GPIO32 (ESP32) or A0 (ESP8266 with voltage divider)
 * 2. Calibrate: Find DRY_VALUE and WET_VALUE (see calibration section)
 * 3. Upload and open Serial Monitor at 115200 baud
 * 4. Watch your soil moisture in real-time!
 */

#include   // Not needed after ESP32 core installation

// ========== PIN CONFIGURATION ==========
#ifdef ESP32
    const int SOIL_PIN = 32;      // GPIO32 has ADC capability
#endif
#ifdef ESP8266
    const int SOIL_PIN = A0;      // A0 is the only ADC pin on ESP8266
#endif

// ========== CALIBRATION VALUES - YOU MUST ADJUST THESE! ==========
// Step 1: Upload code with DRY_VALUE = 4095, WET_VALUE = 0
// Step 2: Read sensor in dry air → record value
// Step 3: Submerge sensor in water → record value
// Step 4: Replace these values with YOUR readings
const int DRY_VALUE = 3800;   // Replace with your dry air reading (ex: 3500-4095)
const int WET_VALUE = 1500;   // Replace with your water reading (ex: 1000-2000)

// ========== THRESHOLDS (Adjust based on your crops) ==========
const int WATER_NEEDED = 30;   // Water when moisture drops below 30%
const int TOO_WET = 80;        // Too wet above 80% (risk of root rot)

void setup() {
    Serial.begin(115200);
    pinMode(SOIL_PIN, INPUT);
    
    Serial.println("========================================");
    Serial.println("💧 Soil Moisture Monitor v1.0");
    Serial.println("========================================");
    Serial.print("Sensor Pin: ");
    Serial.println(SOIL_PIN);
    Serial.print("Calibration: Dry=");
    Serial.print(DRY_VALUE);
    Serial.print(", Wet=");
    Serial.println(WET_VALUE);
    Serial.println("========================================
");
}

void loop() {
    // Step 1: Read raw analog value
    int raw = analogRead(SOIL_PIN);
    
    // Step 2: Convert to percentage (map raw to 0-100%)
    int moisture = map(raw, DRY_VALUE, WET_VALUE, 0, 100);
    
    // Step 3: Constrain to valid range (0-100%)
    moisture = constrain(moisture, 0, 100);
    
    // Step 4: Display results
    Serial.print("📊 Raw: ");
    Serial.print(raw);
    Serial.print(" | 💧 Moisture: ");
    Serial.print(moisture);
    Serial.println("%");
    
    // Step 5: Make irrigation recommendations
    if (moisture < WATER_NEEDED) {
        Serial.println("⚠️  CRITICAL: SOIL IS DRY - Water immediately!");
        // To automate: digitalWrite(RELAY_PIN, LOW); // Turn pump ON
    } 
    else if (moisture > TOO_WET) {
        Serial.println("✅ Soil is wet - Stop watering, check drainage if persists");
        // To automate: digitalWrite(RELAY_PIN, HIGH); // Turn pump OFF
    } 
    else if (moisture < 45) {
        Serial.println("🟡 Soil is drying - Prepare to water soon");
    }
    else {
        Serial.println("✅ Soil moisture is adequate");
    }
    
    Serial.println("----------------------------------------");
    
    // Wait 60 seconds before next reading (saves battery)
    delay(60000);
}
    

📊 Code Explanation: Line by Line

  • analogRead(SOIL_PIN) - Reads voltage from sensor (0-3.3V → 0-4095 on ESP32)
  • map(raw, DRY_VALUE, WET_VALUE, 0, 100) - Converts raw reading to percentage. Example: 3800 (dry) → 0%, 1500 (wet) → 100%
  • constrain(moisture, 0, 100) - Ensures value never goes below 0% or above 100%
  • if (moisture < 30) - Alert when soil is too dry (most crops need water below 30%)
  • if (moisture > 80) - Alert when soil is too wet (risk of root rot)
  • delay(60000) - Wait 1 minute between readings (adjust for your needs)

📖 MicroPython Version for Raspberry Pi Pico W

# Soil Moisture Sensor for Raspberry Pi Pico W
# Uses ADC0 (GP26) which reads 0-3.3V → 0-65535

from machine import Pin, ADC
import time

# Initialize ADC on GP26 (pin 31)
moisture_sensor = ADC(Pin(26))  # GP26 is ADC0

# CALIBRATION VALUES - REPLACE WITH YOUR READINGS!
DRY_VALUE = 60000   # Reading in dry air (ex: 55000-65535)
WET_VALUE = 20000   # Reading in water (ex: 10000-25000)

def read_soil_moisture():
    """Read soil moisture and return percentage"""
    raw = moisture_sensor.read_u16()  # Returns 0-65535
    # Calculate percentage
    percent = 100 - ((raw - WET_VALUE) * 100 / (DRY_VALUE - WET_VALUE))
    # Constrain to 0-100%
    percent = max(0, min(100, percent))
    return raw, percent

print("💧 Soil Moisture Monitor Started")
print("=" * 40)

while True:
    raw, moisture = read_soil_moisture()
    
    print(f"Raw: {raw:5d} | Moisture: {moisture:.1f}%")
    
    if moisture < 30:
        print("⚠️  SOIL DRY - Water now!")
    elif moisture > 80:
        print("✅ Soil wet - No watering needed")
    
    print("-" * 40)
    time.sleep(60)  # Read every minute
    

📐 Calibration Process (Important!)

Every sensor is different! You MUST calibrate yours for accurate readings:

📋 Step-by-Step Calibration:
  1. Find DRY_VALUE: Place sensor in dry air (not touching soil). Run code and note the reading after 30 seconds. Write it down: DRY_VALUE = _______
  2. Find WET_VALUE: Submerge sensor completely in a glass of water. Run code and note the reading after 30 seconds. Write it down: WET_VALUE = _______
  3. Update code: Replace the DRY_VALUE and WET_VALUE constants with YOUR readings.
  4. Test: Insert sensor into moist soil. The percentage should read between 30-70%.

🌱 Application: Automating Irrigation

Once your sensor is calibrated, use it to control a water pump automatically:

// Add a relay to control a water pump
#define RELAY_PIN 5

void setup() {
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, HIGH);  // Pump starts OFF
}

void loop() {
    int moisture = readSoilMoisture();  // Your moisture reading
    
    if (moisture < 30) {
        digitalWrite(RELAY_PIN, LOW);   // Turn pump ON
        delay(60000);                    // Water for 1 minute
        digitalWrite(RELAY_PIN, HIGH);  // Turn pump OFF
    }
    delay(60000);
}
    
📖 Real Success Story - Kenya:

A tomato farmer installed capacitive soil moisture sensors with ESP32. After calibration, the system automatically watered when moisture dropped below 30%. Results after 3 months:

  • 💧 Water usage decreased by 38%
  • 📈 Tomato yield increased by 28%
  • 💰 Saved $45 per month on water bills
  • 🌱 Healthier plants with no over-watering

"The sensors paid for themselves in the first month!" - Farm owner, Kenya

✅ Quick Reference: Soil Moisture Levels by Crop

Crop Ideal Moisture % Water Below % Too Wet Above %
Tomatoes65-80%55%85%
Maize/Corn60-75%50%80%
Vegetables (leafy)70-85%60%88%
Wheat55-70%45%75%
Onions/Garlic50-65%40%70%
⚠️ Common Mistakes to Avoid:
  • Forgetting to calibrate: Using default values will give inaccurate readings
  • ESP8266 without voltage divider: Will damage your board (max 1V on ADC!)
  • Water directly on electronics: Keep the circuit board above water, only submerge the probe
  • Reading too frequently: Every minute is fine. Every second will overload your sensor
💡 Key Takeaways:
  • Apply these concepts directly to your farm or project.
  • Take notes on important details for the quiz.
  • Use the button below to track your progress.