OC
OceanRemote
Low-code IoT platform
← Back to Course

Understanding Soil Moisture Thresholds

Understanding Soil Moisture Thresholds

πŸ“Š Understanding Soil Moisture Thresholds - The Science of Smart Irrigation

🌱 What You'll Learn in This Lesson:

  • πŸ“Š Understand Field Capacity (FC) and Permanent Wilting Point (PWP)
  • πŸ’§ Calculate Available Water Capacity (AWC) for your soil type
  • 🎯 Determine the perfect time to start and stop irrigation
  • 🌾 Apply crop-specific thresholds for 15+ African crops
  • πŸ’» Program your ESP32 with optimal soil moisture ranges

πŸ“ˆ The Three Critical Soil Moisture Thresholds

πŸ’§

Field Capacity (FC)

Typical range: 60-80% on capacitive sensors

The maximum amount of water soil can hold against gravity. After heavy rain or irrigation, excess water drains away, leaving soil at Field Capacity. Plants can easily extract water at this level.

πŸ’‘ Example: After 1 hour of watering, soil reaches 70% (FC). Stop irrigation here!
πŸ₯€

Permanent Wilting Point (PWP)

Typical range: 20-30% on capacitive sensors

The moisture level where plants can no longer extract water from soil. Below this point, plants will wilt permanently and die - even if you water them later, the damage is irreversible.

⚠️ NEVER let soil drop below PWP! For most crops, this is 20-25%.
🎯

Management Allowed Depletion (MAD)

Ideal trigger: 40-50% depletion

The optimal point to START irrigation. This is when plants have used 40-50% of available water - before they experience stress, but early enough to prevent wilting.

βœ… Best practice: Start watering when moisture drops to 30-35% (MAD point).

πŸ“Š Understanding Available Water Capacity (AWC)

πŸ“ Formula:

Available Water = Field Capacity (FC) - Permanent Wilting Point (PWP)

Example: If FC = 70% and PWP = 25%, then Available Water = 45%

When available water drops to 50% (MAD), you should irrigate: 50% of 45% = 22.5% depletion β†’ irrigate at 70% - 22.5% = 47.5% soil moisture

🌾 Soil Type Effects on Field Capacity

Soil Type Field Capacity (FC) Wilting Point (PWP) Available Water MAD Trigger
🏜️ Sandy Soil 35-45% 10-15% 25-30% Water at 25-28% (needs frequent irrigation)
🌾 Loamy Soil (Best!) 60-75% 20-25% 40-50% Water at 35-40% (ideal)
🧴 Clay Soil 75-85% 30-35% 40-50% Water at 50-55% (holds water longer)
πŸͺ¨ Sandy Loam 45-60% 15-20% 30-40% Water at 30-35%
πŸ’‘ How to Determine Your Soil Type:

Take a handful of moist soil and squeeze it:

  • Sandy: Falls apart immediately, feels gritty
  • Loamy: Forms a ball that breaks apart easily - BEST for farming!
  • Clay: Forms a tight ball that stays together, feels smooth

πŸ“Š Crop-Specific Thresholds for African Farmers

Crop Start Watering (%) Stop Watering (%) MAD (%) Critical Below (%) Sensitivity
🌽 Maize/Corn45-50%70-75%55%25%Medium
πŸ… Tomatoes50-55%75-80%50%30%High
🌢️ Peppers50-55%75-80%50%30%High
πŸ₯¬ Cabbage55-60%80-85%45%35%Very High
🌾 Wheat40-45%65-70%60%20%Low
πŸ₯” Potatoes45-50%70-75%55%25%Medium
πŸ§… Onions35-40%60-65%65%20%Low (drought tolerant)
πŸ₯• Carrots40-45%65-70%60%25%Medium
πŸ† Eggplant45-50%70-75%55%30%Medium
πŸ‰ Watermelon40-45%65-70%60%25%Low
🌿 Beans40-45%65-70%60%25%Medium
πŸ“ Strawberries50-55%75-80%50%35%Very High
🌻 Sunflower35-40%60-65%65%20%Low
🌾 Sorghum30-35%55-60%70%15%Very Low (drought tolerant)
πŸ₯œ Groundnuts35-40%60-65%65%20%Low
🌿 Cotton40-45%65-70%60%25%Medium
πŸ’‘ Growth Stage Adjustments:

