OC
OceanRemote
Low-code IoT platform
← Back to Course

Weather Forecast Integration

Weather Forecast Integration

🌀️ Weather Forecast Integration - Smart Irrigation Decision Engine

🌧️ What You'll Learn in This Lesson:

  • 🌀️ Integrate real-time weather forecasts into your irrigation decisions
  • πŸ’§ Save 30-50% water by automatically skipping irrigation before rain
  • 🌑️ Adjust watering based on temperature forecasts
  • πŸ’¨ Account for wind speed in evaporation calculations
  • πŸ€– Build a fully automated weather-aware irrigation system

🌧️ Why Weather Integration Matters

Without Weather Data With Weather Integration
❌ Water before rain β†’ waste water + nutrients leaching βœ… Skip irrigation when rain forecast β†’ save water
❌ Same irrigation on hot vs cool days βœ… Increase water before heat wave, decrease before cool period
❌ No warning for frost or extreme heat βœ… Get alerts before damaging weather arrives
❌ React to problems after they occur βœ… Proactive management based on forecast
πŸ’‘ The Cost of Ignoring Rain Forecasts:

A study of 500 farms showed that farmers who didn't check forecasts before irrigating wasted an average of 15,000 liters per hectare per year - that's $30-50 in water costs and washed-away fertilizer!

πŸ“Š Complete Weather-Integrated Decision Matrix

Soil Moisture Rain Forecast (24h) Temperature Wind Speed Action Water Duration
< 20% (Critical) Any Any Any 🚨 EMERGENCY WATER - Immediate! 20-25 minutes
20-35% (Dry) None or < 5mm Any Any πŸ’§ Water Now 10-15 minutes
20-35% (Dry) β‰₯ 10mm expected Any Any ⏸️ Skip irrigation - rely on rain 0 minutes
35-50% (Adequate) None < 30Β°C < 20 km/h βœ… Monitor only 0 minutes
35-50% (Adequate) None > 35Β°C (Heat wave) Any πŸ’§ Light cooling irrigation 3-5 minutes
35-50% (Adequate) None Any > 30 km/h (High wind) ⚠️ Delay irrigation - high evaporation 0 minutes (wait for calm)
50-70% (Optimal) Any Any Any βœ… No irrigation needed 0 minutes
70-85% (Wet) Any Any Any ⚠️ Stop irrigation - allow drying 0 minutes
> 85% (Flooded) Any Any Any 🚨 CRITICAL - Root rot risk! Improve drainage

🌑️ Weather Parameters That Affect Your Crops

🌧️

Rain Forecast

  • < 5mm: No irrigation adjustment
  • 5-10mm: Reduce irrigation by 50%
  • 10-20mm: Skip irrigation entirely
  • > 20mm: Skip + check drainage after
🌑️

Temperature

  • < 15Β°C: Reduce irrigation by 40%
  • 15-25Β°C: Normal schedule
  • 25-32Β°C: Increase by 20%
  • > 32Β°C: Increase by 40% + cooling
πŸ’¨

Wind Speed

  • < 10 km/h: Normal evaporation
  • 10-20 km/h: Increase water by 15%
  • 20-30 km/h: Increase water by 30%
  • > 30 km/h: Delay irrigation (wind drift)
πŸ’§

Humidity

  • > 80%: Reduce irrigation by 30%
  • 60-80%: Normal schedule
  • 40-60%: Increase by 15%
  • < 40%: Increase by 30%
☁️

Cloud Cover

  • Clear: Highest evaporation (normal)
  • Partly cloudy: Reduce by 10%
  • Overcast: Reduce by 25%
  • Heavy clouds: Reduce by 40%
❄️

Frost Risk

  • Temp < 2Β°C: Frost alert!
  • Action: Irrigate before frost (water releases heat)
  • Cover crops: Use row covers if possible
  • Delay planting: Until frost passes

πŸ“‘ Free Weather APIs for African Farmers

API Provider Free Tier Limit Best For API Key Required
OpenWeatherMap 1,000 calls/day Temperature, humidity, rain, forecast Yes (free)
WeatherAPI.com 5,000 calls/day Agriculture-specific data, soil temp Yes (free)
Open-Meteo Unlimited (no key!) Best for Africa - good coverage No API key needed!
NOAA (US) Unlimited US and global weather models No
πŸ’‘ Recommended for Africa:

