import requests #Python library used to make HTTP requests. This library simplifies the process # of sending HTTP requests to interact with web services (APIs) and retrieve data. # Part C1 in the task. # As specified in the task, this is the class that contains and encapsulate all the data and methods # related to weather data for a specific location and date class WeatherData: def __init__(self, latitude, longitude, date): self.latitude = latitude self.longitude = longitude self.date = date self.year = date.year self.month = date.month self.day = date.day self.avg_temp = None self.min_temp = None self.max_temp = None self.avg_wind_speed = None self.min_wind_speed = None self.max_wind_speed = None self.sum_precipitation = None self.min_precipitation = None self.max_precipitation = None self.data = None # This is a special method that returns a string representation of the object # When inspecting an object in an interactive session, Python calls the '__repr__' # This is useful for debugging and logging, as it shows the current state of the object's attributes # This is useful in quickly understanding the data contained within the instance 'WeatherData' def __repr__(self): return (f"WeatherData({self.latitude}, {self.longitude}, {self.date}, " f"avg_temp={self.avg_temp}, min_temp={self.min_temp}, max_temp={self.max_temp}, " f"avg_wind_speed={self.avg_wind_speed}, min_wind_speed={self.min_wind_speed}, max_wind_speed={self.max_wind_speed}, " f"sum_precipitation={self.sum_precipitation}, min_precipitation={self.min_precipitation}, max_precipitation={self.max_precipitation})") # This part shows the method for fetching weather data for the specified location and date range # URL is directly copied from open meteo right after changing the location, timezone, and daily weather variables # In task part 2, it is specified that the data should be the most recent 5 years, so I made the start and end dates dynamic. def fetch_weather_data(self): start_date = (self.date.replace(year=self.date.year - 5)).strftime('%Y-%m-%d') end_date = self.date.strftime('%Y-%m-%d') url = (f"https://archive-api.open-meteo.com/v1/archive?" f"latitude={self.latitude}&longitude={self.longitude}&start_date={start_date}&end_date={end_date}" f"&daily=temperature_2m_max,temperature_2m_min,temperature_2m_mean,precipitation_sum,wind_speed_10m_max" f"&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch&timezone=America%2FNew_York") # This is the GET request sent to the constructed URL. The URL is taken directly from open-meteo and edited. # Response's status code 200 indicates success, and the response is parsed as JSON and stored in the 'data' variable response = requests.get(url) if response.status_code == 200: data = response.json() # Processing the retrieved data. # This code calculates the average, minimum, maximum,and sum for the relevant weather parameters. # Mean = add up all the given values, then divide by how many values there are. This calculation # is the dame as getting the average. So, for ease of use, I am using avg all throughout. # Filter out None values before summing and averaging. 'None' values represent missing data temp_mean_values = [val for val in data['daily']['temperature_2m_mean'] if val is not None] temp_min_values = [val for val in data['daily']['temperature_2m_min'] if val is not None] temp_max_values = [val for val in data['daily']['temperature_2m_max'] if val is not None] wind_speed_values = [val for val in data['daily']['wind_speed_10m_max'] if val is not None] precipitation_values = [val for val in data['daily']['precipitation_sum'] if val is not None] # Calculate averages, min, and max while handling empty lists self.avg_temp = sum(temp_mean_values) / len(temp_mean_values) if temp_mean_values else None self.min_temp = min(temp_min_values) if temp_min_values else None self.max_temp = max(temp_max_values) if temp_max_values else None self.avg_wind_speed = sum(wind_speed_values) / len(wind_speed_values) if wind_speed_values else None self.min_wind_speed = min(wind_speed_values) if wind_speed_values else None self.max_wind_speed = max(wind_speed_values) if wind_speed_values else None self.sum_precipitation = sum(precipitation_values) if precipitation_values else None self.min_precipitation = min(precipitation_values) if precipitation_values else None self.max_precipitation = max(precipitation_values) if precipitation_values else None # This is for handling errors. If the API request fails (status code is not 200), an error message is # printed with the relevant status code else: print(f"Error fetching data: {response.status_code}") # separate methods for part c2 def fetch_mean_temperature(self): start_date = (self.date.replace(year=self.date.year - 5)).strftime('%Y-%m-%d') end_date = self.date.strftime('%Y-%m-%d') url = (f"https://archive-api.open-meteo.com/v1/archive?" f"latitude={self.latitude}&longitude={self.longitude}&start_date={start_date}&end_date={end_date}" f"&daily=temperature_2m_max,temperature_2m_min,temperature_2m_mean,precipitation_sum,wind_speed_10m_max" f"&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch&timezone=America%2FNew_York") response = requests.get(url) if response.status_code == 200: data = response.json() temp_mean_values = [val for val in data['daily']['temperature_2m_mean'] if val is not None] self.avg_temp = sum(temp_mean_values) / len(temp_mean_values) if temp_mean_values else None print(f"Mean Temperature: {self.avg_temp} Fahrenheit") else: print(f"Error fetching mean temperature data: {response.status_code}") def fetch_max_wind_speed(self): start_date = (self.date.replace(year=self.date.year - 5)).strftime('%Y-%m-%d') end_date = self.date.strftime('%Y-%m-%d') url = (f"https://archive-api.open-meteo.com/v1/archive?" f"latitude={self.latitude}&longitude={self.longitude}&start_date={start_date}&end_date={end_date}" f"&daily=temperature_2m_max,temperature_2m_min,temperature_2m_mean,precipitation_sum,wind_speed_10m_max" f"&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch&timezone=America%2FNew_York") response = requests.get(url) if response.status_code == 200: data = response.json() wind_speed_values = [val for val in data['daily']['wind_speed_10m_max'] if val is not None] self.max_wind_speed = max(wind_speed_values) if wind_speed_values else None print(f"Maximum Wind Speed: {self.max_wind_speed} mph") else: print(f"Error fetching maximum wind speed data: {response.status_code}") def fetch_precipitation_sum(self): start_date = (self.date.replace(year=self.date.year - 5)).strftime('%Y-%m-%d') end_date = self.date.strftime('%Y-%m-%d') url = (f"https://archive-api.open-meteo.com/v1/archive?" f"latitude={self.latitude}&longitude={self.longitude}&start_date={start_date}&end_date={end_date}" f"&daily=temperature_2m_max,temperature_2m_min,temperature_2m_mean,precipitation_sum,wind_speed_10m_max" f"&temperature_unit=fahrenheit&wind_speed_unit=mph&precipitation_unit=inch&timezone=America%2FNew_York") response = requests.get(url) if response.status_code == 200: data = response.json() precipitation_values = [val for val in data['daily']['precipitation_sum'] if val is not None] self.sum_precipitation = sum(precipitation_values) if precipitation_values else None print(f"Sum Precipitation: {self.sum_precipitation} inch") else: print(f"Error fetching precipitation data: {response.status_code}")