""" Script voor het INCREMENTEEL ophalen van weerdata voor Amersfoort en dit direct in MySQL op te slaan (met 'Upsert' logica). Het vult de database aan vanaf de laatst bekende datum tot NU. """ import requests import mysql.connector from mysql.connector import Error import pandas as pd from datetime import datetime, timedelta import time # ===== CONFIGURATIE ===== LOCATIE = "Amersfoort" LATITUDE = 52.15 LONGITUDE = 5.39 # --- MySQL Database Config --- # VUL DIT IN MET JOUW GEGEVENS DB_CONFIG = { 'host': '192.168.178.201', 'user': 'energy_prices_user', 'password': 'kS9R*xp17ZwCD@CV&E^N', 'database': 'energy_prices', 'port': 3307 } # ======================== def haal_recente_weerdata_op(aantal_dagen_terug): """ Haal recente/huidige weerdata op via de Open-Meteo FORECAST API """ url = "https://api.open-meteo.com/v1/forecast" # Dit is de Forecast API params = { "latitude": LATITUDE, "longitude": LONGITUDE, "hourly": [ "temperature_2m", "apparent_temperature", "precipitation", "wind_speed_10m", "wind_direction_10m", "relative_humidity_2m", "cloud_cover", "surface_pressure" ], "timezone": "Europe/Amsterdam", "past_days": int(aantal_dagen_terug) # Vraag data op van de afgelopen X dagen } print(f"\nšŸ“” Data ophalen voor de afgelopen {aantal_dagen_terug} dagen (tot nu)...") try: response = requests.get(url, params=params, timeout=60) response.raise_for_status() print(f"āœ… Data succesvol opgehaald van Open-Meteo!") return response.json() except requests.exceptions.RequestException as e: print(f"āŒ Fout bij ophalen data: {e}") return None def parse_api_data(data): """Converteer de JSON response van de Forecast API naar een DataFrame""" hourly = data['hourly'] df = pd.DataFrame({ "datum_tijd": pd.to_datetime(hourly['time']), "locatie": LOCATIE, "temperatuur": hourly['temperature_2m'], "gevoelstemperatuur": hourly['apparent_temperature'], "neerslag": hourly['precipitation'], "wind_snelheid": hourly['wind_speed_10m'], "wind_richting": hourly['wind_direction_10m'], "luchtvochtigheid": hourly['relative_humidity_2m'], "bewolking": hourly['cloud_cover'], "luchtdruk": hourly['surface_pressure'] }) # Vervang 'None' of 'NaN' door None (dat MySQL als NULL begrijpt) df = df.where(pd.notnull(df), None) return df def sla_data_op_mysql(conn, data_df): """Sla data op in MySQL database met 'Upsert' logica""" if data_df.empty: print("Geen data om op te slaan.") return 0 cursor = conn.cursor() print(f" ----------------------------------------------------------------------") print(f" Ā  {len(data_df)} uurlijkse records voor MySQL verwerken (Upsert)...") # Maak een lijst van tuples voor de 'executemany' batch = [tuple(row) for row in data_df.itertuples(index=False)] # De "Upsert" query. # Dit werkt perfect omdat 'datum_tijd' je PRIMARY KEY is. query = """ INSERT INTO amersfoort_weer_uurlijks (datum_tijd, locatie, temperatuur, gevoelstemperatuur, neerslag, wind_snelheid, wind_richting, luchtvochtigheid, bewolking, luchtdruk) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) ON DUPLICATE KEY UPDATE locatie = VALUES(locatie), temperatuur = VALUES(temperatuur), gevoelstemperatuur = VALUES(gevoelstemperatuur), neerslag = VALUES(neerslag), wind_snelheid = VALUES(wind_snelheid), wind_richting = VALUES(wind_richting), luchtvochtigheid = VALUES(luchtvochtigheid), bewolking = VALUES(bewolking), luchtdruk = VALUES(luchtdruk); """ try: cursor.executemany(query, batch) conn.commit() # rowcount bij 'upsert' telt 1 voor een INSERT, en 2 voor een UPDATE print(f"āœ… {cursor.rowcount} records succesvol verwerkt (inserted/updated).") return cursor.rowcount except Error as e: print(f"āŒ Fout bij opslaan naar MySQL: {e}") conn.rollback() return 0 def main(): """Hoofdfunctie""" print("="*70) print(f"INCREMENTELE WEERDATA UPDATE VOOR {LOCATIE} -> MYSQL") print("="*70) conn = None try: # 1. Verbind met DB en vind laatste datum print("šŸ’¾ Verbinden met MySQL database...") conn = mysql.connector.connect(**DB_CONFIG) cursor = conn.cursor() print("āœ… Succesvol verbonden met MySQL.") cursor.execute("SELECT MAX(datum_tijd) FROM amersfoort_weer_uurlijks") result = cursor.fetchone() last_date_in_db = result[0] if result[0] else None aantal_dagen_terug = 1 if last_date_in_db is None: print("Database is leeg. 16 dagen data wordt opgehaald.") aantal_dagen_terug = 16 # Maximaal wat de API toestaat else: print(f"Laatste datum in database: {last_date_in_db}") # Bereken hoeveel dagen we terug moeten kijken # +1 voor veiligheid, +1 omdat 'past_days' geen 'vandaag' meerekent dagen_verschil = (datetime.now() - last_date_in_db).days + 2 aantal_dagen_terug = min(max(1, dagen_verschil), 16) print(f"Database is {dagen_verschil-2} dagen oud. We halen {aantal_dagen_terug} dag(en) op.") # 2. Haal recente data op data = haal_recente_weerdata_op(aantal_dagen_terug) if data: # 3. Parse de data naar een DataFrame all_data_df = parse_api_data(data) # 4. Filter ALLEEN de data die we nog niet hebben # We filteren alle data *na* de laatste datum in de DB """ if last_date_in_db is not None: # We pakken alle data *na* onze laatste meting # De 'upsert' query handelt eventuele overlap af data_om_op_te_slaan = all_data_df[all_data_df['datum_tijd'] > last_date_in_db].copy() else: data_om_op_te_slaan = all_data_df.copy() # Alles is nieuw """ # 4. Stuur *alle* opgehaalde data naar MySQL. # De 'ON DUPLICATE KEY' query regelt de updates en inserts. data_om_op_te_slaan = all_data_df.copy() # 5. Sla de data op if not data_om_op_te_slaan.empty: sla_data_op_mysql(conn, data_om_op_te_slaan) else: print("\nāœ… Je database is al volledig up-to-date.") except Error as e: print(f"āŒ Hoofdfout: {e}") finally: if conn and conn.is_connected(): conn.close() print("Verbinding met MySQL gesloten.") print(f"\nāœ… Klaar! Script voltooid.") if __name__ == "__main__": main()