Open-Meteo is the best choice for African farmers - no API key required, excellent coverage across the continent, and provides agriculture-specific data including soil moisture and evapotranspiration!

πŸ’» Complete Arduino Code: Weather-Integrated Irrigation

/*
 * Weather-Integrated Smart Irrigation System
 * Uses Open-Meteo API (no API key needed!)
 * Automatically adjusts irrigation based on forecast
 * 
 * Features:
 * - Real-time weather from free API
 * - Rain forecast check (skip watering before rain)
 * - Temperature adjustment
 * - Wind speed compensation
 * - Frost alerts
 */

#include 
#include 
#include 

// ========== WIFI CONFIGURATION ==========
const char* ssid = "YOUR_WIFI";
const char* password = "YOUR_PASSWORD";

// ========== LOCATION (Change to your coordinates!) ==========
const float LATITUDE = -1.286389;   // Nairobi: -1.286389
const float LONGITUDE = 36.817223;  // Nairobi: 36.817223

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

// ========== SOIL MOISTURE CALIBRATION ==========
const int DRY_VALUE = 3800;
const int WET_VALUE = 1500;

// ========== IRRIGATION PARAMETERS ==========
const int BASE_WATER_DURATION = 600;  // 10 minutes base
const int MAX_WATER_DURATION = 1500;  // 25 minutes max
const int MIN_WATER_DURATION = 180;    // 3 minutes min

// ========== WEATHER DATA STRUCTURE ==========
struct WeatherData {
    float temp;           // Current temperature (Β°C)
    float humidity;       // Current humidity (%)
    float rainNext24h;    // Rain forecast for next 24 hours (mm)
    float windSpeed;      // Wind speed (km/h)
    int cloudCover;       // Cloud cover (%)
    bool isRaining;       // Currently raining?
};

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

// ========== FETCH WEATHER FROM OPEN-METEO (FREE, NO API KEY) ==========
WeatherData fetchWeather() {
    WeatherData weather = {0, 0, 0, 0, 0, false};
    
    if (WiFi.status() != WL_CONNECTED) {
        Serial.println("⚠️ WiFi not connected");
        return weather;
    }
    
    HTTPClient http;
    
    // Open-Meteo API URL - provides current weather + forecast
    String url = "https://api.open-meteo.com/v1/forecast?";
    url += "latitude=" + String(LATITUDE, 6);
    url += "&longitude=" + String(LONGITUDE, 6);
    url += "¤t_weather=true";
    url += "&hourly=relativehumidity_2m,rain,windspeed_10m,cloudcover";
    url += "&forecast_days=1";
    
    http.begin(url);
    int httpCode = http.GET();
    
    if (httpCode == 200) {
        String payload = http.getString();
        DynamicJsonDocument doc(4096);
        deserializeJson(doc, payload);
        
        // Current weather
        JsonObject current = doc["current_weather"];
        weather.temp = current["temperature"];
        weather.windSpeed = current["windspeed"];
        weather.isRaining = false; // Will check hourly rain
        
        // Get hourly data for next 24 hours
        JsonArray time = doc["hourly"]["time"];
        JsonArray rain = doc["hourly"]["rain"];
        JsonArray humidity = doc["hourly"]["relativehumidity_2m"];
        JsonArray cloud = doc["hourly"]["cloudcover"];
        
        // Calculate average rain for next 24 hours
        float totalRain = 0;
        float avgHumidity = 0;
        float avgCloud = 0;
        int count = 0;
        
        int currentHour = 0; // Simplified - in production, find current hour index
        
        for (int i = 0; i < 24 && i < rain.size(); i++) {
            totalRain += rain[i].as();
            avgHumidity += humidity[i].as();
            avgCloud += cloud[i].as();
            count++;
        }
        
        if (count > 0) {
            weather.rainNext24h = totalRain;
            weather.humidity = avgHumidity / count;
            weather.cloudCover = avgCloud / count;
        }
        
        Serial.println("βœ… Weather data fetched successfully");
        
    } else {
        Serial.printf("❌ Weather API error: HTTP %d\n", httpCode);
    }
    
    http.end();
    return weather;
}

