263 lines
7.9 KiB
Python
Executable File
263 lines
7.9 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Weather Module v2 - With Database Storage
|
|
Tracks weather history for performance analysis
|
|
"""
|
|
import requests
|
|
from datetime import datetime
|
|
import sqlite3
|
|
|
|
DB_PATH = "/home/h3r7/turf_scraper/turf.db"
|
|
|
|
# Hippodrome coordinates
|
|
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),
|
|
'lyon': (45.7378, 4.8092),
|
|
'marseille': (43.2964, 5.3695),
|
|
'cagnes': (43.6689, 7.1914),
|
|
'le croise larroche': (50.6692, 3.0775),
|
|
'mons': (50.4547, 3.9522),
|
|
}
|
|
|
|
def init_weather_db():
|
|
"""Initialize weather table"""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
c = conn.cursor()
|
|
|
|
c.execute('''
|
|
CREATE TABLE IF NOT EXISTS weather (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
date TEXT NOT NULL,
|
|
hippodrome TEXT,
|
|
temperature REAL,
|
|
humidity INTEGER,
|
|
wind_speed REAL,
|
|
precipitation REAL,
|
|
weather_code INTEGER,
|
|
ground_condition TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
c.execute('''
|
|
CREATE TABLE IF NOT EXISTS horse_weather_performance (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
date TEXT,
|
|
race_date TEXT,
|
|
horse_name TEXT,
|
|
position INTEGER,
|
|
hippodrome TEXT,
|
|
temperature REAL,
|
|
ground_condition TEXT,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
)
|
|
''')
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
print("Weather tables initialized!")
|
|
|
|
def get_weather(hippodrome, date=None):
|
|
"""Get weather from Open-Meteo API"""
|
|
hippo_key = hippodrome.lower().strip()
|
|
|
|
# Try to find matching hippodrome
|
|
coords = None
|
|
for name, coord in HIPPODROMES.items():
|
|
if name in hippo_key or hippo_key in name:
|
|
coords = coord
|
|
break
|
|
|
|
if not coords:
|
|
return {'error': f'Hippodrome non trouvé: {hippodrome}'}
|
|
|
|
lat, lon = coords
|
|
|
|
url = "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',
|
|
'timezone': 'Europe/Paris'
|
|
}
|
|
|
|
try:
|
|
r = requests.get(url, params=params, timeout=10)
|
|
data = r.json()
|
|
|
|
if 'current' in data:
|
|
current = data['current']
|
|
weather = {
|
|
'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'),
|
|
'ground_condition': get_ground_condition(current),
|
|
'timestamp': datetime.now().isoformat()
|
|
}
|
|
return weather
|
|
|
|
except Exception as e:
|
|
return {'error': str(e)}
|
|
|
|
return {'error': 'Unknown error'}
|
|
|
|
def get_ground_condition(weather_data):
|
|
"""Determine ground condition"""
|
|
if isinstance(weather_data, dict):
|
|
precip = weather_data.get('precipitation', 0)
|
|
else:
|
|
precip = 0
|
|
|
|
if precip > 10:
|
|
return 'TRES_LOURD'
|
|
elif precip > 5:
|
|
return 'LOURD'
|
|
elif precip > 1:
|
|
return 'SOUPLE'
|
|
else:
|
|
return 'BON'
|
|
|
|
def weather_code_to_desc(code):
|
|
"""Weather code to description"""
|
|
codes = {
|
|
0: "Ciel dégagé", 1: "Mainly clear", 2: "Partly cloudy", 3: "Overcast",
|
|
45: "Brouillard", 48: "Brouillard",
|
|
51: "Bruine légère", 53: "Bruine", 55: "Bruine dense",
|
|
61: "Pluie légère", 63: "Pluie", 65: "Pluie forte",
|
|
71: "Neige légère", 73: "Neige", 75: "Neige forte",
|
|
80: "Averses", 81: "Averses", 82: "Averses fortes",
|
|
95: "Orage", 96: "Orage grêle",
|
|
}
|
|
return codes.get(code, f"Code {code}")
|
|
|
|
def save_weather(date, hippodrome, weather):
|
|
"""Save weather to database"""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
c = conn.cursor()
|
|
|
|
c.execute('''
|
|
INSERT INTO weather (date, hippodrome, temperature, humidity, wind_speed, precipitation, weather_code, ground_condition)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
''', (
|
|
date,
|
|
hippodrome,
|
|
weather.get('temperature'),
|
|
weather.get('humidity'),
|
|
weather.get('wind_speed'),
|
|
weather.get('precipitation'),
|
|
weather.get('weather_code'),
|
|
weather.get('ground_condition')
|
|
))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
print(f"Weather saved: {hippodrome} - {weather.get('ground_condition')}")
|
|
|
|
def save_horse_weather_performance(date, race_date, horse_name, position, hippodrome, temperature, ground_condition):
|
|
"""Save horse performance with weather"""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
c = conn.cursor()
|
|
|
|
c.execute('''
|
|
INSERT INTO horse_weather_performance (date, race_date, horse_name, position, hippodrome, temperature, ground_condition)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
''', (date, race_date, horse_name, position, hippodrome, temperature, ground_condition))
|
|
|
|
conn.commit()
|
|
conn.close()
|
|
|
|
def get_horse_weather_stats(horse_name):
|
|
"""Get horse performance by weather conditions"""
|
|
conn = sqlite3.connect(DB_PATH)
|
|
c = conn.cursor()
|
|
|
|
c.execute('''
|
|
SELECT
|
|
ground_condition,
|
|
COUNT(*) as races,
|
|
SUM(CASE WHEN position <= 3 THEN 1 ELSE 0 END) as podiums,
|
|
ROUND(CAST(SUM(CASE WHEN position <= 3 THEN 1 ELSE 0 END) AS FLOAT) / COUNT(*) * 100, 1) as podium_rate
|
|
FROM horse_weather_performance
|
|
WHERE horse_name = ?
|
|
GROUP BY ground_condition
|
|
''', (horse_name,))
|
|
|
|
results = c.fetchall()
|
|
conn.close()
|
|
|
|
stats = {}
|
|
for row in results:
|
|
stats[row[0]] = {
|
|
'races': row[1],
|
|
'podiums': row[2],
|
|
'podium_rate': row[3]
|
|
}
|
|
|
|
return stats
|
|
|
|
def analyze_weather_advantage(horse_name):
|
|
"""Analyze horse performance by weather"""
|
|
stats = get_horse_weather_stats(horse_name)
|
|
|
|
if not stats:
|
|
return {'message': 'Pas de données météo pour ce cheval'}
|
|
|
|
# Find best ground condition
|
|
best = None
|
|
best_rate = 0
|
|
for condition, data in stats.items():
|
|
if data['podium_rate'] > best_rate:
|
|
best_rate = data['podium_rate']
|
|
best = condition
|
|
|
|
return {
|
|
'horse': horse_name,
|
|
'best_ground': best,
|
|
'best_rate': best_rate,
|
|
'all_conditions': stats
|
|
}
|
|
|
|
# Test
|
|
if __name__ == "__main__":
|
|
init_weather_db()
|
|
|
|
print("\n" + "="*50)
|
|
print("WEATHER MODULE v2 - TEST")
|
|
print("="*50)
|
|
|
|
# Get weather for today's races
|
|
hippodromes = ['Auteuil', 'Vincennes', 'Pau', 'Cagnes-sur-Mer']
|
|
today = datetime.now().strftime('%Y-%m-%d')
|
|
|
|
for hippo in hippodromes:
|
|
w = get_weather(hippo)
|
|
if 'error' not in w:
|
|
print(f"\n{hippo}:")
|
|
print(f" {w.get('temperature')}°C, {w.get('humidity')}%, {w.get('wind_speed')} km/h")
|
|
print(f" Terrain: {w.get('ground_condition')}")
|
|
save_weather(today, hippo, w)
|
|
|
|
# Test horse weather analysis
|
|
print("\n" + "="*50)
|
|
print("HORSE WEATHER ANALYSIS TEST")
|
|
print("="*50)
|
|
|
|
# Save some test data
|
|
save_horse_weather_performance(today, today, 'PASSIONATA', 1, 'Auteuil', 13, 'BON')
|
|
save_horse_weather_performance(today, today, 'PASSIONATA', 2, 'Vincennes', 10, 'SOUPLE')
|
|
|
|
result = analyze_weather_advantage('PASSIONATA')
|
|
print(f"\nPASSIONATA: {result}")
|