194 lines
6.7 KiB
Python
194 lines
6.7 KiB
Python
"""
|
||
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
|
||
|
||
# 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() |