// ========== CALCULATE WATERING DURATION ==========
int calculateWaterDuration(int moisture, WeatherData weather) {
    int duration = 0;
    
    // BASE: Soil moisture deficit
    if (moisture < 20) {
        duration = MAX_WATER_DURATION;
    } else if (moisture < 35) {
        int deficit = 35 - moisture;
        duration = BASE_WATER_DURATION + (deficit * 15);
        duration = constrain(duration, MIN_WATER_DURATION, MAX_WATER_DURATION);
    }
    
    // ADJUSTMENT 1: Rain forecast - most important!
    if (weather.rainNext24h > 15) {
        duration = 0;  // Skip completely
        Serial.println("   🌧️ Heavy rain forecast - skipping irrigation");
    } else if (weather.rainNext24h > 8) {
        duration = duration * 0.4;  // 60% reduction
        Serial.println("   🌧️ Moderate rain forecast - 60% reduction");
    } else if (weather.rainNext24h > 3) {
        duration = duration * 0.6;  // 40% reduction
        Serial.println("   🌧️ Light rain forecast - 40% reduction");
    }
    
    // ADJUSTMENT 2: Temperature
    if (duration > 0) {
        if (weather.temp > 38) {
            duration = duration * 1.5;  // 50% increase for extreme heat
            Serial.println("   πŸ”₯ Extreme heat - +50% water");
        } else if (weather.temp > 32) {
            duration = duration * 1.25; // 25% increase for heat
            Serial.println("   β˜€οΈ High temperature - +25% water");
        } else if (weather.temp < 15) {
            duration = duration * 0.6;  // 40% reduction for cool
            Serial.println("   ❄️ Cool temperature - 40% reduction");
        }
    }
    
    // ADJUSTMENT 3: Wind speed
    if (duration > 0 && weather.windSpeed > 30) {
        duration = duration * 0;  // Skip if very windy (evaporation + drift)
        Serial.println("   πŸ’¨ High wind - delaying irrigation");
    } else if (weather.windSpeed > 20) {
        duration = duration * 1.2;  // 20% increase for wind evaporation
        Serial.println("   πŸ’¨ Windy - +20% for evaporation");
    }
    
    // ADJUSTMENT 4: Cloud cover
    if (duration > 0 && weather.cloudCover > 80) {
        duration = duration * 0.7;  // 30% reduction - less evaporation
        Serial.println("   ☁️ Heavy clouds - 30% reduction");
    }
    
    // ADJUSTMENT 5: Currently raining
    if (weather.isRaining) {
        duration = 0;
        Serial.println("   🌧️ Currently raining - skipping irrigation");
    }
    
    return constrain(duration, 0, MAX_WATER_DURATION);
}

// ========== FROST ALERT ==========
void checkFrostAlert(WeatherData weather) {
    if (weather.temp < 2) {
        Serial.println("⚠️⚠️⚠️ FROST WARNING ⚠️⚠️⚠️");
        Serial.println("   ❄️ Temperature below 2Β°C detected!");
        Serial.println("   πŸ’§ Irrigate now (water releases heat when freezing)");
        Serial.println("   🌿 Cover sensitive crops if possible");
    } else if (weather.temp < 5) {
        Serial.println("⚠️ FROST RISK: Temperature below 5°C");
        Serial.println("   Monitor closely, prepare for possible frost");
    }
}