Adjust thresholds based on crop development:

  • 🌱 Seedling/Early growth: Keep moisture HIGH (add 5-10% to thresholds) - roots are shallow
  • 🌿 Vegetative growth: Normal thresholds - plant is establishing
  • 🌾 Flowering/Fruiting: Keep moisture HIGH (add 5% to thresholds) - critical period!
  • πŸ… Ripening/Harvest: Reduce moisture (subtract 5-10%) - stress can improve flavor

πŸ’» Arduino Code: Smart Threshold-Based Irrigation

/*
 * Smart Irrigation Using Soil Moisture Thresholds
 * Implements Field Capacity, Wilting Point, and MAD
 * 
 * Features:
 * - Crop-specific thresholds
 * - Growth stage adjustment
 * - Automatic irrigation based on MAD
 * - Alerts for critical conditions
 */

#include 

// ========== PIN DEFINITIONS ==========
#define SOIL_PIN 32
#define RELAY_PIN 5

// ========== SOIL CALIBRATION (CALIBRATE THESE!) ==========
const int DRY_VALUE = 3800;   // Sensor in dry air
const int WET_VALUE = 1500;   // Sensor in water

// ========== SOIL THRESHOLDS (Based on your soil type) ==========
const float FIELD_CAPACITY = 70.0;      // FC: 70% (after watering)
const float WILTING_POINT = 25.0;       // PWP: 25% (plants die)
const float AVAILABLE_WATER = FIELD_CAPACITY - WILTING_POINT;  // 45%

// ========== CROP CONFIGURATION ==========
struct CropConfig {
    const char* name;
    float mad;                    // Management Allowed Depletion (50-70%)
    float moistureTarget;         // Calculate: FC - (AVC * MAD/100)
    float criticalPoint;          // Below this = emergency!
};

// Pre-calculated thresholds for common crops
CropConfig crops[] = {
    {"Tomatoes", 50, FIELD_CAPACITY - (AVAILABLE_WATER * 0.50), 30},
    {"Maize", 55, FIELD_CAPACITY - (AVAILABLE_WATER * 0.55), 25},
    {"Peppers", 50, FIELD_CAPACITY - (AVAILABLE_WATER * 0.50), 30},
    {"Cabbage", 45, FIELD_CAPACITY - (AVAILABLE_WATER * 0.45), 35},
    {"Onions", 65, FIELD_CAPACITY - (AVAILABLE_WATER * 0.65), 20},
    {"Potatoes", 55, FIELD_CAPACITY - (AVAILABLE_WATER * 0.55), 25},
    {"Beans", 60, FIELD_CAPACITY - (AVAILABLE_WATER * 0.60), 25},
    {"Sorghum", 70, FIELD_CAPACITY - (AVAILABLE_WATER * 0.70), 15}
};

int currentCrop = 0;  // Index of selected crop
int growthStage = 2;   // 1=Seedling, 2=Vegetative, 3=Flowering, 4=Ripening

// ========== READ SOIL MOISTURE ==========
float readSoilMoisture() {
    int raw = analogRead(SOIL_PIN);
    float moisture = map(raw, DRY_VALUE, WET_VALUE, 0, 100);
    return constrain(moisture, 0, 100);
}

// ========== GET GROWTH STAGE ADJUSTMENT ==========
float getGrowthStageAdjustment() {
    switch(growthStage) {
        case 1: return 8.0;   // Seedling: +8% (keep wetter)
        case 2: return 0.0;   // Vegetative: normal
        case 3: return 5.0;   // Flowering: +5% (critical)
        case 4: return -5.0;  // Ripening: -5% (stress for flavor)
        default: return 0.0;
    }
}

// ========== DETERMINE IRRIGATION ACTION ==========
String getIrrigationAction(float moisture, CropConfig crop, float growthAdj) {
    float adjustedTarget = crop.moistureTarget + growthAdj;
    float adjustedCritical = crop.criticalPoint + growthAdj;
    
    if (moisture <= adjustedCritical) {
        return "🚨 CRITICAL: EMERGENCY IRRIGATION! Soil below critical point!";
    } else if (moisture <= adjustedTarget) {
        return "πŸ’§ IRRIGATE: Soil below MAD threshold. Starting irrigation...";
    } else if (moisture >= FIELD_CAPACITY) {
        return "⏸️ STOP: Soil at Field Capacity. Stop irrigation!";
    } else {
        return "βœ… OK: Soil moisture adequate. No action needed.";
    }
}

