#!/usr/bin/env python3 """ Weather Module - Open-Meteo API Integration Adds weather context for horse racing analysis """ import requests from datetime import datetime # Hippodrome coordinates (France) HIPPODROMES = { 'auteuil': (48.8718, 2.2525), ' Chantilly': (49.1939, 2.4744), 'deauville': (49.3563, 0.0775), 'vincennes': (48.8414, 2.4375), 'longchamp': (48.8641, 2.2372), 'saint-cloud': (48.8419, 2.1039), 'pau': (43.2917, -0.3708), 'cagnes-sur-mer': (43.6689, 7.1914), 'lyon-parilly': (45.7378, 4.8092), 'marseille': (43.2964, 5.3695), } def get_weather(hippodrome, date=None): """ Get weather for hippodrome from Open-Meteo API (FREE!) Args: hippodrome: Name of hippodrome date: Optional date (YYYY-MM-DD), defaults to today Returns: dict: Weather data """ if hippodrome.lower() not in HIPPODROMES: return {'error': f'Hippodrome not found: {hippodrome}'} lat, lon = HIPPODROMES[hippodrome.lower()] # Open-Meteo API (free, no key needed) url = f"https://api.open-meteo.com/v1/forecast" params = { 'latitude': lat, 'longitude': lon, 'current': 'temperature_2m,relative_humidity_2m,precipitation,rain,weather_code,wind_speed_10m,wind_direction_10m', 'timezone': 'Europe/Paris' } if date: # Historical data url = f"https://archive-api.open-meteo.com/v1/archive" params['start_date'] = date params['end_date'] = date try: r = requests.get(url, params=params, timeout=10) data = r.json() if 'current' in data: current = data['current'] return { 'hippodrome': hippodrome, 'temperature': current.get('temperature_2m'), 'humidity': current.get('relative_humidity_2m'), 'precipitation': current.get('precipitation'), 'rain': current.get('rain'), 'weather_code': current.get('weather_code'), 'wind_speed': current.get('wind_speed_10m'), 'wind_direction': current.get('wind_direction_10m'), 'timestamp': datetime.now().isoformat() } elif 'daily' in data: return { 'hippodrome': hippodrome, 'date': date, 'temperature_max': data['daily'].get('temperature_2m_max', [None])[0], 'temperature_min': data['daily'].get('temperature_2m_min', [None])[0], 'precipitation_sum': data['daily'].get('precipitation_sum', [None])[0], 'rain_sum': data['daily'].get('rain_sum', [None])[0], 'wind_speed_max': data['daily'].get('wind_speed_10m_max', [None])[0], } except Exception as e: return {'error': str(e)} def weather_code_to_desc(code): """Convert weather code to description""" codes = { 0: "Ciel dégagé", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast", 45: "Brouillard", 48: "Fog", 51: "Bruine légère", 53: "Bruine modérée", 55: "Bruine dense", 61: "Pluie légère", 63: "Pluie modérée", 65: "Pluie forte", 71: "Neige légère", 73: "Neige modérée", 75: "Neige forte", 80: "Averses légères", 81: "Averses modérées", 82: "Averses fortes", 95: "Orage", } return codes.get(code, f"Code {code}") def get_ground_condition(weather_data): """ Determine ground condition based on weather Returns: BON, SOUPLE, LOURD, TERRE PERTURBÉE, etc. """ if 'error' in weather_data: return 'INCONNU' precip = weather_data.get('precipitation', 0) rain = weather_data.get('rain', 0) humidity = weather_data.get('humidity', 0) # Simple logic for turf conditions if precip > 10 or rain > 5: return 'LOURD' elif precip > 5 or rain > 2: return 'SOUPLE' elif precip > 1: return 'BON' else: return 'BON' def analyze_weather_impact(weather_data, horse_history): """ Analyze how horse performs in current weather Args: weather_data: Current weather conditions horse_history: List of past performances with weather Returns: dict: Weather impact analysis """ analysis = { 'ground_condition': get_ground_condition(weather_data), 'recommendation': 'NEUTRAL' } # Check ground preference based on history # This would need historical data to be implemented return analysis # Example usage if __name__ == "__main__": # Test print("="*50) print("Weather Module - Test") print("="*50) for hippo in ['Auteuil', 'Vincennes', 'Pau']: print(f"\n{hippo}:") w = get_weather(hippo) if 'error' not in w: print(f" Temp: {w.get('temperature')}°C") print(f" Humidity: {w.get('humidity')}%") print(f" Wind: {w.get('wind_speed')} km/h") print(f" Ground: {get_ground_condition(w)}") else: print(f" Error: {w.get('error')}")