Source code for dinau.models

from dataclasses import dataclass
from enum import Enum, auto

import pandas as pd


[docs] class AirQualityIndex(Enum): """European Air Quality Index categories. This enum defines the standard European air quality categories ranging from good to extremely poor conditions. """ GOOD = auto() FAIR = auto() MODERATE = auto() POOR = auto() VERY_POOR = auto() EXTREMELY_POOR = auto()
[docs] @dataclass class CurrentWeather: """Current weather conditions with comprehensive information. :param timestamp: Time of the request (Unix Timestamp) :type timestamp: float :param temperature: Current temperature in Celsius :type temperature: float :param apparent_temperature: Current feels-like temperature in Celsius :type apparent_temperature: float :param humidity: Current relative humidity (0-100%) :type humidity: float :param wind_speed: Current wind speed in km/h :type wind_speed: float :param wind_direction: Current wind direction in degrees :type wind_direction: float :param wind_gust: Current wind gust speed in km/h :type wind_gust: float :param weather_code: Current WMO weather code :type weather_code: int :param precipitation: Preceding 15 minutes sum in mm :type precipitation: float :param snowfall: Preceding 15 minutes sum in cm :type snowfall: float :param rain: Preceding 15 minutes sum in mm :type rain: float :param showers: Preceding 15 minutes sum in mm :type showers: float :param cloud_cover: Current cloud cover percentage (0-100%) :type cloud_cover: float :param pressure_sea_level: Current atmospheric pressure at sea level in hPa :type pressure_sea_level: float :param pressure_surface_level: Current atmospheric pressure at surface level in hPa :type pressure_surface_level: float """ timestamp: float temperature: float apparent_temperature: float humidity: float wind_speed: float wind_direction: float wind_gust: float weather_code: int precipitation: float snowfall: float rain: float showers: float cloud_cover: float pressure_sea_level: float pressure_surface_level: float
[docs] @dataclass class CurrentWeatherLite: """Current weather conditions with only the most important information. :param timestamp: Time of the request (Unix Timestamp) :type timestamp: float :param temperature: Current temperature in Celsius :type temperature: float :param apparent_temperature: Current feels-like temperature in Celsius :type apparent_temperature: float :param humidity: Current relative humidity (0-100%) :type humidity: float :param wind_speed: Current wind speed in km/h :type wind_speed: float :param weather_code: Current WMO weather code :type weather_code: int :param precipitation: Preceding 15 minutes sum in mm :type precipitation: float """ timestamp: float temperature: float apparent_temperature: float humidity: float wind_speed: float weather_code: int precipitation: float
[docs] @dataclass class DailyWeatherLite: """Weather forecast for a single day with only the most important information. :param timestamp: Time of the request (Unix Timestamp) :type timestamp: float :param temperature_min: Minimum temperature in Celsius :type temperature_min: float :param temperature_max: Maximum temperature in Celsius :type temperature_max: float :param precipitation_probability: Probability of precipitation (0-100%) :type precipitation_probability: float :param hourly_data: Hourly weather data for the day :type hourly_data: pd.DataFrame .. note:: The ``hourly_data`` DataFrame contains the following columns: - **date** (*datetime*): Datetime of this row - **temperature** (*float*): Temperature (Celsius) - **apparent_temperature** (*float*): Feels-like temperature - **humidity** (*float*): Relative humidity at this time (0-100%) - **wind_speed** (*float*): Wind speed - **weather_code** (*int*): WMO weather code - **precipitation** (*float*): Precipitation amount (mm) The DataFrame contains 24 rows (one per hour). """ timestamp: float temperature_min: float temperature_max: float precipitation_probability: float hourly_data: pd.DataFrame
[docs] def umbrella_needed(self, threshold: float = 3.0) -> bool: """Determines if an umbrella is needed based on the weather data. Umbrella points are calculated internally based on the following factors: - Precipitation probability (0-100%) - Precipitation amount, temperature, and time of precipitation :param threshold: Minimum number of 'umbrella points' needed to return True (default: 3.0) :type threshold: float :return: True if an umbrella is needed, False otherwise :rtype: bool """ df = self.hourly_data.copy() # Probability factor (0–2) probability_factor = (self.precipitation_probability / 100.0) * 2.0 # Temperature factor. Snow is ignored. Rain at cold temperature is weighted higher temp_factor = pd.Series(1.0, index=df.index) temp_factor[df["temperature"] < 0] = 0.0 temp_factor[df["temperature"].between(0, 20, inclusive="left")] = 1.5 # Time of day factor. Morning/Evening hours are weighted higher, rain at night is weighted less hours = df["date"].dt.hour time_factor = pd.Series(1.0, index=df.index) # Morning (6–9) and evening (16–19) time_factor[hours.between(6, 9)] = 1.5 time_factor[hours.between(16, 19)] = 1.5 # Night (22–5) night_mask = (hours >= 22) | (hours <= 5) time_factor[night_mask] = 0.75 # Umbrella points umbrella_points = ( df["precipitation"] * probability_factor * temp_factor * time_factor ).sum() return umbrella_points >= threshold
[docs] @dataclass class DailyWeather(DailyWeatherLite): """Weather forecast for a single day with comprehensive information. :param timestamp: Time of the request (Unix Timestamp) :type timestamp: float :param temperature_min: Minimum temperature in Celsius :type temperature_min: float :param temperature_max: Maximum temperature in Celsius :type temperature_max: float :param precipitation_probability: Probability of precipitation (0-100%) :type precipitation_probability: float :param hourly_data: Hourly weather data for the day :type hourly_data: pd.DataFrame .. note:: The ``hourly_data`` DataFrame contains the following columns: - **date** (*datetime*): Datetime of this row - **temperature** (*float*): Temperature - **apparent_temperature** (*float*): Feels-like temperature - **humidity** (*float*): Relative humidity (0-100%) - **wind_speed** (*float*): Wind speed - **wind_direction** (*float*): Wind direction in degrees - **wind_gusts** (*float*): Wind gust speed - **weather_code** (*int*): WMO weather code - **precipitation** (*float*): Precipitation amount - **snowfall** (*float*): Snowfall amount - **rain** (*float*): Rain amount - **showers** (*float*): Shower amount - **cloud_cover** (*float*): Cloud cover percentage (0-100%) - **pressure_sea_level** (*float*): Atmospheric pressure at sea level in hPa - **pressure_surface_level** (*float*): Atmospheric pressure at surface level in hPa The DataFrame contains 24 rows (one per hour). """ pass
[docs] @dataclass class WeatherForecastLite: """Weather forecast for multiple days with only the most important information. :param timestamp: Time of the request (Unix Timestamp) :type timestamp: float :param daily_data: Daily weather data :type daily_data: pd.DataFrame :param hourly_data: Hourly weather data :type hourly_data: pd.DataFrame .. note:: The ``daily_data`` DataFrame contains the following columns: - **date** (*datetime*): Datetime of this row - **temperature_min** (*float*): Minimum temperature - **temperature_max** (*float*): Maximum temperature - **temperature_mean** (*float*): Mean temperature - **apparent_temperature_mean** (*float*): Mean feels-like temperature - **precipitation_probability** (*float*): Probability of precipitation (0-100%) - **precipitation_sum** (*float*): Sum of precipitation for the day The ``hourly_data`` DataFrame contains the following columns: - **date** (*datetime*): Datetime of this row - **temperature** (*float*): Temperature (Celsius) - **apparent_temperature** (*float*): Feels-like temperature (Celsius) - **humidity** (*float*): Relative humidity (0-100%) - **wind_speed** (*float*): Wind speed (km/h) - **weather_code** (*int*): WMO weather code - **precipitation** (*float*): Precipitation amount (mm) """ timestamp: float daily_data: pd.DataFrame hourly_data: pd.DataFrame
[docs] def umbrella_needed(self, threshold: float = 3.0) -> list[bool]: """Determines if an umbrella is needed for each day based on the weather data. Umbrella points are calculated internally based on the following factors: - Precipitation probability (0-100%) - Precipitation amount, temperature, and time of precipitation :param threshold: Minimum number of 'umbrella points' needed to return True (default: 3.0) :type threshold: float :return: List of boolean values, one per day. True if an umbrella is needed for that day, False otherwise :rtype: list[bool] """ results = [] # Iterate over each day dates = self.daily_data["date"].dt.date.unique() for date in dates: daily_row = self.daily_data[self.daily_data["date"].dt.date == date].iloc[0] hourly_df = self.hourly_data[ self.hourly_data["date"].dt.date == date ].copy() # Probability factor (0–2) probability_factor = (daily_row["precipitation_probability"] / 100.0) * 2.0 # Temperature factor. Snow is ignored. Rain at cold temperature is weighted higher temp_factor = pd.Series(1.0, index=hourly_df.index) temp_factor[hourly_df["temperature"] < 0] = 0.0 temp_factor[hourly_df["temperature"].between(0, 20, inclusive="left")] = 1.5 # Time of day factor. Morning/Evening hours are weighted higher, rain at night is weighted less hours = hourly_df["date"].dt.hour time_factor = pd.Series(1.0, index=hourly_df.index) # Morning (6–9) and evening (16–19) time_factor[hours.between(6, 9)] = 1.5 time_factor[hours.between(16, 19)] = 1.5 # Night (22–5) night_mask = (hours >= 22) | (hours <= 5) time_factor[night_mask] = 0.75 # Umbrella points umbrella_points = ( hourly_df["precipitation"] * probability_factor * temp_factor * time_factor ).sum() results.append(umbrella_points >= threshold) return results
[docs] def get_detailed_data(self, section_length: int = 6) -> pd.DataFrame: """Calculate weather data with customized section length. :param section_length: Number of hours per section (default: 6 for 4 sections per day) :type section_length: int :return: DataFrame with detailed data containing the following columns: - **date** (*str*): String representation of the section (e.g., "Jan 01 00-06") - **temperature_min** (*float*): Minimum temperature in the section - **temperature_max** (*float*): Maximum temperature in the section - **temperature_mean** (*float*): Mean temperature in the section - **apparent_temperature_mean** (*float*): Mean feels-like temperature in the section - **precipitation_sum** (*float*): Sum of precipitation for the section :rtype: pd.DataFrame """ detailed_rows = [] # Group hourly data by date dates = self.hourly_data["date"].dt.date.unique() for date in dates: # Filter hourly data for this date day_hourly = self.hourly_data[ self.hourly_data["date"].dt.date == date ].copy() # Divide the day into sections num_sections = 24 // section_length for section in range(num_sections): start_hour = section * section_length end_hour = start_hour + section_length # Filter data for this section section_data = day_hourly[ (day_hourly["date"].dt.hour >= start_hour) & (day_hourly["date"].dt.hour < end_hour) ] if len(section_data) == 0: continue # Calculate aggregated values for this section detailed_row = { "date": f"{date.strftime('%b %d')} {start_hour:02d}-{end_hour:02d}", "temperature_min": section_data["temperature"].min(), "temperature_max": section_data["temperature"].max(), "temperature_mean": section_data["temperature"].mean(), "apparent_temperature_mean": section_data[ "apparent_temperature" ].mean(), "precipitation_sum": section_data["precipitation"].sum(), } detailed_rows.append(detailed_row) return pd.DataFrame(detailed_rows)
[docs] @dataclass class WeatherForecast(WeatherForecastLite): """Weather forecast for multiple days with comprehensive information. :param timestamp: Time of the request (Unix Timestamp) :type timestamp: float :param daily_data: Daily weather data :type daily_data: pd.DataFrame :param hourly_data: Hourly weather data :type hourly_data: pd.DataFrame .. note:: The ``daily_data`` DataFrame contains the following columns: - **date** (*datetime*): Datetime of this row - **temperature_min** (*float*): Minimum temperature - **temperature_max** (*float*): Maximum temperature - **temperature_mean** (*float*): Mean temperature - **apparent_temperature_mean** (*float*): Mean feels-like temperature - **precipitation_probability** (*float*): Probability of precipitation (0-100%) - **precipitation_sum** (*float*): Sum of precipitation for the day The ``hourly_data`` DataFrame contains the following columns: - **date** (*datetime*): Datetime of this row - **temperature** (*float*): Temperature - **apparent_temperature** (*float*): Feels-like temperature - **humidity** (*float*): Relative humidity (0-100%) - **wind_speed** (*float*): Wind speed - **wind_direction** (*float*): Wind direction in degrees - **wind_gusts** (*float*): Wind gust speed - **weather_code** (*int*): WMO weather code - **precipitation** (*float*): Precipitation amount - **snowfall** (*float*): Snowfall amount - **rain** (*float*): Rain amount - **showers** (*float*): Shower amount - **cloud_cover** (*float*): Cloud cover percentage (0-100%) - **pressure_sea_level** (*float*): Atmospheric pressure at sea level in hPa - **pressure_surface_level** (*float*): Atmospheric pressure at surface level in hPa """ pass