// ========== CALCULATE WATER NEEDED ==========
int calculateWaterNeeded(float moisture, CropConfig crop, float growthAdj) {
    float adjustedTarget = crop.moistureTarget + growthAdj;
    
    if (moisture <= adjustedTarget) {
        // Calculate how much water to add
        float deficit = FIELD_CAPACITY - moisture;
        int duration = (deficit / 20.0) * 300;  // Rough guide: 20% deficit = 5 minutes
        
        // Ensure reasonable limits
        duration = constrain(duration, 180, 1200);  // 3-20 minutes
        return duration;
    }
    return 0;
}

// ========== DISPLAY COMPLETE REPORT ==========
void displaySoilReport(float moisture, CropConfig crop, float growthAdj) {
    float adjustedTarget = crop.moistureTarget + growthAdj;
    float adjustedCritical = crop.criticalPoint + growthAdj;
    
    Serial.println("\n╔══════════════════════════════════════════════════════════════╗");
    Serial.println("β•‘              πŸ“Š SOIL MOISTURE THRESHOLD REPORT               β•‘");
    Serial.println("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•");
    
    Serial.println("\n🌱 CROP INFORMATION:");
    Serial.printf("   Crop: %s\n", crop.name);
    Serial.printf("   Growth Stage: ");
    switch(growthStage) {
        case 1: Serial.println("Seedling (keep wetter +8%)"); break;
        case 2: Serial.println("Vegetative (normal)");
        case 3: Serial.println("Flowering/Fruiting (critical +5%)");
        case 4: Serial.println("Ripening/Harvest (dry down -5%)");
        default: Serial.println("Unknown");
    }
    
    Serial.println("\nπŸ“Š SOIL THRESHOLDS:");
    Serial.printf("   Field Capacity (FC): %.0f%% (Stop watering here)\n", FIELD_CAPACITY);
    Serial.printf("   Wilting Point (PWP): %.0f%% (CRITICAL - plants die)\n", WILTING_POINT);
    Serial.printf("   MAD Trigger: %.0f%% (Start watering here)\n", adjustedTarget);
    Serial.printf("   Critical Point: %.0f%% (Emergency below this)\n", adjustedCritical);
    
    Serial.println("\nπŸ’§ CURRENT STATUS:");
    Serial.printf("   Current Moisture: %.1f%%\n", moisture);
    
    // Visual gauge
    int bars = moisture / 5;
    Serial.print("   [");
    for (int i = 0; i < 20; i++) {
        if (i < bars) Serial.print("β–ˆ");
        else Serial.print("β–‘");
    }
    Serial.println("]");
    
    Serial.println("\n🎯 DECISION:");
    String action = getIrrigationAction(moisture, crop, growthAdj);
    Serial.printf("   %s\n", action.c_str());
    
    int waterNeeded = calculateWaterNeeded(moisture, crop, growthAdj);
    if (waterNeeded > 0) {
        Serial.printf("   πŸ’§ Recommended watering: %d minutes (%.0f minutes)\n", waterNeeded, waterNeeded/60.0);
    }
    
    Serial.println("\n══════════════════════════════════════════════════════════════\n");
}

void setup() {
    Serial.begin(115200);
    pinMode(SOIL_PIN, INPUT);
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, HIGH);  // Pump OFF initially
    
    Serial.println("═══════════════════════════════════════════");
    Serial.println("πŸ“Š SMART THRESHOLD-BASED IRRIGATION");
    Serial.println("   Field Capacity, Wilting Point & MAD");
    Serial.println("═══════════════════════════════════════════\n");
    
    Serial.println("Crop Selection:");
    for (int i = 0; i < 8; i++) {
        Serial.printf("   %d: %s (MAD: %.0f%%, Target: %.0f%%)\n", i+1, crops[i].name, crops[i].mad, crops[i].moistureTarget);
    }
    
    // Set crop (change this to your crop)
    currentCrop = 0;  // 0 = Tomatoes
    Serial.printf("\nβœ… Selected: %s\n", crops[currentCrop].name);
    Serial.printf("   Start watering at: %.0f%%\n", crops[currentCrop].moistureTarget);
    Serial.printf("   Stop watering at: %.0f%% (Field Capacity)\n\n", FIELD_CAPACITY);
}

