customized_farm_planner / weather_alert_service.py
pranit144's picture
Upload 56 files
429a26d verified
import requests
import json
from datetime import datetime, timedelta
from typing import Dict, List, Optional
import logging
from models import WeatherAlert, Farm, db
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class WeatherAlertService:
"""Service for generating weather-based alerts for farms"""
def __init__(self, weather_api_key: str):
self.weather_api_key = weather_api_key
self.base_url = "http://api.openweathermap.org/data/2.5"
def check_and_generate_alerts(self, farm_id: int) -> List[Dict]:
"""Check weather conditions for a farm and generate alerts if needed"""
try:
farm = Farm.query.get(farm_id)
if not farm or not farm.latitude or not farm.longitude:
logger.warning(f"Farm {farm_id} not found or coordinates missing")
return []
# Get current weather and forecast
current_weather = self._get_current_weather(farm.latitude, farm.longitude)
forecast = self._get_weather_forecast(farm.latitude, farm.longitude)
alerts = []
# Check for various weather conditions
alerts.extend(self._check_rain_alerts(farm, current_weather, forecast))
alerts.extend(self._check_temperature_alerts(farm, current_weather, forecast))
alerts.extend(self._check_wind_alerts(farm, current_weather, forecast))
alerts.extend(self._check_humidity_alerts(farm, current_weather, forecast))
# Save alerts to database
for alert_data in alerts:
existing = WeatherAlert.query.filter_by(
farm_id=farm_id,
alert_type=alert_data['alert_type'],
is_active=True
).first()
if not existing:
alert = WeatherAlert(
farm_id=farm_id,
alert_type=alert_data['alert_type'],
severity=alert_data['severity'],
title=alert_data['title'],
message=alert_data['message'],
recommended_action=alert_data['recommended_action'],
weather_data=json.dumps(alert_data.get('weather_data', {})),
expires_at=datetime.now() + timedelta(hours=24)
)
db.session.add(alert)
db.session.commit()
return alerts
except Exception as e:
logger.error(f"Error generating weather alerts for farm {farm_id}: {str(e)}")
return []
def _get_current_weather(self, lat: float, lon: float) -> Dict:
"""Get current weather data"""
try:
url = f"{self.base_url}/weather"
params = {
'lat': lat,
'lon': lon,
'appid': self.weather_api_key,
'units': 'metric'
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
return response.json()
except Exception as e:
logger.error(f"Error fetching current weather: {str(e)}")
return {}
def _get_weather_forecast(self, lat: float, lon: float) -> Dict:
"""Get 5-day weather forecast"""
try:
url = f"{self.base_url}/forecast"
params = {
'lat': lat,
'lon': lon,
'appid': self.weather_api_key,
'units': 'metric'
}
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
return response.json()
except Exception as e:
logger.error(f"Error fetching weather forecast: {str(e)}")
return {}
def _check_rain_alerts(self, farm: Farm, current: Dict, forecast: Dict) -> List[Dict]:
"""Check for rain-related alerts"""
alerts = []
# Heavy rain alert
if current.get('rain', {}).get('1h', 0) > 10: # More than 10mm/hour
alerts.append({
'alert_type': 'heavy_rain',
'severity': 'high',
'title': 'Heavy Rain Alert',
'message': f'Heavy rainfall detected at {farm.farm_name}. Current rate: {current["rain"]["1h"]:.1f}mm/hour',
'recommended_action': 'Ensure proper drainage, protect harvested crops, avoid field operations',
'weather_data': current
})
# Forecast rain alert
forecast_list = forecast.get('list', [])
for item in forecast_list[:8]: # Next 24 hours
if item.get('rain', {}).get('3h', 0) > 15: # More than 15mm in 3 hours
alerts.append({
'alert_type': 'rain_forecast',
'severity': 'medium',
'title': 'Heavy Rain Expected',
'message': f'Heavy rain expected at {farm.farm_name} in the next 24 hours',
'recommended_action': 'Prepare drainage, postpone irrigation, cover sensitive crops',
'weather_data': item
})
break
return alerts
def _check_temperature_alerts(self, farm: Farm, current: Dict, forecast: Dict) -> List[Dict]:
"""Check for temperature-related alerts"""
alerts = []
temp = current.get('main', {}).get('temp', 0)
# Heat wave alert
if temp > 40:
alerts.append({
'alert_type': 'heat_wave',
'severity': 'high',
'title': 'Extreme Heat Alert',
'message': f'Very high temperature at {farm.farm_name}: {temp:.1f}°C',
'recommended_action': 'Increase irrigation frequency, provide shade for livestock, avoid midday work',
'weather_data': current
})
# Cold wave alert
elif temp < 5:
alerts.append({
'alert_type': 'cold_wave',
'severity': 'high',
'title': 'Cold Wave Alert',
'message': f'Very low temperature at {farm.farm_name}: {temp:.1f}°C',
'recommended_action': 'Protect crops from frost, cover sensitive plants, check irrigation pipes',
'weather_data': current
})
return alerts
def _check_wind_alerts(self, farm: Farm, current: Dict, forecast: Dict) -> List[Dict]:
"""Check for wind-related alerts"""
alerts = []
wind_speed = current.get('wind', {}).get('speed', 0) * 3.6 # Convert m/s to km/h
if wind_speed > 50: # Strong winds
alerts.append({
'alert_type': 'strong_wind',
'severity': 'medium',
'title': 'Strong Wind Alert',
'message': f'Strong winds at {farm.farm_name}: {wind_speed:.1f} km/h',
'recommended_action': 'Secure loose structures, check support for tall crops, avoid spraying',
'weather_data': current
})
return alerts
def _check_humidity_alerts(self, farm: Farm, current: Dict, forecast: Dict) -> List[Dict]:
"""Check for humidity-related alerts"""
alerts = []
humidity = current.get('main', {}).get('humidity', 0)
# High humidity - disease risk
if humidity > 85:
alerts.append({
'alert_type': 'high_humidity',
'severity': 'medium',
'title': 'Disease Risk Alert',
'message': f'High humidity at {farm.farm_name}: {humidity}% - Increased disease risk',
'recommended_action': 'Monitor crops for fungal diseases, improve ventilation, reduce watering',
'weather_data': current
})
return alerts
def get_weather_alerts(self, latitude: float, longitude: float) -> List[Dict]:
"""
Get weather alerts for a location
Args:
latitude: Farm latitude
longitude: Farm longitude
Returns:
List of weather alert dictionaries
"""
try:
# Get current weather and forecast for this location
current_weather = self._get_current_weather(latitude, longitude)
forecast = self._get_weather_forecast(latitude, longitude)
alerts = []
# Generate alerts based on current conditions
if current_weather:
# Temperature alerts
temp = current_weather.get('main', {}).get('temp', 0)
if temp > 40:
alerts.append({
'alert_type': 'extreme_heat',
'severity': 'high',
'title': 'Extreme Heat Warning',
'message': f'Very high temperature: {temp}°C. Protect crops from heat stress.',
'recommendations': 'Increase irrigation, provide shade, harvest early morning',
'created_at': datetime.now().isoformat(),
'is_active': True
})
elif temp < 5:
alerts.append({
'alert_type': 'frost_warning',
'severity': 'high',
'title': 'Frost Warning',
'message': f'Low temperature: {temp}°C. Risk of frost damage.',
'recommendations': 'Cover sensitive crops, use frost protection methods',
'created_at': datetime.now().isoformat(),
'is_active': True
})
# Rain alerts
rain = current_weather.get('rain', {}).get('1h', 0)
if rain > 10:
alerts.append({
'alert_type': 'heavy_rain',
'severity': 'medium',
'title': 'Heavy Rain Alert',
'message': f'Heavy rainfall: {rain}mm/hr. Check drainage systems.',
'recommendations': 'Ensure proper drainage, avoid field operations',
'created_at': datetime.now().isoformat(),
'is_active': True
})
# Wind alerts
wind_speed = current_weather.get('wind', {}).get('speed', 0) * 3.6 # Convert m/s to km/h
if wind_speed > 50:
alerts.append({
'alert_type': 'strong_wind',
'severity': 'medium',
'title': 'Strong Wind Warning',
'message': f'Strong winds: {wind_speed:.1f} km/h. Risk of crop damage.',
'recommendations': 'Secure equipment, check for crop lodging',
'created_at': datetime.now().isoformat(),
'is_active': True
})
# Humidity alerts
humidity = current_weather.get('main', {}).get('humidity', 0)
if humidity > 85:
alerts.append({
'alert_type': 'high_humidity',
'severity': 'medium',
'title': 'High Humidity Alert',
'message': f'High humidity: {humidity}%. Increased disease risk.',
'recommendations': 'Monitor for fungal diseases, improve ventilation',
'created_at': datetime.now().isoformat(),
'is_active': True
})
# Check forecast for upcoming conditions
if forecast and 'list' in forecast:
for item in forecast['list'][:8]: # Check next 24 hours
forecast_temp = item.get('main', {}).get('temp', 0)
forecast_rain = item.get('rain', {}).get('3h', 0)
if forecast_temp > 42:
alerts.append({
'alert_type': 'upcoming_heat',
'severity': 'medium',
'title': 'Upcoming Heat Wave',
'message': f'High temperature expected: {forecast_temp}°C',
'recommendations': 'Prepare heat protection measures, plan irrigation',
'created_at': datetime.now().isoformat(),
'is_active': True
})
break # Only add one forecast alert
if forecast_rain > 15:
alerts.append({
'alert_type': 'upcoming_rain',
'severity': 'medium',
'title': 'Heavy Rain Expected',
'message': f'Heavy rain forecast: {forecast_rain}mm',
'recommendations': 'Postpone spraying, check drainage systems',
'created_at': datetime.now().isoformat(),
'is_active': True
})
break # Only add one forecast alert
return alerts
except Exception as e:
logger.error(f"Error getting weather alerts: {str(e)}")
return []
def get_active_alerts(self, farm_id: int) -> List[WeatherAlert]:
"""Get all active alerts for a farm"""
return WeatherAlert.query.filter_by(
farm_id=farm_id,
is_active=True
).filter(
WeatherAlert.expires_at > datetime.now()
).order_by(WeatherAlert.created_at.desc()).all()
def mark_alert_sent(self, alert_id: int):
"""Mark an alert as sent"""
alert = WeatherAlert.query.get(alert_id)
if alert:
alert.is_sent = True
db.session.commit()