mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-11-21 12:56:27 +00:00
feat: add bidding zone to energy charts price prediction (#765)
Energy charts supports bidding zones. Allow to specifiy the bidding zone in the configuration. Extend and simplify ElecPrice configuration structure and setup config migration to automatically update the configuration file. Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
@@ -21,11 +21,14 @@ if TYPE_CHECKING:
|
||||
# - tuple[str, Callable[[Any], Any]] (new path + transform)
|
||||
# - None (drop)
|
||||
MIGRATION_MAP: Dict[str, Union[str, Tuple[str, Callable[[Any], Any]], None]] = {
|
||||
# 0.1.0 -> 0.2.0
|
||||
# 0.2.0 -> 0.2.0+dev
|
||||
"elecprice/provider_settings/ElecPriceImport/import_file_path": "elecprice/elecpriceimport/import_file_path",
|
||||
"elecprice/provider_settings/ElecPriceImport/import_json": "elecprice/elecpriceimport/import_json",
|
||||
# 0.1.0 -> 0.2.0+dev
|
||||
"devices/batteries/0/initial_soc_percentage": None,
|
||||
"devices/electric_vehicles/0/initial_soc_percentage": None,
|
||||
"elecprice/provider_settings/import_file_path": "elecprice/provider_settings/ElecPriceImport/import_file_path",
|
||||
"elecprice/provider_settings/import_json": "elecprice/provider_settings/ElecPriceImport/import_json",
|
||||
"elecprice/provider_settings/import_file_path": "elecprice/elecpriceimport/import_file_path",
|
||||
"elecprice/provider_settings/import_json": "elecprice/elecpriceimport/import_json",
|
||||
"load/provider_settings/import_file_path": "load/provider_settings/LoadImport/import_file_path",
|
||||
"load/provider_settings/import_json": "load/provider_settings/LoadImport/import_json",
|
||||
"load/provider_settings/loadakkudoktor_year_energy": "load/provider_settings/LoadAkkudoktor/loadakkudoktor_year_energy_kwh",
|
||||
|
||||
@@ -4,6 +4,9 @@ from pydantic import Field, field_validator
|
||||
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel
|
||||
from akkudoktoreos.prediction.elecpriceabc import ElecPriceProvider
|
||||
from akkudoktoreos.prediction.elecpriceenergycharts import (
|
||||
ElecPriceEnergyChartsCommonSettings,
|
||||
)
|
||||
from akkudoktoreos.prediction.elecpriceimport import ElecPriceImportCommonSettings
|
||||
from akkudoktoreos.prediction.prediction import get_prediction
|
||||
|
||||
@@ -17,15 +20,6 @@ elecprice_providers = [
|
||||
]
|
||||
|
||||
|
||||
class ElecPriceCommonProviderSettings(SettingsBaseModel):
|
||||
"""Electricity Price Prediction Provider Configuration."""
|
||||
|
||||
ElecPriceImport: Optional[ElecPriceImportCommonSettings] = Field(
|
||||
default=None,
|
||||
json_schema_extra={"description": "ElecPriceImport settings", "examples": [None]},
|
||||
)
|
||||
|
||||
|
||||
class ElecPriceCommonSettings(SettingsBaseModel):
|
||||
"""Electricity Price Prediction Configuration."""
|
||||
|
||||
@@ -53,17 +47,14 @@ class ElecPriceCommonSettings(SettingsBaseModel):
|
||||
},
|
||||
)
|
||||
|
||||
provider_settings: ElecPriceCommonProviderSettings = Field(
|
||||
default_factory=ElecPriceCommonProviderSettings,
|
||||
json_schema_extra={
|
||||
"description": "Provider settings",
|
||||
"examples": [
|
||||
# Example 1: Empty/default settings (all providers None)
|
||||
{
|
||||
"ElecPriceImport": None,
|
||||
},
|
||||
],
|
||||
},
|
||||
elecpriceimport: ElecPriceImportCommonSettings = Field(
|
||||
default_factory=ElecPriceImportCommonSettings,
|
||||
json_schema_extra={"description": "Import provider settings."},
|
||||
)
|
||||
|
||||
energycharts: ElecPriceEnergyChartsCommonSettings = Field(
|
||||
default_factory=ElecPriceEnergyChartsCommonSettings,
|
||||
json_schema_extra={"description": "Energy Charts provider settings."},
|
||||
)
|
||||
|
||||
# Validators
|
||||
|
||||
@@ -7,21 +7,44 @@ format, enabling consistent access to forecasted and historical electricity pric
|
||||
"""
|
||||
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
from typing import Any, List, Optional, Union
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import requests
|
||||
from loguru import logger
|
||||
from pydantic import ValidationError
|
||||
from pydantic import Field, ValidationError
|
||||
from statsmodels.tsa.holtwinters import ExponentialSmoothing
|
||||
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel
|
||||
from akkudoktoreos.core.cache import cache_in_file
|
||||
from akkudoktoreos.core.pydantic import PydanticBaseModel
|
||||
from akkudoktoreos.prediction.elecpriceabc import ElecPriceProvider
|
||||
from akkudoktoreos.utils.datetimeutil import to_datetime, to_duration
|
||||
|
||||
|
||||
class EnergyChartsBiddingZones(str, Enum):
|
||||
"""Energy Charts Bidding Zones."""
|
||||
|
||||
AT = "AT"
|
||||
BE = "BE"
|
||||
CH = "CH"
|
||||
CZ = "CZ"
|
||||
DE_LU = "DE-LU"
|
||||
DE_AT_LU = "DE-AT-LU"
|
||||
DK1 = "DK1"
|
||||
DK2 = "DK2"
|
||||
FR = "FR"
|
||||
HU = "HU"
|
||||
IT_North = "IT-NORTH"
|
||||
NL = "NL"
|
||||
NO2 = "NO2"
|
||||
PL = "PL"
|
||||
SE4 = "SE4"
|
||||
SI = "SI"
|
||||
|
||||
|
||||
class EnergyChartsElecPrice(PydanticBaseModel):
|
||||
license_info: str
|
||||
unix_seconds: List[int]
|
||||
@@ -30,6 +53,21 @@ class EnergyChartsElecPrice(PydanticBaseModel):
|
||||
deprecated: bool
|
||||
|
||||
|
||||
class ElecPriceEnergyChartsCommonSettings(SettingsBaseModel):
|
||||
"""Common settings for Energy Charts electricity price provider."""
|
||||
|
||||
bidding_zone: EnergyChartsBiddingZones = Field(
|
||||
default=EnergyChartsBiddingZones.DE_LU,
|
||||
json_schema_extra={
|
||||
"description": (
|
||||
"Bidding Zone: 'AT', 'BE', 'CH', 'CZ', 'DE-LU', 'DE-AT-LU', 'DK1', 'DK2', 'FR', "
|
||||
"'HU', 'IT-NORTH', 'NL', 'NO2', 'PL', 'SE4' or 'SI'"
|
||||
),
|
||||
"examples": ["AT"],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
class ElecPriceEnergyCharts(ElecPriceProvider):
|
||||
"""Fetch and process electricity price forecast data from Energy-Charts.
|
||||
|
||||
@@ -95,7 +133,8 @@ class ElecPriceEnergyCharts(ElecPriceProvider):
|
||||
)
|
||||
|
||||
last_date = to_datetime(self.end_datetime, as_string="YYYY-MM-DD")
|
||||
url = f"{source}/price?bzn=DE-LU&start={start_date}&end={last_date}"
|
||||
bidding_zone = str(self.config.elecprice.energycharts.bidding_zone)
|
||||
url = f"{source}/price?bzn={bidding_zone}&start={start_date}&end={last_date}"
|
||||
response = requests.get(url, timeout=30)
|
||||
logger.debug(f"Response from {url}: {response}")
|
||||
response.raise_for_status() # Raise an error for bad responses
|
||||
|
||||
@@ -9,7 +9,6 @@ format, enabling consistent access to forecasted and historical elecprice attrib
|
||||
from pathlib import Path
|
||||
from typing import Optional, Union
|
||||
|
||||
from loguru import logger
|
||||
from pydantic import Field, field_validator
|
||||
|
||||
from akkudoktoreos.config.configabc import SettingsBaseModel
|
||||
@@ -65,16 +64,13 @@ class ElecPriceImport(ElecPriceProvider, PredictionImportProvider):
|
||||
return "ElecPriceImport"
|
||||
|
||||
def _update_data(self, force_update: Optional[bool] = False) -> None:
|
||||
if self.config.elecprice.provider_settings.ElecPriceImport is None:
|
||||
logger.debug(f"{self.provider_id()} data update without provider settings.")
|
||||
return
|
||||
if self.config.elecprice.provider_settings.ElecPriceImport.import_file_path:
|
||||
if self.config.elecprice.elecpriceimport.import_file_path:
|
||||
self.import_from_file(
|
||||
self.config.elecprice.provider_settings.ElecPriceImport.import_file_path,
|
||||
self.config.elecprice.elecpriceimport.import_file_path,
|
||||
key_prefix="elecprice",
|
||||
)
|
||||
if self.config.elecprice.provider_settings.ElecPriceImport.import_json:
|
||||
if self.config.elecprice.elecpriceimport.import_json:
|
||||
self.import_from_json(
|
||||
self.config.elecprice.provider_settings.ElecPriceImport.import_json,
|
||||
self.config.elecprice.elecpriceimport.import_json,
|
||||
key_prefix="elecprice",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user