mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-13 17:41:56 +00:00
fix: surface DVhub feed-in tariff update failures (#1357)
* fix: surface DVhub feed-in tariff update failures * test: annotate DVhub sample records for mypy * fix: require real feed-in tariff coverage in GENETIC0 * test: satisfy GENETIC0 tariff coverage checks * test: patch DVhub storage method on its class
This commit is contained in:
@@ -8,6 +8,7 @@ It also provides a method to assemble these parameters from predictions,
|
||||
forecasts, and fallback defaults, preparing them for optimization runs.
|
||||
"""
|
||||
|
||||
import math
|
||||
from typing import Optional, Union
|
||||
|
||||
from loguru import logger
|
||||
@@ -36,6 +37,7 @@ from akkudoktoreos.devices.genetic0.genetic0homeappliance import (
|
||||
)
|
||||
from akkudoktoreos.devices.genetic0.genetic0inverter import Genetic0InverterParameters
|
||||
from akkudoktoreos.optimization.genetic0.genetic0abc import Genetic0ParametersBaseModel
|
||||
from akkudoktoreos.optimization.genetic.forecast import bounded_forecast_array
|
||||
from akkudoktoreos.utils.datetimeutil import to_duration
|
||||
|
||||
# Do not import directly from akkudoktoreos.core.coreabc
|
||||
@@ -506,41 +508,28 @@ class Genetic0OptimizationParameters(
|
||||
)
|
||||
# Retry
|
||||
continue
|
||||
try:
|
||||
array = await cls.prediction.key_to_array(
|
||||
key="feed_in_tariff_wh",
|
||||
start_datetime=parameter_start_datetime,
|
||||
end_datetime=parameter_end_datetime,
|
||||
interval=interval,
|
||||
fill_method="ffill",
|
||||
tariff_values = await bounded_forecast_array(
|
||||
cls.prediction,
|
||||
key="feed_in_tariff_wh",
|
||||
start_datetime=parameter_start_datetime,
|
||||
end_datetime=parameter_end_datetime,
|
||||
interval=interval,
|
||||
)
|
||||
first = int(
|
||||
(ems.start_datetime - parameter_start_datetime).total_seconds()
|
||||
/ interval.total_seconds()
|
||||
)
|
||||
last = first + cls.config.optimization.genetic0.horizon_hours
|
||||
if last > len(tariff_values) or not all(
|
||||
math.isfinite(value) for value in tariff_values[first:last]
|
||||
):
|
||||
logger.error(
|
||||
"Missing feed-in tariff within the GENETIC0 control horizon; "
|
||||
"canceling optimization with provider {}.",
|
||||
cls.config.feedintariff.provider,
|
||||
)
|
||||
feed_in_tariff_wh = array.tolist()
|
||||
except Exception as e:
|
||||
logger.info(
|
||||
"No feed in tariff forecast data available - defaulting to demo data. Parameter preparation attempt {}: {}",
|
||||
attempt,
|
||||
e,
|
||||
)
|
||||
cls.config.merge_settings_from_dict(
|
||||
{
|
||||
"feedintariff": {
|
||||
"provider": "FeedInTariffFixed",
|
||||
"feedintarifffixed": {
|
||||
"feed_in_tariff_amt_kwh": {
|
||||
"windows": [
|
||||
{
|
||||
"start_time": "00:00",
|
||||
"duration": "24 hours",
|
||||
"value": 0.078,
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
# Retry
|
||||
continue
|
||||
return None
|
||||
feed_in_tariff_wh = tariff_values.tolist()
|
||||
|
||||
# Add device data
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ class FeedInTariffDvhubOnline(FeedInTariffProvider):
|
||||
market price is stored as ``feed_in_tariff_wh`` (EUR/Wh) — like
|
||||
``FeedInTariffEnergyCharts`` this intentionally adds no import charges or
|
||||
VAT, so the series is the direct-marketing revenue the optimizer needs.
|
||||
Slots beyond the published day-ahead horizon are left to the consumer's
|
||||
forward-fill (same behaviour as ``FeedInTariffImport``).
|
||||
Only published slots are stored. Automatic optimization requires real
|
||||
tariff coverage for the GENETIC or GENETIC0 control horizon.
|
||||
"""
|
||||
|
||||
highest_orig_datetime: Optional[datetime] = None
|
||||
@@ -124,24 +124,11 @@ class FeedInTariffDvhubOnline(FeedInTariffProvider):
|
||||
)
|
||||
end_date = to_datetime(self.end_datetime, as_string="YYYY-MM-DD")
|
||||
|
||||
try:
|
||||
dvhub_data = self._request_forecast(
|
||||
start_date=start_date, end_date=end_date, force_update=force_update
|
||||
) # type: ignore[call-arg]
|
||||
series_data = self._parse_data(dvhub_data)
|
||||
if series_data.empty:
|
||||
raise ValueError("No dvhub.online feed-in tariff data available")
|
||||
self.highest_orig_datetime = series_data.index.max()
|
||||
await self.key_from_series("feed_in_tariff_wh", series_data)
|
||||
except Exception as exc:
|
||||
if self.highest_orig_datetime is None:
|
||||
# Cold start: nothing to fall back to — a failed fetch is fatal.
|
||||
raise
|
||||
# Transient outage with existing history: keep the history and let
|
||||
# downstream forward-fill cover the remaining slots.
|
||||
logger.warning(
|
||||
"dvhub.online feed-in tariff update failed ({}); keeping existing "
|
||||
"history until {}.",
|
||||
exc,
|
||||
self.highest_orig_datetime,
|
||||
)
|
||||
dvhub_data = self._request_forecast(
|
||||
start_date=start_date, end_date=end_date, force_update=force_update
|
||||
) # type: ignore[call-arg]
|
||||
series_data = self._parse_data(dvhub_data)
|
||||
if series_data.empty:
|
||||
raise ValueError("No dvhub.online feed-in tariff data available")
|
||||
await self.key_from_series("feed_in_tariff_wh", series_data)
|
||||
self.highest_orig_datetime = series_data.index.max()
|
||||
|
||||
Reference in New Issue
Block a user