void loop() {
    float moisture = readSoilMoisture();
    CropConfig crop = crops[currentCrop];
    float growthAdj = getGrowthStageAdjustment();
    
    displaySoilReport(moisture, crop, growthAdj);
    
    // Decision logic
    float adjustedTarget = crop.moistureTarget + growthAdj;
    
    if (moisture <= adjustedTarget) {
        // Start irrigation
        int duration = calculateWaterNeeded(moisture, crop, growthAdj);
        Serial.printf("πŸ’§ Starting irrigation for %d seconds...\n", duration);
        digitalWrite(RELAY_PIN, LOW);   // Pump ON
        delay(duration * 1000);
        digitalWrite(RELAY_PIN, HIGH);  // Pump OFF
        Serial.println("βœ… Irrigation complete\n");
    } else if (moisture >= FIELD_CAPACITY) {
        Serial.println("⏸️ Soil at Field Capacity - Skipping irrigation\n");
    } else {
        Serial.println("βœ… Soil moisture adequate - Waiting for next check\n");
    }
    
    // Check every 6 hours (21,600,000 ms) or adjust as needed
    delay(21600000);
}
    
πŸ“– Case Study - Tomato Farm Masters Thresholds:

A tomato farm in Tanzania implemented threshold-based irrigation:

  • πŸ“Š Before: Watered daily regardless of soil condition β†’ 25% wasted water
  • πŸ”¬ Measurement: Found Field Capacity = 72%, Wilting Point = 28%
  • 🎯 Threshold: Set MAD at 50% β†’ Start irrigation at 50% moisture
  • πŸ’§ Result: Water usage decreased 35%, tomato yield increased 22%
  • πŸ’° Savings: $200/month + higher quality tomatoes

"Understanding Field Capacity and Wilting Point changed everything. We now water exactly when the plants need it - not on a fixed schedule." - Farm Manager, Tanzania

⚠️ Common Mistake - Over-Watering at Field Capacity:

Many farmers continue irrigating even after soil reaches Field Capacity. This causes:

  • πŸ’§ Water wasted (drains below root zone)
  • πŸ’Έ Fertilizer leaching (washed away)
  • 🌱 Root rot from anaerobic conditions
  • πŸ“ˆ Lower yields (stressed plants)

Solution: Always stop irrigation when moisture reaches 70-80% (Field Capacity)!

πŸŽ‰ Congratulations!

You now understand soil moisture thresholds scientifically!

  • βœ… Field Capacity, Wilting Point, and Available Water explained
  • βœ… Soil type effects (sandy, loamy, clay) with numerical values
  • βœ… Crop-specific thresholds for 15+ African crops
  • βœ… Growth stage adjustments for seedlings, flowering, ripening
  • βœ… Complete Arduino code implementing all thresholds

Next step: Calibrate your specific soil sensor and apply these thresholds!

πŸ“‹ Quick Reference - Threshold Cheat Sheet:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    SOIL MOISTURE THRESHOLD QUICK REFERENCE                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  πŸ”΄ 0-20%: CRITICAL DRY - Plants at Permanent Wilting Point!               β”‚
β”‚      β†’ EMERGENCY IRRIGATION REQUIRED!                                      β”‚
β”‚                                                                             β”‚
β”‚  🟑 20-40%: DRY - Approaching MAD threshold                                β”‚
β”‚      β†’ Plan irrigation within 24-48 hours                                  β”‚
β”‚                                                                             β”‚
β”‚  🟒 40-65%: IDEAL RANGE - Optimal for most crops                           β”‚
β”‚      β†’ Maintain with regular irrigation                                    β”‚
β”‚                                                                             β”‚
β”‚  🟒 65-75%: MOIST - Approaching Field Capacity                             β”‚
β”‚      β†’ Reduce irrigation frequency                                         β”‚
β”‚                                                                             β”‚
β”‚  πŸ”΅ 75-100%: VERY WET - At or above Field Capacity                         β”‚
β”‚      β†’ STOP irrigating! Risk of root rot                                   β”‚
β”‚                                                                             β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  FORMULAS:                                                                  β”‚
β”‚  Available Water = FC - PWP                                                β”‚
β”‚  MAD Trigger = FC - (Available Water Γ— MAD%)                               β”‚
β”‚  Example (Loam): FC=70%, PWP=25%, AWC=45%, MAD=50%                         β”‚
β”‚  β†’ Irrigate at: 70% - (45% Γ— 0.5) = 47.5%                                 β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
πŸ’‘ 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.