// ========== DISPLAY COMPLETE REPORT ==========
void displayReport(int moisture, WeatherData weather, int duration) {
    Serial.println("\n╔══════════════════════════════════════════════════════════════╗");
    Serial.println("β•‘           🌀️ WEATHER-INTEGRATED IRRIGATION REPORT            β•‘");
    Serial.println("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•");
    
    Serial.println("\nπŸ“Š SOIL STATUS:");
    Serial.printf("   πŸ’§ Soil moisture: %d%%\n", moisture);
    if (moisture < 20) Serial.println("   πŸ”΄ CRITICAL: Soil extremely dry!");
    else if (moisture < 35) Serial.println("   🟑 WARNING: Soil drying - irrigation needed");
    else if (moisture > 70) Serial.println("   🟒 GOOD: Soil moisture adequate");
    
    Serial.println("\n🌀️ WEATHER FORECAST (Next 24h):");
    Serial.printf("   🌑️ Temperature: %.1f°C\n", weather.temp);
    Serial.printf("   πŸ’§ Humidity: %.0f%%\n", weather.humidity);
    Serial.printf("   🌧️ Expected rain: %.1f mm\n", weather.rainNext24h);
    Serial.printf("   πŸ’¨ Wind speed: %.1f km/h\n", weather.windSpeed);
    Serial.printf("   ☁️ Cloud cover: %d%%\n", weather.cloudCover);
    
    checkFrostAlert(weather);
    
    Serial.println("\n🎯 DECISION:");
    if (duration > 0) {
        Serial.printf("   πŸ’§ IRRIGATE: %d minutes (%.0f minutes)\n", duration, duration/60.0);
        if (weather.rainNext24h > 0) {
            Serial.printf("   πŸ’‘ Note: %.1fmm rain expected - reduced watering accordingly\n", weather.rainNext24h);
        }
    } else {
        if (weather.rainNext24h > 10) {
            Serial.printf("   ⏸️ SKIP IRRIGATION: %.1fmm rain expected in next 24h\n", weather.rainNext24h);
        } else if (moisture > 50) {
            Serial.println("   βœ… NO IRRIGATION: Soil moisture adequate");
        } else if (weather.windSpeed > 30) {
            Serial.println("   ⏸️ DELAY IRRIGATION: Wind too high (evaporation/drift)");
        } else {
            Serial.println("   βœ… NO ACTION NEEDED");
        }
    }
    
    Serial.println("\n══════════════════════════════════════════════════════════════\n");
}

// ========== EXECUTE IRRIGATION ==========
void irrigate(int durationSeconds) {
    if (durationSeconds <= 0) return;
    
    Serial.printf("πŸ’§ Starting irrigation for %d seconds...\n", durationSeconds);
    digitalWrite(RELAY_PIN, LOW);   // Pump ON (active LOW)
    delay(durationSeconds * 1000);
    digitalWrite(RELAY_PIN, HIGH);  // Pump OFF
    Serial.println("βœ… Irrigation complete\n");
}

void setup() {
    Serial.begin(115200);
    pinMode(SOIL_PIN, INPUT);
    pinMode(RELAY_PIN, OUTPUT);
    digitalWrite(RELAY_PIN, HIGH);  // Pump OFF initially
    
    // Connect to WiFi
    WiFi.begin(ssid, password);
    Serial.print("πŸ“‘ Connecting to WiFi");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("\nβœ… WiFi connected!");
    
    Serial.println("═══════════════════════════════════════════");
    Serial.println("🌀️ WEATHER-INTEGRATED IRRIGATION SYSTEM");
    Serial.println("   Smart watering based on forecast");
    Serial.println("═══════════════════════════════════════════\n");
}

void loop() {
    // Read soil moisture
    int moisture = readSoilMoisture();
    
    // Fetch weather data
    WeatherData weather = fetchWeather();
    
    // Calculate optimal watering duration
    int duration = calculateWaterDuration(moisture, weather);
    
    // Display report
    displayReport(moisture, weather, duration);
    
    // Execute irrigation if needed
    if (duration > 0) {
        irrigate(duration);
    }
    
    // Wait before next check (default: 4 hours = 14,400,000 ms)
    // Longer delay saves API calls and battery
    delay(14400000);
}
    

πŸ“± Weather API Integration with OceanRemote

/*
 * Send weather-integrated decisions to OceanRemote
 * Monitor irrigation decisions from anywhere
 */

void sendDecisionToCloud(int moisture, WeatherData weather, int duration) {
    if (WiFi.status() != WL_CONNECTED) return;
    
    HTTPClient http;
    http.begin("https://api.oceanremote.net/device/state");
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    String data = "token=YOUR_TOKEN";
    data += "&soil_moisture=" + String(moisture);
    data += "&temperature=" + String(weather.temp);
    data += "&rain_forecast=" + String(weather.rainNext24h);
    data += "&irrigation_duration=" + String(duration);
    data += "&irrigation_decision=";
    
    if (duration > 0) {
        data += "IRRIGATING";
    } else if (weather.rainNext24h > 10) {
        data += "SKIP_RAIN";
    } else {
        data += "SKIP_ADEQUATE";
    }
    
    http.POST(data);
    http.end();
}
    
