Merge pull request 'fetch-weather' (#12) from fetch-weather into main

Reviewed-on: #12
This commit was merged in pull request #12.
This commit is contained in:
2025-08-27 17:27:01 +00:00
10 changed files with 1942 additions and 516 deletions

3
.gitignore vendored
View File

@@ -1,5 +1,6 @@
.idea
.Trash-1000
target
database
data/stats/imported
data/stats/imported/*
data/__pycache__

View File

@@ -4,9 +4,11 @@ verify_ssl = true
name = "pypi"
[packages]
numpy = "*"
ephem = "*"
matplotlib = "*"
requests = "2.32"
numpy = "*"
requests = "*"
timezonefinder = "*"
[dev-packages]

1096
Pipfile.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,75 +1,100 @@
import ephem
import requests
import datetime
from timezonefinder import TimezoneFinder
class Weather:
# Example usage (requires OpenWeatherMap API key)
# Replace 'YOUR_API_KEY' with your actual key from https://openweathermap.org/
def get_weather(self, latitude: float, longitude: float, date_str: str, hour: int) -> dict:
"""
Fetches weather data for the specified location and time.
def get_sun_and_moon_phase(lat, long, date_str):
date_str = f"{date_str[:4]}/{date_str[4:6]}/{date_str[6:8]}"
observer = ephem.Observer()
observer.lat = str(lat)
observer.lon = str(long)
observer.date = date_str
sun = ephem.Sun()
sun.compute(observer)
sunrise_time = int(observer.next_rising(sun).datetime().strftime('%Y%m%d'))
sunset_time = int(observer.next_setting(sun).datetime().strftime('%Y%m%d'))
date = ephem.Date(date_str)
moon = ephem.Moon()
moon.compute(date)
return (sunrise_time, sunset_time, moon.phase)
def get_timezone(latitude: float, longitude: float):
obj = TimezoneFinder()
timezone_str = obj.timezone_at(lng=longitude, lat=latitude)
return timezone_str
def get_weather(latitude: float, longitude: float, date_str: str, hour: int) -> dict:
"""
Fetches weather data for the specified location and time.
Args:
latitude (float): Latitude of the location in degrees.
longitude (float): Longitude of the location in degrees.
date_str (str): Date in YYYYMMDD format.
hour (int): Hour (0-23) when you want to know the weather.
Returns:
dict: Dictionary containing temperature, condition, and sunrise/sunset times.
"""
# Convert date string components for API request
date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
stats_to_get = [
"temperature_2m",
"relative_humidity_2m",
"dew_point_2m",
"apparent_temperature",
"pressure_msl",
"surface_pressure",
"precipitation",
"rain",
"snowfall",
"cloud_cover",
"cloud_cover_low",
"cloud_cover_mid",
"cloud_cover_high",
"shortwave_radiation",
"direct_radiation",
"direct_normal_irradiance",
"diffuse_radiation",
"global_tilted_irradiance",
"sunshine_duration",
"wind_speed_10m",
"wind_speed_100m",
"wind_direction_10m",
"wind_direction_100m",
"wind_gusts_10m",
"et0_fao_evapotranspiration",
"weather_code",
"snow_depth",
"vapour_pressure_deficit",
"soil_temperature_0_to_7cm",
"soil_temperature_7_to_28cm",
"soil_temperature_28_to_100cm",
"soil_temperature_100_to_255cm",
"soil_moisture_0_to_7cm",
"soil_moisture_7_to_28cm",
"soil_moisture_28_to_100cm",
"soil_moisture_100_to_255cm",
]
stats_to_get = ','.join(stats_to_get)
timezone = get_timezone(latitude, longitude)
try:
api_url = f"https://archive-api.open-meteo.com/v1/archive?latitude={latitude}&longitude={longitude}&timezone={timezone}&start_date={date}&end_date={date}&hourly={stats_to_get}"
response = requests.get(api_url)
data = response.json()
Args:
latitude (float): Latitude of the location in degrees.
longitude (float): Longitude of the location in degrees.
date_str (str): Date in YYYYMMDD format.
hour (int): Hour (0-23) when you want to know the weather.
Returns:
dict: Dictionary containing temperature, condition, and sunrise/sunset times.
"""
# Convert date string components for API request
date = f"{date_str[:4]}-{date_str[4:6]}-{date_str[6:8]}"
if response.status_code != 200:
return {"error": "Failed to fetch weather", "details": data}
stats_to_get = [
"temperature_2m",
"relative_humidity_2m",
"dew_point_2m",
"apparent_temperature",
"pressure_msl",
"surface_pressure",
"precipitation",
"rain",
"snowfall",
"cloud_cover",
"cloud_cover_low",
"cloud_cover_mid",
"cloud_cover_high",
"shortwave_radiation",
"direct_radiation",
"direct_normal_irradiance",
"diffuse_radiation",
"global_tilted_irradiance",
"sunshine_duration",
"wind_speed_10m",
"wind_speed_100m",
"wind_direction_10m",
"wind_direction_100m",
"wind_gusts_10m",
"et0_fao_evapotranspiration",
"weather_code",
"snow_depth",
"vapour_pressure_deficit",
"soil_temperature_0_to_7cm",
"soil_temperature_7_to_28cm",
"soil_temperature_28_to_100cm",
"soil_temperature_100_to_255cm",
"soil_moisture_0_to_7cm",
"soil_moisture_7_to_28cm",
"soil_moisture_28_to_100cm",
"soil_moisture_100_to_255cm",
]
stats_to_get = ','.join(stats_to_get)
try:
api_url = f"https://archive-api.open-meteo.com/v1/archive?latitude={latitude}&longitude={longitude}&start_date={date}&end_date={date}&hourly={stats_to_get}"
response = requests.get(api_url)
data = response.json()
if response.status_code != 200:
return {"error": "Failed to fetch weather", "details": data}
return data
except Exception as e:
return {"error": str(e), "details": f"No weather data available for {latitude}, {longitude} on {date_str}"}
return data
except Exception as e:
return {"error": str(e), "details": f"No weather data available for {latitude}, {longitude} on {date_str}"}

View File

@@ -13,17 +13,26 @@ class Database:
cursor.executescript(sql_script_string)
self.db.commit()
def select(self, index):
def select(self, query, values):
# Query the database for the specified index
cursor = self.db.cursor()
query = "SELECT name, address FROM people WHERE id = ?"
cursor.execute(query, (index,))
cursor.execute(query, values)
result = cursor.fetchone()
if result:
return result
else:
return None
def selectall(self, query, values):
# Query the database for the specified index
cursor = self.db.cursor()
cursor.execute(query, values)
result = cursor.fetchall()
if result:
return result
else:
return None
def insert(self, query, values):
# Insert new entry into the database
cursor = self.db.cursor()

View File

@@ -138,15 +138,19 @@ CREATE TABLE IF NOT EXISTS team_game (
CREATE TABLE IF NOT EXISTS weather (
game_id INTEGER NOT NULL,
temperature SMALLINT,
wind_speed FLOAT,
air_pressure FLOAT,
temperature FLOAT,
humidity SMALLINT UNSIGNED,
uv_index FLOAT,
air_quality TINYINT UNSIGNED,
percipitation_type CHAR(10),
percipitation_amount FLOAT,
sky_condition CHAR(20),
dew_point FLOAT,
apparent_temperature FLOAT,
air_pressure FLOAT,
precipitation FLOAT,
rain FLOAT,
snowfall FLOAT,
cloud_cover SMALLINT UNSIGNED,
wind_speed FLOAT,
wind_direction SMALLINT UNSIGNED,
wind_gusts SMALLINT UNSIGNED,
sun_rise TIME,
sun_set TIME,
moon_phase TINYINT UNSIGNED,

View File

@@ -4,7 +4,9 @@ INSERT OR IGNORE INTO parks
("ARL03", "Globe Life Field in Arlington", 332, 14, 400, 8, 325, 8, 1, 32.747361, -97.084167, 568),
("ATL03", "Truist Park", 335, 11, 400, 12, 330, 15, 0, 33.89, -84.468, 951),
("BAL12", "Oriole Park at Camden Yards", 333, 7, 400, 7, 318, 21, 0, 39.283889, -76.621667, 36),
("BIR01", "Rickwood Field", 325, 8, 400, 8, 332, 8, 0, 33.502222, -86.855833, 551),
("BOS07", "Fenway Park", 310, 37, 390, 15, 302, 3, 0, 42.34625, -71.09775, 16),
("CHI11", "Weeghman Park; Cubs Park", 355, 11, 400, 11, 353, 11, 0, 41.948056, -87.655556, 594),
("CHI12", "Guaranteed Rate Field", 330, 8, 400, 8, 335, 8, 0, 41.83, -87.633889, 594),
("CIN09", "Great American Ballpark", 328, 12, 404, 8, 325, 12, 0, 39.0975, -84.506667, 489),
("CLE08", "Progressive Field", 325, 19, 410, 9, 325, 9, 0, 41.495833, -81.685278, 653),
@@ -12,21 +14,25 @@ INSERT OR IGNORE INTO parks
("DET05", "Comerica Park", 345, 7, 420, 9, 330, 8, 0, 42.339169, -83.048607, 577),
("HOU03", "Minute Maid Park", 315, 21, 436, 10, 326, 7, 1, 29.756944, -95.355556, 20),
("KAN06", "Kauffman Stadium", 330, 9, 410, 9, 330, 9, 0, 39.051389, -94.480556, 856),
("LON01", "London Stadium", 330, 16, 392, 16, 330, 16, 1, 51.538611, -0.016389, 24),
("LOS02", "Wrigley Field", 355, 15, 400, 11.5, 353, 15, 0, 41.948056, -87.655556, 600),
("LOS03", "Dodger Stadium", 330, 8, 395, 8, 330, 8, 0, 34.073611, -118.24, 515),
("MEX02", "Estadio Alfredo Harp Helu", 332, 10, 410, 10, 332, 10, 0, 19.404, -99.0855, 7316),
("MIA02", "Marlins Park", 344, 9, 407, 12, 335, 9, 1, 25.778056, -80.219722, 7),
("MIL06", "Miller Park", 344, 8, 400, 8, 345, 8, 1, 43.028333, -87.971111, 617),
("MIN04", "Target Field", 339, 8, 404, 8, 328, 23, 0, 44.981667, -93.278333, 827),
("NYC20", "Citi Field", 335, 8, 408, 8, 330, 8, 0, 40.756944, -73.845833, 13),
("NYC21", "Yankee Stadium II", 318, 8, 408, 8, 314, 8, 0, 40.829167, -73.926389, 23),
("OAK01", "Oakland-Alameda County Coliseum", 330, 8, 400, 8, 330, 8, 0, 37.751667, -122.200556, -16),
("PHI13", "Citizens Bank Park", 329, 10, 401, 6, 330, 13, 0, 39.905833, -75.166389, 0),
("PHO01", "Chase Field", 330, 7.6, 407, 25, 335, 7.6, 1, 33.445526, -112.066664, 1060.36),
("PIT08", "PNC Park", 325, 6, 399, 15, 320, 21, 0, 40.446944, -80.005833, 725),
("OAK01", "Oakland-Alameda County Coliseum", 330, 8, 400, 8, 330, 8, 0, 37.751667, -122.200556, -16),
("SAN02", "Petco Park", 334, 4, 369, 4, 322, 5, 0, 32.7073, -117.1566, 16),
("SEA03", "T-Mobile Park", 331, 15, 401, 7, 326, 7, 1, 47.591, -122.333, 16),
("SEO01", "Gocheok Sky Dome", 325, 12, 400, 12, 325, 12, 1, 37.498222, 126.86725, 40),
("SFO03", "Oracle Park", 339, 8, 399, 8, 309, 25, 0, 37.778611, -122.389167, 13),
("STL10", "Busch Stadium III", 336, 8, 400, 8, 335, 8, 0, 38.6225, -90.193056, 440),
("STP01", "Tropicana Field", 315, 11, 404, 9, 322, 11, 1, 27.768333, -82.653333, 39),
("TOR02", "Rogers Centre", 328, 8, 400, 8, 328, 8, 1, 43.641389, -79.389167, 282),
("WAS11", "Nationals Park", 336, 8, 402, 12, 335, 10, 0, 38.872778, -77.0075, 7)
("WAS11", "Nationals Park", 336, 8, 402, 12, 335, 10, 0, 38.872778, -77.0075, 7),
("WIL02", "BB&T Ballpark at Bowman Field", 323, 8, 411, 8, 331, 8, 0, 41.242347, -77.047067, 521)

View File

@@ -1,7 +1,11 @@
import os
import csv
import time
import shutil
from math import *
from data.db_connect import Database
from data.build_weather import get_weather, get_sun_and_moon_phase
class Importer:
def __init__(self, database: Database):
@@ -28,13 +32,12 @@ class Importer:
src_file = os.path.join(source_dir, filename)
dest_file = os.path.join(dest_dir, filename)
self.parse_one_file(f"{source_dir}/{filename}")
try:
shutil.copy(src_file, dest_file)
print(f"Copied {filename} to {dest_dir}")
except Exception as e:
print(f"Failed to copy {filename}: {e}")
if self.parse_one_file(f"{source_dir}/{filename}"):
try:
shutil.copy(src_file, dest_file)
print(f"Copied {filename} to {dest_dir}")
except Exception as e:
print(f"Failed to copy {filename}: {e}")
def parse_one_file(self, filepath):
bb_dict = {}
@@ -42,10 +45,39 @@ class Importer:
reader = csv.DictReader(bb_data_file)
bb_dict = list(reader)
count = 0
for game in bb_dict:
self.populate_database_with_stats(game)
# Delay to not overwhelm the free api
count += 1
print(f"Current line {count}")
if count % 600 == 0:
print("Sleeping for 1 min")
time.sleep(60)
if count % 5000 == 0:
print("Sleeping for 1 hour")
time.sleep(60*60)
if count % 10000 == 0:
print("Sleeping for 1 day")
time.sleep(60*60*24)
if not self.populate_database_with_stats(game):
return False
return True
def populate_database_with_stats(self, game_stats) -> bool:
parkid = game_stats["park-id"]
park_data = self.database.select("SELECT latitude, longitude FROM parks WHERE park_id = ?", (game_stats["park-id"],))
if park_data is None:
print(f"{parkid} is None")
return True
check_game_added_query = "SELECT id FROM games WHERE game_date = ? AND game_number = ? AND park_id = ?"
check_game_added_data = [game_stats["date"], game_stats["num-of-game"], game_stats['park-id']]
if self.database.select(check_game_added_query, check_game_added_data) is not None:
return True
def populate_database_with_stats(self, game_stats):
insert_game = """
INSERT INTO games
(
@@ -124,6 +156,42 @@ class Importer:
)
"""
insert_into_weather = """
INSERT INTO weather
(
game_id, temperature, humidity,
dew_point, apparent_temperature, air_pressure,
precipitation, rain, snowfall,
cloud_cover, wind_speed, wind_direction,
wind_gusts, sun_rise, sun_set,
moon_phase
)
VALUES
(
?, ?, ?,
?, ?, ?,
?, ?, ?,
?, ?, ?,
?, ?, ?,
?
)
"""
hour = 15 if game_stats["day-night"] == "D" else 19
historic_weather = get_weather(park_data[0], park_data[1], game_stats["date"], hour)
if "error" in historic_weather:
print(f"Error: {historic_weather['error']}: Details: {historic_weather['details']}")
if "No weather data available" in historic_weather['details']:
historic_weather = None
else:
return False
elif "hourly" not in historic_weather:
print(f"Failed to get weather: Full JSON: {historic_weather}")
historic_weather = None
else:
historic_weather = historic_weather["hourly"]
game_data = [
game_stats["date"], game_stats["num-of-game"], game_stats["day-of-week"],
game_stats["length-in-outs"], game_stats["day-night"], game_stats["completion-info"],
@@ -189,3 +257,19 @@ class Importer:
self.database.insert(insert_team_game, visiting_team_data)
self.database.insert(insert_team_game, home_team_data)
if historic_weather is not None:
(sunrise_time, sunset_time, moonphase) = get_sun_and_moon_phase(park_data[0], park_data[1], game_stats["date"])
weather_data = [
game_id, historic_weather["temperature_2m"][hour], historic_weather["relative_humidity_2m"][hour],
historic_weather["dew_point_2m"][hour], historic_weather["apparent_temperature"][hour], historic_weather["pressure_msl"][hour],
historic_weather["precipitation"][hour], historic_weather["rain"][hour], historic_weather["snowfall"][hour],
historic_weather["cloud_cover"][hour], historic_weather["wind_speed_10m"][hour], historic_weather["wind_direction_10m"][hour],
historic_weather["wind_gusts_10m"][hour], sunrise_time, sunset_time,
moonphase,
]
self.database.insert(insert_into_weather, weather_data)
return True

53
main.py
View File

@@ -2,7 +2,7 @@ import numpy as np # helps with the math
import matplotlib.pyplot as plt # to plot error during training
from data.db_connect import Database
from data.stats_importer import Importer
from data.build_weather import Weather
from data.build_weather import get_weather, get_sun_and_moon_phase
# input data
inputs = np.array([[0, 0, 1, 0],
@@ -14,50 +14,6 @@ inputs = np.array([[0, 0, 1, 0],
# output data
outputs = np.array([[0], [0], [0], [1], [1], [1]])
# create NeuralNetwork class
class NeuralNetwork:
# intialize variables in class
def __init__(self, inputs, outputs):
self.inputs = inputs
self.outputs = outputs
# initialize weights as .50 for simplicity
self.weights = np.array([[.50], [.50], [.50], [0.50]])
self.error_history = []
self.epoch_list = []
#activation function ==> S(x) = 1/1+e^(-x)
def sigmoid(self, x, deriv=False):
if deriv == True:
return x * (1 - x)
return 1 / (1 + np.exp(-x))
# data will flow through the neural network.
def feed_forward(self):
self.hidden = self.sigmoid(np.dot(self.inputs, self.weights))
# going backwards through the network to update weights
def backpropagation(self):
self.error = self.outputs - self.hidden
delta = self.error * self.sigmoid(self.hidden, deriv=True)
self.weights += np.dot(self.inputs.T, delta)
# train the neural net for 25,000 iterations
def train(self, epochs=25000):
for epoch in range(epochs):
# flow forward and produce an output
self.feed_forward()
# go back though the network to make corrections based on the output
self.backpropagation()
# keep track of the error history over each epoch
self.error_history.append(np.average(np.abs(self.error)))
self.epoch_list.append(epoch)
# function to predict output on new and unseen input data
def predict(self, new_input):
prediction = self.sigmoid(np.dot(new_input, self.weights))
return prediction
if __name__ == '__main__':
build_db_path = "./data/sql/build_db.sql"
fill_parks_path = "./data/sql/prefill_parks.sql"
@@ -73,9 +29,7 @@ if __name__ == '__main__':
imp = Importer(db_conn)
imp.parse_all_data("./data/stats/to_import", "./data/stats/imported/")
#we = Weather()
#print(we.get_weather(39.26733000, -76.79831000, "20250706", 12))
"""
else:
# create neural network
NN = NeuralNetwork(inputs, outputs)
@@ -95,4 +49,5 @@ else:
plt.plot(NN.epoch_list, NN.error_history)
plt.xlabel('Epoch')
plt.ylabel('Error')
plt.savefig('plot.png')
plt.savefig('plot.png')
"""

988
weather_example.json Normal file
View File

@@ -0,0 +1,988 @@
{
"latitude": 39.26186,
"longitude": -76.8595,
"generationtime_ms": 15.3275728225708,
"utc_offset_seconds": 0,
"timezone": "GMT",
"timezone_abbreviation": "GMT",
"elevation": 54.0,
"hourly_units": {
"time": "iso8601",
"temperature_2m": "°C",
"relative_humidity_2m": "%",
"dew_point_2m": "°C",
"apparent_temperature": "°C",
"pressure_msl": "hPa",
"surface_pressure": "hPa",
"precipitation": "mm",
"rain": "mm",
"snowfall": "cm",
"cloud_cover": "%",
"cloud_cover_low": "%",
"cloud_cover_mid": "%",
"cloud_cover_high": "%",
"shortwave_radiation": "W/m²",
"direct_radiation": "W/m²",
"direct_normal_irradiance": "W/m²",
"diffuse_radiation": "W/m²",
"global_tilted_irradiance": "W/m²",
"sunshine_duration": "s",
"wind_speed_10m": "km/h",
"wind_speed_100m": "km/h",
"wind_direction_10m": "°",
"wind_direction_100m": "°",
"wind_gusts_10m": "km/h",
"et0_fao_evapotranspiration": "mm",
"weather_code": "wmo code",
"snow_depth": "m",
"vapour_pressure_deficit": "kPa",
"soil_temperature_0_to_7cm": "°C",
"soil_temperature_7_to_28cm": "°C",
"soil_temperature_28_to_100cm": "°C",
"soil_temperature_100_to_255cm": "°C",
"soil_moisture_0_to_7cm": "m³/m³",
"soil_moisture_7_to_28cm": "m³/m³",
"soil_moisture_28_to_100cm": "m³/m³",
"soil_moisture_100_to_255cm": "m³/m³"
},
"hourly": {
"time": [
"2025-07-06T00:00",
"2025-07-06T01:00",
"2025-07-06T02:00",
"2025-07-06T03:00",
"2025-07-06T04:00",
"2025-07-06T05:00",
"2025-07-06T06:00",
"2025-07-06T07:00",
"2025-07-06T08:00",
"2025-07-06T09:00",
"2025-07-06T10:00",
"2025-07-06T11:00",
"2025-07-06T12:00",
"2025-07-06T13:00",
"2025-07-06T14:00",
"2025-07-06T15:00",
"2025-07-06T16:00",
"2025-07-06T17:00",
"2025-07-06T18:00",
"2025-07-06T19:00",
"2025-07-06T20:00",
"2025-07-06T21:00",
"2025-07-06T22:00",
"2025-07-06T23:00"
],
"temperature_2m": [
25.4,
24.2,
23.4,
22.8,
22.2,
21.6,
21.1,
20.7,
20.2,
19.9,
19.5,
20.4,
22.4,
24.7,
26.6,
27.7,
27.7,
29.4,
29.4,
29.4,
29.8,
29.5,
29.0,
28.2
],
"relative_humidity_2m": [
57,
69,
71,
73,
76,
78,
79,
79,
80,
82,
84,
82,
77,
74,
69,
67,
66,
59,
60,
62,
63,
61,
64,
68
],
"dew_point_2m": [
16.2,
18.2,
17.8,
17.8,
17.8,
17.6,
17.2,
16.9,
16.7,
16.7,
16.7,
17.2,
18.1,
19.9,
20.5,
21.0,
20.7,
20.6,
20.9,
21.4,
21.9,
21.3,
21.5,
21.8
],
"apparent_temperature": [
25.9,
25.6,
24.6,
24.2,
23.7,
23.0,
22.3,
21.8,
21.3,
21.0,
20.8,
22.0,
24.6,
27.8,
29.1,
31.2,
30.5,
33.4,
33.0,
32.8,
33.4,
32.1,
31.4,
31.0
],
"pressure_msl": [
1018.7,
1019.2,
1019.6,
1019.8,
1019.8,
1019.6,
1019.4,
1019.1,
1018.8,
1018.9,
1018.9,
1018.9,
1019.1,
1019.6,
1019.2,
1018.8,
1018.8,
1018.1,
1017.2,
1016.2,
1015.6,
1015.1,
1014.8,
1014.9
],
"surface_pressure": [
1012.4,
1012.9,
1013.3,
1013.5,
1013.5,
1013.2,
1013.0,
1012.7,
1012.4,
1012.5,
1012.5,
1012.5,
1012.8,
1013.3,
1012.9,
1012.6,
1012.6,
1011.9,
1011.0,
1010.0,
1009.4,
1008.9,
1008.6,
1008.7
],
"precipitation": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.1,
0.1,
0.3,
0.4,
0.6,
0.1,
0.1,
0.0,
0.0
],
"rain": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.1,
0.1,
0.3,
0.4,
0.6,
0.1,
0.1,
0.0,
0.0
],
"snowfall": [
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"cloud_cover": [
99,
99,
98,
100,
98,
100,
97,
99,
98,
99,
92,
6,
5,
11,
39,
65,
30,
31,
53,
60,
20,
28,
15,
11
],
"cloud_cover_low": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
11,
39,
64,
30,
29,
28,
39,
11,
15,
12,
0
],
"cloud_cover_mid": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
7,
4,
10,
37,
35,
11,
19,
7,
11
],
"cloud_cover_high": [
99,
99,
98,
100,
98,
100,
97,
99,
98,
99,
92,
6,
5,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"shortwave_radiation": [
121.0,
11.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
63.0,
224.0,
394.0,
553.0,
664.0,
388.0,
821.0,
771.0,
670.0,
638.0,
455.0,
379.0,
261.0
],
"direct_radiation": [
73.0,
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
31.0,
155.0,
292.0,
419.0,
480.0,
52.0,
598.0,
558.0,
438.0,
465.0,
287.0,
237.0,
166.0
],
"direct_normal_irradiance": [
386.8,
35.6,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
223.5,
519.1,
607.6,
648.2,
611.7,
58.7,
633.5,
585.0,
478.5,
559.5,
406.0,
430.2,
443.9
],
"diffuse_radiation": [
48.0,
8.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
32.0,
69.0,
102.0,
134.0,
184.0,
336.0,
223.0,
213.0,
232.0,
173.0,
168.0,
142.0,
95.0
],
"global_tilted_irradiance": [
121.0,
11.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
63.0,
224.0,
394.0,
553.0,
664.0,
388.0,
821.0,
771.0,
670.0,
638.0,
455.0,
379.0,
261.0
],
"sunshine_duration": [
3600.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
2585.07,
3600.0,
3600.0,
3600.0,
3600.0,
0.0,
3600.0,
3600.0,
3600.0,
3600.0,
3600.0,
3600.0,
3600.0
],
"wind_speed_10m": [
10.8,
10.9,
11.4,
9.5,
9.1,
9.1,
8.9,
8.5,
8.1,
8.3,
7.3,
6.5,
4.7,
4.8,
11.0,
10.3,
9.5,
11.5,
12.9,
12.5,
11.7,
13.4,
15.2,
13.5
],
"wind_speed_100m": [
23.0,
23.5,
25.4,
22.0,
21.3,
20.7,
20.5,
20.5,
19.6,
19.8,
18.9,
14.7,
13.5,
7.3,
14.9,
13.9,
12.9,
15.2,
17.5,
16.8,
16.1,
18.7,
21.9,
20.7
],
"wind_direction_10m": [
133,
147,
157,
179,
189,
195,
198,
205,
219,
219,
216,
231,
198,
202,
194,
178,
171,
158,
148,
143,
149,
143,
137,
136
],
"wind_direction_100m": [
137,
148,
162,
184,
193,
198,
198,
203,
212,
215,
214,
220,
205,
203,
195,
179,
172,
159,
148,
142,
148,
145,
141,
139
],
"wind_gusts_10m": [
21.2,
19.4,
19.8,
20.2,
16.2,
15.5,
15.5,
14.8,
14.4,
13.7,
13.7,
11.5,
11.5,
14.4,
24.5,
26.3,
25.2,
27.7,
29.9,
29.9,
28.4,
27.7,
31.7,
31.3
],
"et0_fao_evapotranspiration": [
0.13,
0.06,
0.04,
0.03,
0.02,
0.02,
0.02,
0.01,
0.01,
0.01,
0.02,
0.04,
0.13,
0.26,
0.38,
0.47,
0.31,
0.6,
0.57,
0.5,
0.48,
0.37,
0.32,
0.22
],
"weather_code": [
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
3,
0,
0,
0,
1,
51,
51,
51,
51,
53,
51,
51,
0,
0
],
"snow_depth": [None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None
],
"vapour_pressure_deficit": [
1.39,
0.92,
0.84,
0.74,
0.64,
0.57,
0.53,
0.52,
0.47,
0.42,
0.37,
0.44,
0.62,
0.8,
1.07,
1.22,
1.28,
1.68,
1.62,
1.54,
1.56,
1.59,
1.44,
1.22
],
"soil_temperature_0_to_7cm": [
26.8,
25.8,
24.9,
24.1,
23.3,
22.7,
22.1,
21.6,
21.1,
20.7,
20.3,
20.4,
21.3,
22.9,
24.3,
25.7,
26.2,
27.5,
28.3,
28.7,
29.0,
28.9,
28.7,
28.2
],
"soil_temperature_7_to_28cm": [
24.3,
24.4,
24.4,
24.4,
24.3,
24.2,
24.1,
24.0,
23.8,
23.6,
23.5,
23.3,
23.1,
23.1,
23.1,
23.2,
23.3,
23.4,
23.6,
23.8,
24.0,
24.2,
24.4,
24.5
],
"soil_temperature_28_to_100cm": [
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6,
21.6
],
"soil_temperature_100_to_255cm": [
14.3,
14.3,
14.3,
14.3,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4,
14.4
],
"soil_moisture_0_to_7cm": [
0.247,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.244,
0.248,
0.246,
0.245,
0.246,
0.246,
0.247,
0.251,
0.25,
0.249,
0.248,
0.247
],
"soil_moisture_7_to_28cm": [
0.362,
0.361,
0.36,
0.36,
0.36,
0.36,
0.36,
0.36,
0.36,
0.36,
0.36,
0.36,
0.359,
0.362,
0.361,
0.36,
0.359,
0.358,
0.357,
0.356,
0.355,
0.355,
0.354,
0.353
],
"soil_moisture_28_to_100cm": [
0.287,
0.286,
0.286,
0.287,
0.287,
0.287,
0.287,
0.287,
0.287,
0.287,
0.287,
0.287,
0.287,
0.288,
0.288,
0.288,
0.288,
0.288,
0.288,
0.288,
0.288,
0.288,
0.288,
0.288
],
"soil_moisture_100_to_255cm": [
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352,
0.352
]
}
}