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 |
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 |
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();
}
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
- π 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
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!
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β 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 β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- 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.