πŸ“– Case Study - Weather Integration Saves Water in Kenya:

A potato farm in Kinungi, Kenya installed weather-integrated irrigation:

  • πŸ“Š Before: Fixed irrigation schedule - watered every 3 days regardless
  • 🌧️ Problem: Often irrigated just before heavy rain β†’ waste
  • πŸ”§ Solution: Weather API skipped irrigation when rain forecast > 10mm
  • πŸ’§ Result: 35% reduction in water usage (saved 2,000 mΒ³/month)
  • πŸ’° Savings: $180/month on water + reduced fertilizer leaching

"The weather integration paid for itself in the first month. Now we never water before rain!" - Farm Manager, Kinungi

πŸ’‘ Pro Tips for Weather Integration:
  • πŸ“ Check forecast in morning: Make irrigation decisions before 8 AM daily
  • πŸ“ Use multiple sources: Compare 2-3 weather apps for accuracy
  • πŸ“ Install a rain gauge: Physical verification of forecast accuracy
  • πŸ“ Adjust by season: Rainy season vs dry season thresholds differ
  • πŸ“ Monitor API limits: Check forecast every 4-6 hours, not every minute
πŸŽ‰ Congratulations!

You can now integrate weather forecasts into your irrigation decisions!

  • βœ… Fetch real-time weather using free APIs (no key needed!)
  • βœ… Adjust irrigation based on rain forecast (save 30-50% water)
  • βœ… Compensate for temperature, wind, and cloud cover
  • βœ… Get frost alerts before crop damage occurs
  • βœ… Build a fully automated weather-aware farm

Next step: Combine with soil moisture sensors for ultimate precision!

πŸ“‹ Quick Reference - Weather Adjustment Factors:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    WEATHER ADJUSTMENT FACTORS                               β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                             β”‚
β”‚  🌧️ RAIN FORECAST (Most Important!)                                        β”‚
β”‚     β€’ > 15mm forecast  β†’ SKIP irrigation entirely                          β”‚
β”‚     β€’ 8-15mm forecast  β†’ 60% reduction                                     β”‚
β”‚     β€’ 3-8mm forecast   β†’ 40% reduction                                     β”‚
β”‚                                                                             β”‚
β”‚  🌑️ TEMPERATURE                                                            β”‚
β”‚     β€’ > 38Β°C (Extreme) β†’ +50% water                                        β”‚
β”‚     β€’ 32-38Β°C (Hot)    β†’ +25% water                                        β”‚
β”‚     β€’ 15-25Β°C (Ideal)  β†’ Normal                                            β”‚
β”‚     β€’ < 15Β°C (Cool)    β†’ -40% water                                        β”‚
β”‚                                                                             β”‚
β”‚  πŸ’¨ WIND SPEED                                                              β”‚
β”‚     β€’ > 30 km/h        β†’ SKIP (evaporation/drift)                          β”‚
β”‚     β€’ 20-30 km/h       β†’ +20% water                                        β”‚
β”‚     β€’ < 20 km/h        β†’ Normal                                            β”‚
β”‚                                                                             β”‚
β”‚  ☁️ CLOUD COVER                                                             β”‚
β”‚     β€’ > 80% (Heavy)    β†’ -30% water                                        β”‚
β”‚     β€’ 50-80% (Medium)  β†’ -15% water                                        β”‚
β”‚     β€’ < 50% (Clear)    β†’ Normal                                            β”‚
β”‚                                                                             β”‚
β”‚  ❄️ FROST ALERT                                                             β”‚
β”‚     β€’ Temp < 2Β°C       β†’ ALERT! Irrigate before frost                       β”‚
β”‚     β€’ Temp < 5Β°C       β†’ Monitor closely                                    β”‚
β”‚                                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
πŸ’‘ 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.