mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-10-11 11:56:17 +00:00
Rename settings variables (remove prefixes)
This commit is contained in:
@@ -9,12 +9,12 @@ from akkudoktoreos.prediction.elecpriceimport import ElecPriceImportCommonSettin
|
||||
class ElecPriceCommonSettings(SettingsBaseModel):
|
||||
"""Electricity Price Prediction Configuration."""
|
||||
|
||||
elecprice_provider: Optional[str] = Field(
|
||||
provider: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Electricity price provider id of provider to be used.",
|
||||
examples=["ElecPriceAkkudoktor"],
|
||||
)
|
||||
elecprice_charges_kwh: Optional[float] = Field(
|
||||
charges_kwh: Optional[float] = Field(
|
||||
default=None, ge=0, description="Electricity price charges (€/kWh).", examples=[0.21]
|
||||
)
|
||||
|
||||
|
@@ -49,15 +49,15 @@ class ElecPriceProvider(PredictionProvider):
|
||||
electricity price_provider (str): Prediction provider for electricity price.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
prediction_historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
latitude (float, optional): The latitude in degrees, must be within -90 to 90.
|
||||
longitude (float, optional): The longitude in degrees, must be within -180 to 180.
|
||||
start_datetime (datetime, optional): The starting datetime for predictions, defaults to the current datetime if unspecified.
|
||||
end_datetime (datetime, computed): The datetime representing the end of the prediction range,
|
||||
calculated based on `start_datetime` and `prediction_hours`.
|
||||
calculated based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The earliest datetime for retaining historical data, calculated
|
||||
based on `start_datetime` and `prediction_historic_hours`.
|
||||
based on `start_datetime` and `historic_hours`.
|
||||
"""
|
||||
|
||||
# overload
|
||||
@@ -71,4 +71,4 @@ class ElecPriceProvider(PredictionProvider):
|
||||
return "ElecPriceProvider"
|
||||
|
||||
def enabled(self) -> bool:
|
||||
return self.provider_id() == self.config.elecprice.elecprice_provider
|
||||
return self.provider_id() == self.config.elecprice.provider
|
||||
|
@@ -54,11 +54,11 @@ class ElecPriceAkkudoktor(ElecPriceProvider):
|
||||
of hours into the future and retains historical data.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): Number of hours in the future for the forecast.
|
||||
prediction_historic_hours (int, optional): Number of past hours for retaining data.
|
||||
hours (int, optional): Number of hours in the future for the forecast.
|
||||
historic_hours (int, optional): Number of past hours for retaining data.
|
||||
start_datetime (datetime, optional): Start datetime for forecasts, defaults to the current datetime.
|
||||
end_datetime (datetime, computed): The forecast's end datetime, computed based on `start_datetime` and `prediction_hours`.
|
||||
keep_datetime (datetime, computed): The datetime to retain historical data, computed from `start_datetime` and `prediction_historic_hours`.
|
||||
end_datetime (datetime, computed): The forecast's end datetime, computed based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The datetime to retain historical data, computed from `start_datetime` and `historic_hours`.
|
||||
|
||||
Methods:
|
||||
provider_id(): Returns a unique identifier for the provider.
|
||||
@@ -125,18 +125,16 @@ class ElecPriceAkkudoktor(ElecPriceProvider):
|
||||
capped_data = data.clip(min=lower_bound, max=upper_bound)
|
||||
return capped_data
|
||||
|
||||
def _predict_ets(
|
||||
self, history: np.ndarray, seasonal_periods: int, prediction_hours: int
|
||||
) -> np.ndarray:
|
||||
def _predict_ets(self, history: np.ndarray, seasonal_periods: int, hours: int) -> np.ndarray:
|
||||
clean_history = self._cap_outliers(history)
|
||||
model = ExponentialSmoothing(
|
||||
clean_history, seasonal="add", seasonal_periods=seasonal_periods
|
||||
).fit()
|
||||
return model.forecast(prediction_hours)
|
||||
return model.forecast(hours)
|
||||
|
||||
def _predict_median(self, history: np.ndarray, prediction_hours: int) -> np.ndarray:
|
||||
def _predict_median(self, history: np.ndarray, hours: int) -> np.ndarray:
|
||||
clean_history = self._cap_outliers(history)
|
||||
return np.full(prediction_hours, np.median(clean_history))
|
||||
return np.full(hours, np.median(clean_history))
|
||||
|
||||
def _update_data(
|
||||
self, force_update: Optional[bool] = False
|
||||
@@ -155,8 +153,8 @@ class ElecPriceAkkudoktor(ElecPriceProvider):
|
||||
# Assumption that all lists are the same length and are ordered chronologically
|
||||
# in ascending order and have the same timestamps.
|
||||
|
||||
# Get elecprice_charges_kwh in wh
|
||||
charges_wh = (self.config.elecprice.elecprice_charges_kwh or 0) / 1000
|
||||
# Get charges_kwh in wh
|
||||
charges_wh = (self.config.elecprice.charges_kwh or 0) / 1000
|
||||
|
||||
highest_orig_datetime = None # newest datetime from the api after that we want to update.
|
||||
series_data = pd.Series(dtype=float) # Initialize an empty series
|
||||
@@ -183,27 +181,23 @@ class ElecPriceAkkudoktor(ElecPriceProvider):
|
||||
assert highest_orig_datetime # mypy fix
|
||||
|
||||
# some of our data is already in the future, so we need to predict less. If we got less data we increase the prediction hours
|
||||
needed_prediction_hours = int(
|
||||
self.config.prediction.prediction_hours
|
||||
needed_hours = int(
|
||||
self.config.prediction.hours
|
||||
- ((highest_orig_datetime - self.start_datetime).total_seconds() // 3600)
|
||||
)
|
||||
|
||||
if needed_prediction_hours <= 0:
|
||||
if needed_hours <= 0:
|
||||
logger.warning(
|
||||
f"No prediction needed. needed_prediction_hours={needed_prediction_hours}, prediction_hours={self.config.prediction.prediction_hours},highest_orig_datetime {highest_orig_datetime}, start_datetime {self.start_datetime}"
|
||||
) # this might keep data longer than self.start_datetime + self.config.prediction.prediction_hours in the records
|
||||
f"No prediction needed. needed_hours={needed_hours}, hours={self.config.prediction.hours},highest_orig_datetime {highest_orig_datetime}, start_datetime {self.start_datetime}"
|
||||
) # this might keep data longer than self.start_datetime + self.config.prediction.hours in the records
|
||||
return
|
||||
|
||||
if amount_datasets > 800: # we do the full ets with seasons of 1 week
|
||||
prediction = self._predict_ets(
|
||||
history, seasonal_periods=168, prediction_hours=needed_prediction_hours
|
||||
)
|
||||
prediction = self._predict_ets(history, seasonal_periods=168, hours=needed_hours)
|
||||
elif amount_datasets > 168: # not enough data to do seasons of 1 week, but enough for 1 day
|
||||
prediction = self._predict_ets(
|
||||
history, seasonal_periods=24, prediction_hours=needed_prediction_hours
|
||||
)
|
||||
prediction = self._predict_ets(history, seasonal_periods=24, hours=needed_hours)
|
||||
elif amount_datasets > 0: # not enough data for ets, do median
|
||||
prediction = self._predict_median(history, prediction_hours=needed_prediction_hours)
|
||||
prediction = self._predict_median(history, hours=needed_hours)
|
||||
else:
|
||||
logger.error("No data available for prediction")
|
||||
raise ValueError("No data available")
|
||||
|
@@ -22,24 +22,22 @@ logger = get_logger(__name__)
|
||||
class ElecPriceImportCommonSettings(SettingsBaseModel):
|
||||
"""Common settings for elecprice data import from file or JSON String."""
|
||||
|
||||
elecpriceimport_file_path: Optional[Union[str, Path]] = Field(
|
||||
import_file_path: Optional[Union[str, Path]] = Field(
|
||||
default=None,
|
||||
description="Path to the file to import elecprice data from.",
|
||||
examples=[None, "/path/to/prices.json"],
|
||||
)
|
||||
|
||||
elecpriceimport_json: Optional[str] = Field(
|
||||
import_json: Optional[str] = Field(
|
||||
default=None,
|
||||
description="JSON string, dictionary of electricity price forecast value lists.",
|
||||
examples=['{"elecprice_marketprice_wh": [0.0003384, 0.0003318, 0.0003284]}'],
|
||||
)
|
||||
|
||||
# Validators
|
||||
@field_validator("elecpriceimport_file_path", mode="after")
|
||||
@field_validator("import_file_path", mode="after")
|
||||
@classmethod
|
||||
def validate_elecpriceimport_file_path(
|
||||
cls, value: Optional[Union[str, Path]]
|
||||
) -> Optional[Path]:
|
||||
def validate_import_file_path(cls, value: Optional[Union[str, Path]]) -> Optional[Path]:
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, str):
|
||||
@@ -65,12 +63,12 @@ class ElecPriceImport(ElecPriceProvider, PredictionImportProvider):
|
||||
return "ElecPriceImport"
|
||||
|
||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||
if self.config.elecprice.provider_settings.elecpriceimport_file_path is not None:
|
||||
if self.config.elecprice.provider_settings.import_file_path is not None:
|
||||
self.import_from_file(
|
||||
self.config.elecprice.provider_settings.elecpriceimport_file_path,
|
||||
self.config.elecprice.provider_settings.import_file_path,
|
||||
key_prefix="elecprice",
|
||||
)
|
||||
if self.config.elecprice.provider_settings.elecpriceimport_json is not None:
|
||||
if self.config.elecprice.provider_settings.import_json is not None:
|
||||
self.import_from_json(
|
||||
self.config.elecprice.provider_settings.elecpriceimport_json, key_prefix="elecprice"
|
||||
self.config.elecprice.provider_settings.import_json, key_prefix="elecprice"
|
||||
)
|
||||
|
@@ -15,7 +15,7 @@ logger = get_logger(__name__)
|
||||
class LoadCommonSettings(SettingsBaseModel):
|
||||
"""Load Prediction Configuration."""
|
||||
|
||||
load_provider: Optional[str] = Field(
|
||||
provider: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Load provider id of provider to be used.",
|
||||
examples=["LoadAkkudoktor"],
|
||||
|
@@ -33,18 +33,18 @@ class LoadProvider(PredictionProvider):
|
||||
LoadProvider is a thread-safe singleton, ensuring only one instance of this class is created.
|
||||
|
||||
Configuration variables:
|
||||
load_provider (str): Prediction provider for load.
|
||||
provider (str): Prediction provider for load.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
prediction_historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
latitude (float, optional): The latitude in degrees, must be within -90 to 90.
|
||||
longitude (float, optional): The longitude in degrees, must be within -180 to 180.
|
||||
start_datetime (datetime, optional): The starting datetime for predictions, defaults to the current datetime if unspecified.
|
||||
end_datetime (datetime, computed): The datetime representing the end of the prediction range,
|
||||
calculated based on `start_datetime` and `prediction_hours`.
|
||||
calculated based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The earliest datetime for retaining historical data, calculated
|
||||
based on `start_datetime` and `prediction_historic_hours`.
|
||||
based on `start_datetime` and `historic_hours`.
|
||||
"""
|
||||
|
||||
# overload
|
||||
@@ -58,4 +58,4 @@ class LoadProvider(PredictionProvider):
|
||||
return "LoadProvider"
|
||||
|
||||
def enabled(self) -> bool:
|
||||
return self.provider_id() == self.config.load.load_provider
|
||||
return self.provider_id() == self.config.load.provider
|
||||
|
@@ -111,7 +111,7 @@ class LoadAkkudoktor(LoadProvider):
|
||||
# We provide prediction starting at start of day, to be compatible to old system.
|
||||
# End date for prediction is prediction hours from now.
|
||||
date = self.start_datetime.start_of("day")
|
||||
end_date = self.start_datetime.add(hours=self.config.prediction.prediction_hours)
|
||||
end_date = self.start_datetime.add(hours=self.config.prediction.hours)
|
||||
while compare_datetimes(date, end_date).lt:
|
||||
# Extract mean (index 0) and standard deviation (index 1) for the given day and hour
|
||||
# Day indexing starts at 0, -1 because of that
|
||||
|
@@ -22,19 +22,19 @@ logger = get_logger(__name__)
|
||||
class LoadImportCommonSettings(SettingsBaseModel):
|
||||
"""Common settings for load data import from file or JSON string."""
|
||||
|
||||
load_import_file_path: Optional[Union[str, Path]] = Field(
|
||||
import_file_path: Optional[Union[str, Path]] = Field(
|
||||
default=None,
|
||||
description="Path to the file to import load data from.",
|
||||
examples=[None, "/path/to/yearly_load.json"],
|
||||
)
|
||||
load_import_json: Optional[str] = Field(
|
||||
import_json: Optional[str] = Field(
|
||||
default=None,
|
||||
description="JSON string, dictionary of load forecast value lists.",
|
||||
examples=['{"load0_mean": [676.71, 876.19, 527.13]}'],
|
||||
)
|
||||
|
||||
# Validators
|
||||
@field_validator("load_import_file_path", mode="after")
|
||||
@field_validator("import_file_path", mode="after")
|
||||
@classmethod
|
||||
def validate_loadimport_file_path(cls, value: Optional[Union[str, Path]]) -> Optional[Path]:
|
||||
if value is None:
|
||||
@@ -62,11 +62,7 @@ class LoadImport(LoadProvider, PredictionImportProvider):
|
||||
return "LoadImport"
|
||||
|
||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||
if self.config.load.provider_settings.load_import_file_path is not None:
|
||||
self.import_from_file(
|
||||
self.config.provider_settings.load_import_file_path, key_prefix="load"
|
||||
)
|
||||
if self.config.load.provider_settings.load_import_json is not None:
|
||||
self.import_from_json(
|
||||
self.config.load.provider_settings.load_import_json, key_prefix="load"
|
||||
)
|
||||
if self.config.load.provider_settings.import_file_path is not None:
|
||||
self.import_from_file(self.config.provider_settings.import_file_path, key_prefix="load")
|
||||
if self.config.load.provider_settings.import_json is not None:
|
||||
self.import_from_json(self.config.load.provider_settings.import_json, key_prefix="load")
|
||||
|
@@ -53,9 +53,9 @@ class PredictionCommonSettings(SettingsBaseModel):
|
||||
determines the time zone based on latitude and longitude.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (Optional[int]): Number of hours into the future for predictions.
|
||||
hours (Optional[int]): Number of hours into the future for predictions.
|
||||
Must be non-negative.
|
||||
prediction_historic_hours (Optional[int]): Number of hours into the past for historical data.
|
||||
historic_hours (Optional[int]): Number of hours into the past for historical data.
|
||||
Must be non-negative.
|
||||
latitude (Optional[float]): Latitude in degrees, must be between -90 and 90.
|
||||
longitude (Optional[float]): Longitude in degrees, must be between -180 and 180.
|
||||
@@ -65,16 +65,16 @@ class PredictionCommonSettings(SettingsBaseModel):
|
||||
and longitude.
|
||||
|
||||
Validators:
|
||||
validate_prediction_hours (int): Ensures `prediction_hours` is a non-negative integer.
|
||||
validate_prediction_historic_hours (int): Ensures `prediction_historic_hours` is a non-negative integer.
|
||||
validate_hours (int): Ensures `hours` is a non-negative integer.
|
||||
validate_historic_hours (int): Ensures `historic_hours` is a non-negative integer.
|
||||
validate_latitude (float): Ensures `latitude` is within the range -90 to 90.
|
||||
validate_longitude (float): Ensures `longitude` is within the range -180 to 180.
|
||||
"""
|
||||
|
||||
prediction_hours: Optional[int] = Field(
|
||||
hours: Optional[int] = Field(
|
||||
default=48, ge=0, description="Number of hours into the future for predictions"
|
||||
)
|
||||
prediction_historic_hours: Optional[int] = Field(
|
||||
historic_hours: Optional[int] = Field(
|
||||
default=48,
|
||||
ge=0,
|
||||
description="Number of hours into the past for historical predictions data",
|
||||
|
@@ -114,16 +114,16 @@ class PredictionStartEndKeepMixin(PredictionBase):
|
||||
@computed_field # type: ignore[prop-decorator]
|
||||
@property
|
||||
def end_datetime(self) -> Optional[DateTime]:
|
||||
"""Compute the end datetime based on the `start_datetime` and `prediction_hours`.
|
||||
"""Compute the end datetime based on the `start_datetime` and `hours`.
|
||||
|
||||
Ajusts the calculated end time if DST transitions occur within the prediction window.
|
||||
|
||||
Returns:
|
||||
Optional[DateTime]: The calculated end datetime, or `None` if inputs are missing.
|
||||
"""
|
||||
if self.start_datetime and self.config.prediction.prediction_hours:
|
||||
if self.start_datetime and self.config.prediction.hours:
|
||||
end_datetime = self.start_datetime + to_duration(
|
||||
f"{self.config.prediction.prediction_hours} hours"
|
||||
f"{self.config.prediction.hours} hours"
|
||||
)
|
||||
dst_change = end_datetime.offset_hours - self.start_datetime.offset_hours
|
||||
logger.debug(f"Pre: {self.start_datetime}..{end_datetime}: DST change: {dst_change}")
|
||||
@@ -147,10 +147,10 @@ class PredictionStartEndKeepMixin(PredictionBase):
|
||||
return None
|
||||
historic_hours = self.historic_hours_min()
|
||||
if (
|
||||
self.config.prediction.prediction_historic_hours
|
||||
and self.config.prediction.prediction_historic_hours > historic_hours
|
||||
self.config.prediction.historic_hours
|
||||
and self.config.prediction.historic_hours > historic_hours
|
||||
):
|
||||
historic_hours = int(self.config.prediction.prediction_historic_hours)
|
||||
historic_hours = int(self.config.prediction.historic_hours)
|
||||
return self.start_datetime - to_duration(f"{historic_hours} hours")
|
||||
|
||||
@computed_field # type: ignore[prop-decorator]
|
||||
|
@@ -19,7 +19,7 @@ class PVForecastCommonSettings(SettingsBaseModel):
|
||||
# Inverter Parameters
|
||||
# https://pvlib-python.readthedocs.io/en/stable/_modules/pvlib/inverter.html
|
||||
|
||||
pvforecast_provider: Optional[str] = Field(
|
||||
provider: Optional[str] = Field(
|
||||
default=None,
|
||||
description="PVForecast provider id of provider to be used.",
|
||||
examples=["PVForecastAkkudoktor"],
|
||||
|
@@ -28,18 +28,18 @@ class PVForecastProvider(PredictionProvider):
|
||||
PVForecastProvider is a thread-safe singleton, ensuring only one instance of this class is created.
|
||||
|
||||
Configuration variables:
|
||||
pvforecast_provider (str): Prediction provider for pvforecast.
|
||||
provider (str): Prediction provider for pvforecast.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
prediction_historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
latitude (float, optional): The latitude in degrees, must be within -90 to 90.
|
||||
longitude (float, optional): The longitude in degrees, must be within -180 to 180.
|
||||
start_datetime (datetime, optional): The starting datetime for predictions (inlcusive), defaults to the current datetime if unspecified.
|
||||
end_datetime (datetime, computed): The datetime representing the end of the prediction range (exclusive),
|
||||
calculated based on `start_datetime` and `prediction_hours`.
|
||||
calculated based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The earliest datetime for retaining historical data (inclusive), calculated
|
||||
based on `start_datetime` and `prediction_historic_hours`.
|
||||
based on `start_datetime` and `historic_hours`.
|
||||
"""
|
||||
|
||||
# overload
|
||||
@@ -54,6 +54,6 @@ class PVForecastProvider(PredictionProvider):
|
||||
|
||||
def enabled(self) -> bool:
|
||||
logger.debug(
|
||||
f"PVForecastProvider ID {self.provider_id()} vs. config {self.config.pvforecast.pvforecast_provider}"
|
||||
f"PVForecastProvider ID {self.provider_id()} vs. config {self.config.pvforecast.provider}"
|
||||
)
|
||||
return self.provider_id() == self.config.pvforecast.pvforecast_provider
|
||||
return self.provider_id() == self.config.pvforecast.provider
|
||||
|
@@ -14,21 +14,25 @@ Classes:
|
||||
Example:
|
||||
# Set up the configuration with necessary fields for URL generation
|
||||
settings_data = {
|
||||
"prediction_hours": 48,
|
||||
"prediction_historic_hours": 24,
|
||||
"latitude": 52.52,
|
||||
"longitude": 13.405,
|
||||
"pvforecast_provider": "Akkudoktor",
|
||||
"pvforecast0_peakpower": 5.0,
|
||||
"pvforecast0_surface_azimuth": -10,
|
||||
"pvforecast0_surface_tilt": 7,
|
||||
"pvforecast0_userhorizon": [20, 27, 22, 20],
|
||||
"pvforecast0_inverter_paco": 10000,
|
||||
"pvforecast1_peakpower": 4.8,
|
||||
"pvforecast1_surface_azimuth": -90,
|
||||
"pvforecast1_surface_tilt": 7,
|
||||
"pvforecast1_userhorizon": [30, 30, 30, 50],
|
||||
"pvforecast1_inverter_paco": 10000,
|
||||
"prediction": {
|
||||
"hours": 48,
|
||||
"historic_hours": 24,
|
||||
"latitude": 52.52,
|
||||
"longitude": 13.405,
|
||||
},
|
||||
"pvforecast": {
|
||||
"provider": "PVForecastAkkudoktor",
|
||||
"pvforecast0_peakpower": 5.0,
|
||||
"pvforecast0_surface_azimuth": -10,
|
||||
"pvforecast0_surface_tilt": 7,
|
||||
"pvforecast0_userhorizon": [20, 27, 22, 20],
|
||||
"pvforecast0_inverter_paco": 10000,
|
||||
"pvforecast1_peakpower": 4.8,
|
||||
"pvforecast1_surface_azimuth": -90,
|
||||
"pvforecast1_surface_tilt": 7,
|
||||
"pvforecast1_userhorizon": [30, 30, 30, 50],
|
||||
"pvforecast1_inverter_paco": 10000,
|
||||
}
|
||||
}
|
||||
|
||||
# Create the config instance from the provided data
|
||||
@@ -47,12 +51,12 @@ Example:
|
||||
print(forecast.report_ac_power_and_measurement())
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int): Number of hours into the future to forecast. Default is 48.
|
||||
prediction_historic_hours (int): Number of past hours to retain for analysis. Default is 24.
|
||||
hours (int): Number of hours into the future to forecast. Default is 48.
|
||||
historic_hours (int): Number of past hours to retain for analysis. Default is 24.
|
||||
latitude (float): Latitude for the forecast location.
|
||||
longitude (float): Longitude for the forecast location.
|
||||
start_datetime (datetime): Start time for the forecast, defaulting to current datetime.
|
||||
end_datetime (datetime): Computed end datetime based on `start_datetime` and `prediction_hours`.
|
||||
end_datetime (datetime): Computed end datetime based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime): Computed threshold datetime for retaining historical data.
|
||||
|
||||
Methods:
|
||||
@@ -159,13 +163,13 @@ class PVForecastAkkudoktor(PVForecastProvider):
|
||||
of hours into the future and retains historical data.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): Number of hours in the future for the forecast.
|
||||
prediction_historic_hours (int, optional): Number of past hours for retaining data.
|
||||
hours (int, optional): Number of hours in the future for the forecast.
|
||||
historic_hours (int, optional): Number of past hours for retaining data.
|
||||
latitude (float, optional): The latitude in degrees, validated to be between -90 and 90.
|
||||
longitude (float, optional): The longitude in degrees, validated to be between -180 and 180.
|
||||
start_datetime (datetime, optional): Start datetime for forecasts, defaults to the current datetime.
|
||||
end_datetime (datetime, computed): The forecast's end datetime, computed based on `start_datetime` and `prediction_hours`.
|
||||
keep_datetime (datetime, computed): The datetime to retain historical data, computed from `start_datetime` and `prediction_historic_hours`.
|
||||
end_datetime (datetime, computed): The forecast's end datetime, computed based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The datetime to retain historical data, computed from `start_datetime` and `historic_hours`.
|
||||
|
||||
Methods:
|
||||
provider_id(): Returns a unique identifier for the provider.
|
||||
@@ -286,10 +290,10 @@ class PVForecastAkkudoktor(PVForecastProvider):
|
||||
|
||||
# Assumption that all lists are the same length and are ordered chronologically
|
||||
# in ascending order and have the same timestamps.
|
||||
if len(akkudoktor_data.values[0]) < self.config.prediction.prediction_hours:
|
||||
if len(akkudoktor_data.values[0]) < self.config.prediction.hours:
|
||||
# Expect one value set per prediction hour
|
||||
error_msg = (
|
||||
f"The forecast must cover at least {self.config.prediction.prediction_hours} hours, "
|
||||
f"The forecast must cover at least {self.config.prediction.hours} hours, "
|
||||
f"but only {len(akkudoktor_data.values[0])} data sets are given in forecast data."
|
||||
)
|
||||
logger.error(f"Akkudoktor schema change: {error_msg}")
|
||||
@@ -318,9 +322,9 @@ class PVForecastAkkudoktor(PVForecastProvider):
|
||||
|
||||
self.update_value(dt, data)
|
||||
|
||||
if len(self) < self.config.prediction.prediction_hours:
|
||||
if len(self) < self.config.prediction.hours:
|
||||
raise ValueError(
|
||||
f"The forecast must cover at least {self.config.prediction.prediction_hours} hours, "
|
||||
f"The forecast must cover at least {self.config.prediction.hours} hours, "
|
||||
f"but only {len(self)} hours starting from {self.start_datetime} "
|
||||
f"were predicted."
|
||||
)
|
||||
@@ -370,13 +374,13 @@ if __name__ == "__main__":
|
||||
# Set up the configuration with necessary fields for URL generation
|
||||
settings_data = {
|
||||
"prediction": {
|
||||
"prediction_hours": 48,
|
||||
"prediction_historic_hours": 24,
|
||||
"hours": 48,
|
||||
"historic_hours": 24,
|
||||
"latitude": 52.52,
|
||||
"longitude": 13.405,
|
||||
},
|
||||
"pvforecast": {
|
||||
"pvforecast_provider": "PVForecastAkkudoktor",
|
||||
"provider": "PVForecastAkkudoktor",
|
||||
"pvforecast0_peakpower": 5.0,
|
||||
"pvforecast0_surface_azimuth": -10,
|
||||
"pvforecast0_surface_tilt": 7,
|
||||
|
@@ -11,7 +11,7 @@ from akkudoktoreos.prediction.weatherimport import WeatherImportCommonSettings
|
||||
class WeatherCommonSettings(SettingsBaseModel):
|
||||
"""Weather Forecast Configuration."""
|
||||
|
||||
weather_provider: Optional[str] = Field(
|
||||
provider: Optional[str] = Field(
|
||||
default=None,
|
||||
description="Weather provider id of provider to be used.",
|
||||
examples=["WeatherImport"],
|
||||
|
@@ -101,18 +101,18 @@ class WeatherProvider(PredictionProvider):
|
||||
WeatherProvider is a thread-safe singleton, ensuring only one instance of this class is created.
|
||||
|
||||
Configuration variables:
|
||||
weather_provider (str): Prediction provider for weather.
|
||||
provider (str): Prediction provider for weather.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
prediction_historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
latitude (float, optional): The latitude in degrees, must be within -90 to 90.
|
||||
longitude (float, optional): The longitude in degrees, must be within -180 to 180.
|
||||
start_datetime (datetime, optional): The starting datetime for predictions, defaults to the current datetime if unspecified.
|
||||
end_datetime (datetime, computed): The datetime representing the end of the prediction range,
|
||||
calculated based on `start_datetime` and `prediction_hours`.
|
||||
calculated based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The earliest datetime for retaining historical data, calculated
|
||||
based on `start_datetime` and `prediction_historic_hours`.
|
||||
based on `start_datetime` and `historic_hours`.
|
||||
"""
|
||||
|
||||
# overload
|
||||
@@ -126,7 +126,7 @@ class WeatherProvider(PredictionProvider):
|
||||
return "WeatherProvider"
|
||||
|
||||
def enabled(self) -> bool:
|
||||
return self.provider_id() == self.config.weather.weather_provider
|
||||
return self.provider_id() == self.config.weather.provider
|
||||
|
||||
@classmethod
|
||||
def estimate_irradiance_from_cloud_cover(
|
||||
|
@@ -62,13 +62,13 @@ class WeatherBrightSky(WeatherProvider):
|
||||
of hours into the future and retains historical data.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): Number of hours in the future for the forecast.
|
||||
prediction_historic_hours (int, optional): Number of past hours for retaining data.
|
||||
hours (int, optional): Number of hours in the future for the forecast.
|
||||
historic_hours (int, optional): Number of past hours for retaining data.
|
||||
latitude (float, optional): The latitude in degrees, validated to be between -90 and 90.
|
||||
longitude (float, optional): The longitude in degrees, validated to be between -180 and 180.
|
||||
start_datetime (datetime, optional): Start datetime for forecasts, defaults to the current datetime.
|
||||
end_datetime (datetime, computed): The forecast's end datetime, computed based on `start_datetime` and `prediction_hours`.
|
||||
keep_datetime (datetime, computed): The datetime to retain historical data, computed from `start_datetime` and `prediction_historic_hours`.
|
||||
end_datetime (datetime, computed): The forecast's end datetime, computed based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The datetime to retain historical data, computed from `start_datetime` and `historic_hours`.
|
||||
|
||||
Methods:
|
||||
provider_id(): Returns a unique identifier for the provider.
|
||||
|
@@ -68,15 +68,15 @@ class WeatherClearOutside(WeatherProvider):
|
||||
WeatherClearOutside is a thread-safe singleton, ensuring only one instance of this class is created.
|
||||
|
||||
Attributes:
|
||||
prediction_hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
prediction_historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
hours (int, optional): The number of hours into the future for which predictions are generated.
|
||||
historic_hours (int, optional): The number of past hours for which historical data is retained.
|
||||
latitude (float, optional): The latitude in degrees, must be within -90 to 90.
|
||||
longitude (float, optional): The longitude in degrees, must be within -180 to 180.
|
||||
start_datetime (datetime, optional): The starting datetime for predictions, defaults to the current datetime if unspecified.
|
||||
end_datetime (datetime, computed): The datetime representing the end of the prediction range,
|
||||
calculated based on `start_datetime` and `prediction_hours`.
|
||||
calculated based on `start_datetime` and `hours`.
|
||||
keep_datetime (datetime, computed): The earliest datetime for retaining historical data, calculated
|
||||
based on `start_datetime` and `prediction_historic_hours`.
|
||||
based on `start_datetime` and `historic_hours`.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
|
@@ -22,22 +22,22 @@ logger = get_logger(__name__)
|
||||
class WeatherImportCommonSettings(SettingsBaseModel):
|
||||
"""Common settings for weather data import from file or JSON string."""
|
||||
|
||||
weatherimport_file_path: Optional[Union[str, Path]] = Field(
|
||||
import_file_path: Optional[Union[str, Path]] = Field(
|
||||
default=None,
|
||||
description="Path to the file to import weather data from.",
|
||||
examples=[None, "/path/to/weather_data.json"],
|
||||
)
|
||||
|
||||
weatherimport_json: Optional[str] = Field(
|
||||
import_json: Optional[str] = Field(
|
||||
default=None,
|
||||
description="JSON string, dictionary of weather forecast value lists.",
|
||||
examples=['{"weather_temp_air": [18.3, 17.8, 16.9]}'],
|
||||
)
|
||||
|
||||
# Validators
|
||||
@field_validator("weatherimport_file_path", mode="after")
|
||||
@field_validator("import_file_path", mode="after")
|
||||
@classmethod
|
||||
def validate_weatherimport_file_path(cls, value: Optional[Union[str, Path]]) -> Optional[Path]:
|
||||
def validate_import_file_path(cls, value: Optional[Union[str, Path]]) -> Optional[Path]:
|
||||
if value is None:
|
||||
return None
|
||||
if isinstance(value, str):
|
||||
@@ -63,11 +63,11 @@ class WeatherImport(WeatherProvider, PredictionImportProvider):
|
||||
return "WeatherImport"
|
||||
|
||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||
if self.config.weather.provider_settings.weatherimport_file_path is not None:
|
||||
if self.config.weather.provider_settings.import_file_path is not None:
|
||||
self.import_from_file(
|
||||
self.config.weather.provider_settings.weatherimport_file_path, key_prefix="weather"
|
||||
self.config.weather.provider_settings.import_file_path, key_prefix="weather"
|
||||
)
|
||||
if self.config.weather.provider_settings.weatherimport_json is not None:
|
||||
if self.config.weather.provider_settings.import_json is not None:
|
||||
self.import_from_json(
|
||||
self.config.weather.provider_settings.weatherimport_json, key_prefix="weather"
|
||||
self.config.weather.provider_settings.import_json, key_prefix="weather"
|
||||
)
|
||||
|
Reference in New Issue
Block a user