| """ |
| Professional Alert Decision Engine |
| =================================== |
| Generates real-time alerts based on weather, pest, and water data |
| Follows climate-resilient agriculture best practices |
| """ |
|
|
| import logging |
| from datetime import datetime |
| from typing import List, Dict, Optional |
|
|
| logger = logging.getLogger("DecisionEngine") |
|
|
| |
| SEVERITY_CRITICAL = "CRITICAL" |
| SEVERITY_HIGH = "HIGH" |
| SEVERITY_MEDIUM = "MEDIUM" |
| SEVERITY_LOW = "LOW" |
| SEVERITY_INFO = "INFO" |
|
|
| def calculate_climate_resilience_score(w_intel: Dict, p_intel: Dict, water_intel: Dict, farmer: Dict) -> Dict: |
| """Calculate comprehensive climate resilience index (0-100)""" |
| |
| score_components = {} |
| |
| |
| curr = w_intel.get("current", {}) |
| temp = curr.get("temp", 25) |
| wind = curr.get("wind", 0) |
| forecast = w_intel.get("forecast", []) |
| |
| weather_score = 30 |
| if temp > farmer.get("threshold_settings", {}).get("temp_high", 40): |
| weather_score -= 15 |
| elif temp < farmer.get("threshold_settings", {}).get("temp_low", 5): |
| weather_score -= 10 |
| |
| if wind > farmer.get("threshold_settings", {}).get("wind_speed", 30): |
| weather_score -= 15 |
| |
| heavy_rain_days = len([d for d in forecast if "heavy" in d.get("description", "").lower()]) |
| if heavy_rain_days > 2: |
| weather_score -= 5 * heavy_rain_days |
| |
| score_components["weather_risk"] = max(0, weather_score) |
| |
| |
| pest_score = 30 |
| for pest in p_intel.get("pest_prediction_table", []): |
| severity = pest.get("severity", "").upper() |
| if severity == "CRITICAL": |
| pest_score -= 15 |
| elif severity == "HIGH": |
| pest_score -= 10 |
| elif severity == "MEDIUM": |
| pest_score -= 5 |
| |
| score_components["pest_risk"] = max(0, pest_score) |
| |
| |
| water_score = 20 |
| irrigation_minutes = water_intel.get("irrigation_minutes", 0) |
| water_m3 = water_intel.get("water_m3_sqm", 0) |
| |
| |
| if irrigation_minutes < 20 or irrigation_minutes > 50: |
| water_score -= 10 |
| |
| score_components["water_risk"] = max(0, water_score) |
| |
| |
| efficiency_score = 20 |
| rain_next_7days = len([d for d in forecast if "rain" in d.get("description", "").lower()]) |
| |
| |
| if rain_next_7days > 2: |
| efficiency_score = 20 |
| elif irrigation_minutes > 40: |
| efficiency_score = 10 |
| |
| score_components["resource_efficiency"] = efficiency_score |
| |
| total_score = sum([score_components["weather_risk"], |
| score_components["pest_risk"], |
| score_components["water_risk"], |
| score_components["resource_efficiency"]]) |
| |
| resilience_level = "π’ GREEN" if total_score >= 75 else "π‘ YELLOW" if total_score >= 50 else "π΄ RED" |
| |
| return { |
| "total_score": total_score, |
| "components": score_components, |
| "resilience_level": resilience_level, |
| "critical_factors": [k for k, v in score_components.items() if v < 15] |
| } |
|
|
| def get_alerts(w_intel: Dict, p_intel: Dict, water_intel: Dict, farmer: Dict) -> List[Dict]: |
| """ |
| Generate actionable alerts with severity levels |
| Returns list of professional farm alerts |
| """ |
| alerts = [] |
| |
| |
| curr = w_intel.get("current", {}) |
| temp = curr.get("temp", 25) |
| humidity = curr.get("humidity", 60) |
| wind = curr.get("wind", 0) |
| forecast = w_intel.get("forecast", []) |
| |
| thresholds = farmer.get("threshold_settings", {}) |
| |
| rain_next_24h = any("rain" in d.get("description", "").lower() for d in forecast[:2]) |
| heavy_rain_forecast = [d for d in forecast if "heavy" in d.get("description", "").lower()] |
| |
| |
| |
| |
| |
| if temp > thresholds.get("temp_high", 40): |
| alerts.append({ |
| "type": "WEATHER", |
| "id": "EXTREME_HEAT", |
| "severity": SEVERITY_CRITICAL, |
| "title": "π‘οΈ EXTREME HEAT WARNING", |
| "message": f"Temperature reached {temp}Β°C. Immediate irrigation required.", |
| "action": "IRRIGATE_IMMEDIATELY", |
| "details": { |
| "current_temp": temp, |
| "threshold": thresholds.get("temp_high", 40), |
| "expected_crop_loss": "25-35%" if temp > 45 else "15-20%", |
| "hydration_urgency": "CRITICAL" |
| }, |
| "action_items": [ |
| f"π¨ Start irrigation within next 30 minutes", |
| "π§ Increase water supply by 20-30%", |
| "π³ Consider temporary shade if available", |
| "π Monitor soil moisture every 2 hours" |
| ] |
| }) |
| |
| if wind > thresholds.get("wind_speed", 30): |
| alerts.append({ |
| "type": "WEATHER", |
| "id": "SEVERE_WIND", |
| "severity": SEVERITY_CRITICAL, |
| "title": "πͺοΈ SEVERE WIND WARNING", |
| "message": f"Wind speed {wind} km/h. High crop damage risk.", |
| "action": "AVOID_ALL_OPERATIONS", |
| "details": { |
| "wind_speed": wind, |
| "risk_level": "CRITICAL", |
| "expected_damage": "Physical damage to plants, fruit drop" |
| }, |
| "action_items": [ |
| "β Stop all spraying and pesticide application", |
| "π§ Secure loose equipment and stakes", |
| "π Postpone harvesting activities", |
| "πΎ Support weak branches with stakes" |
| ] |
| }) |
| |
| if temp < thresholds.get("temp_low", 5): |
| alerts.append({ |
| "type": "WEATHER", |
| "id": "FROST_RISK", |
| "severity": SEVERITY_HIGH, |
| "title": "βοΈ FROST RISK - CROP PROTECTION NEEDED", |
| "message": f"Temperature dropping to {temp}Β°C. Frost damage imminent.", |
| "action": "PROTECT_CROP", |
| "details": { |
| "current_temp": temp, |
| "frost_risk": "HIGH", |
| "vulnerable_stages": "Flowering and young fruits" |
| }, |
| "action_items": [ |
| "π₯ Prepare frost protection measures (smudging/overhead irrigation)", |
| "π¨ Use wind machines if available", |
| "π«οΈ Apply antitranspirants to sensitive crops", |
| "π Contact agricultural extension for emergency support" |
| ] |
| }) |
| |
| |
| |
| |
| |
| if heavy_rain_forecast: |
| alerts.append({ |
| "type": "WEATHER", |
| "id": "HEAVY_RAIN_WARNING", |
| "severity": SEVERITY_HIGH, |
| "title": f"π§οΈ HEAVY RAIN WARNING - {len(heavy_rain_forecast)} days", |
| "message": f"Heavy rainfall expected. Prepare drainage systems.", |
| "action": "PREPARE_DRAINAGE", |
| "details": { |
| "days_affected": len(heavy_rain_forecast), |
| "flooding_risk": "HIGH", |
| "drainage_priority": "URGENT" |
| }, |
| "action_items": [ |
| "π§ Clear all drainage channels and ditches", |
| "π¨ Repair broken drainage pipes immediately", |
| "πͺ΄ Avoid planting in low-lying areas", |
| "βοΈ Test pump systems before heavy rain", |
| "π Monitor water levels in fields" |
| ] |
| }) |
| |
| if not rain_next_24h or wind > thresholds.get("wind_alert", 15): |
| alerts.append({ |
| "type": "SPRAY_OPERATIONS", |
| "id": "UNSAFE_SPRAY_WINDOW", |
| "severity": SEVERITY_HIGH, |
| "title": "π« UNSAFE TO SPRAY", |
| "message": f"Rain or high wind (Wind: {wind} km/h). Postpone spraying.", |
| "action": "POSTPONE_SPRAYING", |
| "details": { |
| "wind_speed": wind, |
| "rain_probability": "HIGH", |
| "spray_loss_rate": "60-70%" |
| }, |
| "action_items": [ |
| "β° Postpone pesticide/fertilizer application", |
| "π
Reschedule for 3-5 days later", |
| "π° Higher wind causes 60-70% spray drift loss", |
| "π Mark postponed tasks for follow-up" |
| ] |
| }) |
| elif not rain_next_24h and wind < thresholds.get("wind_alert", 15): |
| alerts.append({ |
| "type": "SPRAY_OPERATIONS", |
| "id": "OPTIMAL_SPRAY_WINDOW", |
| "severity": SEVERITY_INFO, |
| "title": "β
OPTIMAL SPRAY WINDOW", |
| "message": "Ideal conditions for spraying. Good wind and no rain.", |
| "action": "APPLY_INPUTS", |
| "details": { |
| "wind_speed": wind, |
| "spray_efficiency": "95-98%", |
| "window_duration": "5-7 PM optimal" |
| }, |
| "action_items": [ |
| "β±οΈ Plan spraying activities for 5-7 PM (optimal wind)", |
| "π― Use this window for pesticide/herbicide application", |
| "π‘ Higher efficiency = reduced chemical usage = cost savings", |
| "π Monitor weather updates continuously" |
| ] |
| }) |
| |
| |
| |
| |
| |
| for pest in p_intel.get("pest_prediction_table", []): |
| severity = pest.get("severity", "").upper() |
| pest_name = pest.get("pest_name", "Unknown Pest") |
| confidence = pest.get("confidence", 50) |
| |
| if severity in ["CRITICAL", "HIGH"]: |
| alert_severity = SEVERITY_CRITICAL if severity == "CRITICAL" else SEVERITY_HIGH |
| alerts.append({ |
| "type": "PEST_ALERT", |
| "id": f"PEST_{pest_name.upper().replace(' ', '_')}", |
| "severity": alert_severity, |
| "title": f"π {pest_name.upper()} ALERT", |
| "message": f"High {pest_name} infestation risk detected ({confidence}% confidence).", |
| "action": "PEST_MANAGEMENT", |
| "details": { |
| "pest": pest_name, |
| "risk_level": severity, |
| "confidence": confidence, |
| "favorable_temp": f"{temp}Β°C is {'FAVORABLE' if 20 <= temp <= 30 else 'UNFAVORABLE'} for {pest_name}", |
| "humidity_level": f"Current: {humidity}% - {'High risk' if humidity > 70 else 'Moderate risk'}" |
| }, |
| "action_items": [ |
| f"π Scout fields immediately for {pest_name} symptoms", |
| f"π§ͺ Start bioagent/chemical control within 48 hours", |
| f"πΈ Document infestation level (% affected plants)", |
| f"π Contact agricultural extension for spray recommendations", |
| f"β° Plan early morning or late evening spraying (5-7 PM optimal)" |
| ] |
| }) |
| |
| |
| |
| |
| |
| water_m3 = water_intel.get("water_m3_sqm", 0) |
| irrigation_minutes = water_intel.get("irrigation_minutes", 0) |
| |
| if water_m3 > 0.15 or (temp > 35 and water_m3 > 0.1): |
| alerts.append({ |
| "type": "IRRIGATION", |
| "id": "IMMEDIATE_IRRIGATION_NEEDED", |
| "severity": SEVERITY_CRITICAL if temp > 35 else SEVERITY_HIGH, |
| "title": "π§ IRRIGATION REQUIRED", |
| "message": f"Soil water deficit: {water_m3:.3f} mΒ³. Start irrigation NOW.", |
| "action": "IRRIGATE_IMMEDIATELY", |
| "details": { |
| "water_needed": f"{water_m3:.3f} mΒ³/mΒ²", |
| "irrigation_duration_minutes": round(irrigation_minutes), |
| "soil_moisture_status": "CRITICAL" if water_m3 > 0.15 else "LOW", |
| "temperature_stress": "YES" if temp > 35 else "NO" |
| }, |
| "action_items": [ |
| f"β±οΈ Start irrigation for {round(irrigation_minutes)} minutes", |
| f"π§ Deliver {water_m3:.2f} mΒ³ per mΒ² of field", |
| "π‘οΈ Best timing: Early morning (5-7 AM) or evening (6-8 PM)", |
| "π Check soil moisture after irrigation completion", |
| "π Monitor evapotranspiration for next irrigation schedule" |
| ] |
| }) |
| |
| elif 0.05 < water_m3 <= 0.15: |
| alerts.append({ |
| "type": "IRRIGATION", |
| "id": "IRRIGATION_SCHEDULED", |
| "severity": SEVERITY_MEDIUM, |
| "title": "π§ IRRIGATION SCHEDULED", |
| "message": f"Plan irrigation soon. Water needed: {water_m3:.3f} mΒ³", |
| "action": "SCHEDULE_IRRIGATION", |
| "details": { |
| "water_needed": f"{water_m3:.3f} mΒ³/mΒ²", |
| "irrigation_duration_minutes": round(irrigation_minutes), |
| "best_window": "Next 48-72 hours" |
| }, |
| "action_items": [ |
| f"π
Schedule irrigation in next 2-3 days", |
| f"β±οΈ Duration: {round(irrigation_minutes)} minutes", |
| f"π§ Water quantity: {water_m3:.2f} mΒ³/mΒ²", |
| "π Avoid midday irrigation (high evaporation)", |
| "π§Ή Remove weeds before irrigation (better water use)" |
| ] |
| }) |
| |
| else: |
| alerts.append({ |
| "type": "IRRIGATION", |
| "id": "IRRIGATION_OPTIMAL", |
| "severity": SEVERITY_INFO, |
| "title": "β
SOIL MOISTURE OPTIMAL", |
| "message": "Current soil moisture is adequate. Monitor regularly.", |
| "action": "MONITOR", |
| "details": { |
| "water_status": "OPTIMAL", |
| "next_check": "48 hours" |
| } |
| }) |
| |
| |
| |
| |
| |
| resilience = calculate_climate_resilience_score(w_intel, p_intel, water_intel, farmer) |
| |
| if resilience["total_score"] < 50: |
| alerts.append({ |
| "type": "CLIMATE_RESILIENCE", |
| "id": "LOW_RESILIENCE_ALERT", |
| "severity": SEVERITY_HIGH, |
| "title": "β οΈ LOW CLIMATE RESILIENCE INDEX", |
| "message": f"Farm resilience score: {resilience['total_score']:.0f}/100. Multiple risks detected.", |
| "action": "IMPLEMENT_RESILIENCE_MEASURES", |
| "details": resilience, |
| "action_items": [ |
| "πΎ Implement mulching to reduce water loss 30-40%", |
| "π± Plant nitrogen-fixing legumes for soil health", |
| "π¨ Establish windbreaks for wind protection", |
| "π Diversify crops to reduce single-pest risk", |
| "π° Consider insurance schemes for climate risks" |
| ] |
| }) |
| |
| |
| if irrigation_minutes > 40: |
| alerts.append({ |
| "type": "SUSTAINABILITY", |
| "id": "WATER_CONSERVATION_TIP", |
| "severity": SEVERITY_INFO, |
| "title": "π§ WATER CONSERVATION OPPORTUNITY", |
| "message": "High irrigation need. Implement water-saving techniques.", |
| "action": "CONSERVATION_MEASURE", |
| "details": { |
| "current_irrigation_time": round(irrigation_minutes), |
| "potential_savings": "30-40%" |
| }, |
| "action_items": [ |
| "πΎ Apply mulch (straw/leaves) to reduce evaporation by 40%", |
| "π± Use drip irrigation if available (saves 50% water vs. flood)", |
| "π¨ Install wind breaks to reduce evaporative stress", |
| "π Irrigate early morning (5-7 AM) to minimize evaporation", |
| "π Monitor soil moisture with meter for precision" |
| ] |
| }) |
| else: |
| alerts.append({ |
| "type": "SUSTAINABILITY", |
| "id": "SUSTAINABLE_PRACTICE_TIP", |
| "severity": SEVERITY_INFO, |
| "title": "π SUSTAINABLE FARMING TIP", |
| "message": "Implement intercropping for natural pest control.", |
| "action": "IMPLEMENT_PRACTICE", |
| "details": { |
| "practice": "Intercropping with legumes", |
| "benefit": "30-40% reduction in pest incidence, soil nitrogen boost" |
| }, |
| "action_items": [ |
| "π± Intercrop with legumes (beans, peas) to fix nitrogen", |
| "π Attract pollinators with flowering plants at field edges", |
| "π Encourage beneficial insects (ladybugs, parasitoid wasps)", |
| "β»οΈ Use crop residue for compost instead of burning", |
| "π Expected yield increase: 15-20% with better soil health" |
| ] |
| }) |
| |
| logger.info(f"β
Generated {len(alerts)} alerts for {farmer.get('name', 'Farmer')}") |
| return alerts |
|
|