feat: add dvhubonline feed-in tariff provider (#1193)
Some checks failed
Bump Version / Bump Version Workflow (push) Has been cancelled
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
docker-build / platform-excludes (push) Has been cancelled
docker-build / build (push) Has been cancelled
docker-build / merge (push) Has been cancelled
pre-commit / pre-commit (push) Has been cancelled
Run Pytest on Pull Request / test (push) Has been cancelled
Close stale pull requests/issues / Find Stale issues and PRs (push) Has been cancelled

Fetches GET /api/prices?start&end&zone (15-min slots, EUR/MWh) and stores
the raw market price as feed_in_tariff_wh (EUR/Wh) — no import charges/VAT.

Slots beyond the day-ahead horizon are left to the consumer's forward-fill
(FeedInTariffImport behaviour).

5 unit tests + opt-in live smoke (EOS_DVHUB_ONLINE_LIVE=1, passing).

Signed-off-by: Christin <info@bikinibottom.capital>
Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
This commit is contained in:
Bobby Noelte
2026-07-29 22:21:17 +02:00
committed by GitHub
parent 3c1f5d8bc0
commit 52fe489d4e
13 changed files with 381 additions and 22 deletions

2
.env
View File

@@ -11,7 +11,7 @@ DOCKER_COMPOSE_DATA_DIR=${HOME}/.local/share/net.akkudoktor.eos
# -----------------------------------------------------------------------------
# Image / build
# -----------------------------------------------------------------------------
VERSION=0.3.0.dev2607290898922686
VERSION=0.3.0.dev2607290944830210
PYTHON_VERSION=3.13.9
# -----------------------------------------------------------------------------

View File

@@ -6,7 +6,7 @@
# the root directory (no add-on folder as usual).
name: "Akkudoktor-EOS"
version: "0.3.0.dev2607290898922686"
version: "0.3.0.dev2607290944830210"
slug: "eos"
description: "Akkudoktor-EOS add-on"
url: "https://github.com/Akkudoktor-EOS/EOS"

View File

@@ -130,6 +130,10 @@
"import_file_path": null,
"import_json": null
},
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
},
"energycharts": {
"bidding_zone": "DE-LU"
}

View File

@@ -7,6 +7,7 @@
| Name | Environment Variable | Type | Read-Only | Default | Description |
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
| dvhubonline | `EOS_FEEDINTARIFF__DVHUBONLINE` | `FeedInTariffDvhubOnlineCommonSettings` | `rw` | `required` | DvhubOnline feed in tariff provider settings. |
| energycharts | `EOS_FEEDINTARIFF__ENERGYCHARTS` | `FeedInTariffEnergyChartsCommonSettings` | `rw` | `required` | EnergyCharts feed in tariff provider settings. |
| feedintarifffixed | `EOS_FEEDINTARIFF__FEEDINTARIFFFIXED` | `FeedInTariffFixedCommonSettings` | `rw` | `required` | Fixed feed in tariff provider settings. |
| feedintariffimport | `EOS_FEEDINTARIFF__FEEDINTARIFFIMPORT` | `FeedInTariffImportCommonSettings` | `rw` | `required` | Feed in tarif import provider settings. |
@@ -31,6 +32,10 @@
"import_file_path": null,
"import_json": null
},
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
},
"energycharts": {
"bidding_zone": "DE-LU"
}
@@ -55,11 +60,16 @@
"import_file_path": null,
"import_json": null
},
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
},
"energycharts": {
"bidding_zone": "DE-LU"
},
"providers": [
"FeedInTariffAkkudoktor",
"FeedInTariffDvhubOnline",
"FeedInTariffEnergyCharts",
"FeedInTariffFixed",
"FeedInTariffImport",
@@ -158,3 +168,34 @@
}
```
<!-- pyml enable line-length -->
### Common settings for the dvhub.online feed-in tariff provider
<!-- pyml disable line-length -->
:::{table} feedintariff::dvhubonline
:widths: 10 10 5 5 30
:align: left
| Name | Type | Read-Only | Default | Description |
| ---- | ---- | --------- | ------- | ----------- |
| base_url | `str` | `rw` | `https://dvhub.online` | Base URL of the dvhub.online price API. |
| zone | `str` | `rw` | `DE-LU` | Bidding zone passed to the dvhub.online price API. |
:::
<!-- pyml enable line-length -->
<!-- pyml disable no-emphasis-as-heading -->
**Example Input/Output**
<!-- pyml enable no-emphasis-as-heading -->
<!-- pyml disable line-length -->
```json
{
"feedintariff": {
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
}
}
}
```
<!-- pyml enable line-length -->

View File

@@ -1,6 +1,6 @@
# Akkudoktor-EOS
**Version**: `v0.3.0.dev2607290898922686`
**Version**: `v0.3.0.dev2607290944830210`
<!-- pyml disable line-length -->
**Description**: This project provides a comprehensive solution for simulating and optimizing an energy system based on renewable energy sources. With a focus on photovoltaic (PV) systems, battery storage (batteries), load management (consumer requirements), heat pumps, electric vehicles, and consideration of electricity price data, this system enables forecasting and optimization of energy flow and costs over a specified period.

View File

@@ -8,7 +8,7 @@
"name": "Apache 2.0",
"url": "https://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "v0.3.0.dev2607290898922686"
"version": "v0.3.0.dev2607290944830210"
},
"paths": {
"/v1/admin/cache/clear": {
@@ -4322,6 +4322,10 @@
"$ref": "#/components/schemas/FeedInTariffImportCommonSettings",
"description": "Feed in tarif import provider settings."
},
"dvhubonline": {
"$ref": "#/components/schemas/FeedInTariffDvhubOnlineCommonSettings",
"description": "DvhubOnline feed in tariff provider settings."
},
"energycharts": {
"$ref": "#/components/schemas/FeedInTariffEnergyChartsCommonSettings",
"description": "EnergyCharts feed in tariff provider settings."
@@ -4357,6 +4361,10 @@
"$ref": "#/components/schemas/FeedInTariffImportCommonSettings",
"description": "Feed in tarif import provider settings."
},
"dvhubonline": {
"$ref": "#/components/schemas/FeedInTariffDvhubOnlineCommonSettings",
"description": "DvhubOnline feed in tariff provider settings."
},
"energycharts": {
"$ref": "#/components/schemas/FeedInTariffEnergyChartsCommonSettings",
"description": "EnergyCharts feed in tariff provider settings."
@@ -4378,6 +4386,31 @@
"title": "FeedInTariffCommonSettings",
"description": "Feed In Tariff Prediction Configuration."
},
"FeedInTariffDvhubOnlineCommonSettings": {
"properties": {
"base_url": {
"type": "string",
"title": "Base Url",
"description": "Base URL of the dvhub.online price API.",
"default": "https://dvhub.online",
"examples": [
"https://dvhub.online"
]
},
"zone": {
"type": "string",
"title": "Zone",
"description": "Bidding zone passed to the dvhub.online price API.",
"default": "DE-LU",
"examples": [
"DE-LU"
]
}
},
"type": "object",
"title": "FeedInTariffDvhubOnlineCommonSettings",
"description": "Common settings for the dvhub.online feed-in tariff provider."
},
"FeedInTariffEnergyChartsCommonSettings": {
"properties": {
"bidding_zone": {

View File

@@ -5,6 +5,9 @@ from pydantic import Field, computed_field, field_validator
from akkudoktoreos.config.configabc import SettingsBaseModel
from akkudoktoreos.core.coreabc import get_prediction
from akkudoktoreos.prediction.feedintariffabc import FeedInTariffProvider
from akkudoktoreos.prediction.feedintariffdvhubonline import (
FeedInTariffDvhubOnlineCommonSettings,
)
from akkudoktoreos.prediction.feedintariffenergycharts import (
FeedInTariffEnergyChartsCommonSettings,
)
@@ -20,6 +23,7 @@ def feedintariff_provider_ids() -> list[str]:
# Prediction may not be initialized. Return static built-in provider ids.
return [
"FeedInTariffAkkudoktor",
"FeedInTariffDvhubOnline",
"FeedInTariffEnergyCharts",
"FeedInTariffFixed",
"FeedInTariffImport",
@@ -54,6 +58,11 @@ class FeedInTariffCommonSettings(SettingsBaseModel):
json_schema_extra={"description": "Feed in tarif import provider settings."},
)
dvhubonline: FeedInTariffDvhubOnlineCommonSettings = Field(
default_factory=FeedInTariffDvhubOnlineCommonSettings,
json_schema_extra={"description": "DvhubOnline feed in tariff provider settings."},
)
energycharts: FeedInTariffEnergyChartsCommonSettings = Field(
default_factory=FeedInTariffEnergyChartsCommonSettings,
json_schema_extra={"description": "EnergyCharts feed in tariff provider settings."},

View File

@@ -0,0 +1,147 @@
"""Provides feed-in tariff data from the dvhub.online price API."""
import time
from datetime import datetime
from typing import Any, Optional
import pandas as pd
import requests
from loguru import logger
from pydantic import Field
from akkudoktoreos.config.configabc import SettingsBaseModel
from akkudoktoreos.core.cache import cache_in_file
from akkudoktoreos.prediction.feedintariffabc import FeedInTariffProvider
from akkudoktoreos.utils.datetimeutil import to_datetime, to_duration
class FeedInTariffDvhubOnlineCommonSettings(SettingsBaseModel):
"""Common settings for the dvhub.online feed-in tariff provider."""
base_url: str = Field(
default="https://dvhub.online",
json_schema_extra={
"description": "Base URL of the dvhub.online price API.",
"examples": ["https://dvhub.online"],
},
)
zone: str = Field(
default="DE-LU",
json_schema_extra={
"description": "Bidding zone passed to the dvhub.online price API.",
"examples": ["DE-LU"],
},
)
class FeedInTariffDvhubOnline(FeedInTariffProvider):
"""Fetch dvhub.online day-ahead market prices as feed-in tariff data.
dvhub.online serves EPEX day-ahead prices (15-minute slots, EUR/MWh) via
``GET /api/prices?start=YYYY-MM-DD&end=YYYY-MM-DD&zone=DE-LU``. The raw
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``).
"""
highest_orig_datetime: Optional[datetime] = None
def historic_hours_min(self) -> int:
"""Day-ahead source without seasonal extrapolation — keep two days."""
return 48
@classmethod
def provider_id(cls) -> str:
"""Return the unique identifier for the dvhub.online feed-in tariff provider."""
return "FeedInTariffDvhubOnline"
def _provider_settings(self) -> FeedInTariffDvhubOnlineCommonSettings:
settings = self.config.feedintariff.dvhubonline
if settings is None:
return FeedInTariffDvhubOnlineCommonSettings()
return settings
@cache_in_file(with_ttl="1 hour")
def _request_forecast(self, start_date: str, end_date: str) -> dict[str, Any]:
"""Fetch market prices from the dvhub.online price API."""
settings = self._provider_settings()
url = (
f"{settings.base_url}/api/prices?start={start_date}&end={end_date}&zone={settings.zone}"
)
# Retry transient network problems with a short backoff (same pattern
# as FeedInTariffEnergyCharts): (connect, read) timeout tuple.
max_attempts = 3
last_exc: Optional[Exception] = None
for attempt in range(1, max_attempts + 1):
try:
response = requests.get(
url, headers={"accept": "application/json"}, timeout=(5, 60)
)
logger.debug(f"Response from {url}: {response}")
response.raise_for_status()
data = response.json()
if not isinstance(data, dict) or not isinstance(data.get("data"), list):
raise ValueError(f"Unexpected dvhub.online price API response shape from {url}")
self.update_datetime = to_datetime(in_timezone=self.config.general.timezone)
return data
except (
requests.exceptions.Timeout,
requests.exceptions.ConnectionError,
) as exc:
last_exc = exc
logger.warning(
"dvhub.online price request attempt {}/{} failed: {}",
attempt,
max_attempts,
exc,
)
if attempt < max_attempts:
time.sleep(2 * attempt)
raise last_exc # type: ignore[misc]
def _parse_data(self, dvhub_data: dict[str, Any]) -> pd.Series:
"""dvhub.online entries {ts, price[EUR/MWh]} -> Series of EUR/Wh."""
series_data = pd.Series(dtype=float)
for entry in dvhub_data.get("data", []):
try:
orig_datetime = to_datetime(entry["ts"], in_timezone=self.config.general.timezone)
price_eur_per_mwh = float(entry["price"])
except (KeyError, TypeError, ValueError) as exc:
logger.warning("Skipping malformed dvhub.online price entry {}: {}", entry, exc)
continue
series_data.at[orig_datetime] = price_eur_per_mwh / 1_000_000
return series_data
async def _update_data(self, force_update: Optional[bool] = False) -> None:
"""Update feed-in tariff forecast data from dvhub.online."""
if not self.ems_start_datetime:
raise ValueError(f"Start DateTime not set: {self.ems_start_datetime}")
start_date = to_datetime(
self.ems_start_datetime - to_duration("2 days"), as_string="YYYY-MM-DD"
)
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,
)

View File

@@ -37,6 +37,7 @@ from akkudoktoreos.prediction.elecpricefixed import ElecPriceFixed
from akkudoktoreos.prediction.elecpriceimport import ElecPriceImport
from akkudoktoreos.prediction.elecpricetibber import ElecPriceTibber
from akkudoktoreos.prediction.feedintariffakkudoktor import FeedInTariffAkkudoktor
from akkudoktoreos.prediction.feedintariffdvhubonline import FeedInTariffDvhubOnline
from akkudoktoreos.prediction.feedintariffenergycharts import FeedInTariffEnergyCharts
from akkudoktoreos.prediction.feedintarifffixed import FeedInTariffFixed
from akkudoktoreos.prediction.feedintariffimport import FeedInTariffImport
@@ -85,6 +86,7 @@ elecprice_fixed = ElecPriceFixed()
elecprice_import = ElecPriceImport()
elecprice_tibber = ElecPriceTibber()
feedintariff_akkudoktor = FeedInTariffAkkudoktor()
feedintariff_dvhubonline = FeedInTariffDvhubOnline()
feedintariff_energy_charts = FeedInTariffEnergyCharts()
feedintariff_fixed = FeedInTariffFixed()
feedintariff_import = FeedInTariffImport()
@@ -113,6 +115,7 @@ def prediction_providers() -> list[
ElecPriceImport,
ElecPriceTibber,
FeedInTariffAkkudoktor,
FeedInTariffDvhubOnline,
FeedInTariffEnergyCharts,
FeedInTariffFixed,
FeedInTariffImport,
@@ -144,6 +147,7 @@ def prediction_providers() -> list[
elecprice_import, \
elecprice_tibber, \
feedintariff_akkudoktor, \
feedintariff_dvhubonline, \
feedintariff_energy_charts, \
feedintariff_fixed, \
feedintariff_import, \
@@ -171,6 +175,7 @@ def prediction_providers() -> list[
elecprice_import,
elecprice_tibber,
feedintariff_akkudoktor,
feedintariff_dvhubonline,
feedintariff_energy_charts,
feedintariff_fixed,
feedintariff_import,
@@ -203,6 +208,7 @@ class Prediction(PredictionContainer):
ElecPriceImport,
ElecPriceTibber,
FeedInTariffAkkudoktor,
FeedInTariffDvhubOnline,
FeedInTariffEnergyCharts,
FeedInTariffFixed,
FeedInTariffImport,

View File

@@ -0,0 +1,71 @@
"""Tests for the dvhub.online feed-in tariff provider."""
import os
from unittest.mock import MagicMock, patch
import pytest
from akkudoktoreos.prediction.feedintariffdvhubonline import (
FeedInTariffDvhubOnline,
FeedInTariffDvhubOnlineCommonSettings,
)
SAMPLE = {
"data": [
{"ts": "2026-07-19T12:00:00.000Z", "price": 42.5}, # EUR/MWh
{"ts": "2026-07-19T12:15:00.000Z", "price": -5.69}, # negative slot
{"ts": "bogus", "price": 10.0}, # malformed -> skipped
{"ts": "2026-07-19T12:30:00.000Z", "price": "x"}, # malformed -> skipped
]
}
@pytest.fixture
def provider(config_eos):
config_eos.merge_settings_from_dict(
{"feedintariff": {"provider": "FeedInTariffDvhubOnline"}}
)
return FeedInTariffDvhubOnline()
class TestFeedInTariffDvhubOnline:
def test_provider_id_registered(self, provider, config_eos):
assert provider.provider_id() == "FeedInTariffDvhubOnline"
assert provider.enabled()
assert "FeedInTariffDvhubOnline" in config_eos.feedintariff.providers
def test_parse_data_eur_mwh_to_eur_wh(self, provider):
series = provider._parse_data(SAMPLE)
assert len(series) == 2 # malformed entries skipped
assert series.iloc[0] == pytest.approx(42.5 / 1_000_000)
assert series.iloc[1] == pytest.approx(-5.69 / 1_000_000) # negatives kept
def test_default_settings(self, provider):
settings = provider._provider_settings()
assert settings.base_url == "https://dvhub.online"
assert settings.zone == "DE-LU"
def test_request_shape_guard(self, provider):
response = MagicMock()
response.raise_for_status.return_value = None
response.json.return_value = {"unexpected": True}
with patch(
"akkudoktoreos.prediction.feedintariffdvhubonline.requests.get",
return_value=response,
):
with pytest.raises(ValueError, match="response shape"):
provider._request_forecast(
start_date="2026-07-19", end_date="2026-07-21", force_update=True
)
@pytest.mark.skipif(
os.environ.get("EOS_DVHUB_ONLINE_LIVE") != "1",
reason="live API smoke — set EOS_DVHUB_ONLINE_LIVE=1 to run",
)
def test_live_api_smoke(provider):
data = provider._request_forecast(
start_date="2026-07-19", end_date="2026-07-20", force_update=True
)
series = provider._parse_data(data)
assert not series.empty

View File

@@ -8,6 +8,7 @@ from akkudoktoreos.prediction.elecpricefixed import ElecPriceFixed
from akkudoktoreos.prediction.elecpriceimport import ElecPriceImport
from akkudoktoreos.prediction.elecpricetibber import ElecPriceTibber
from akkudoktoreos.prediction.feedintariffakkudoktor import FeedInTariffAkkudoktor
from akkudoktoreos.prediction.feedintariffdvhubonline import FeedInTariffDvhubOnline
from akkudoktoreos.prediction.feedintariffenergycharts import FeedInTariffEnergyCharts
from akkudoktoreos.prediction.feedintarifffixed import FeedInTariffFixed
from akkudoktoreos.prediction.feedintariffimport import FeedInTariffImport
@@ -50,6 +51,7 @@ def forecast_providers():
ElecPriceImport(),
ElecPriceTibber(),
FeedInTariffAkkudoktor(),
FeedInTariffDvhubOnline(),
FeedInTariffEnergyCharts(),
FeedInTariffFixed(),
FeedInTariffImport(),
@@ -106,24 +108,25 @@ def test_provider_sequence(prediction):
assert isinstance(prediction.providers[3], ElecPriceImport)
assert isinstance(prediction.providers[4], ElecPriceTibber)
assert isinstance(prediction.providers[5], FeedInTariffAkkudoktor)
assert isinstance(prediction.providers[6], FeedInTariffEnergyCharts)
assert isinstance(prediction.providers[7], FeedInTariffFixed)
assert isinstance(prediction.providers[8], FeedInTariffImport)
assert isinstance(prediction.providers[9], FeedInTariffTibber)
assert isinstance(prediction.providers[10], LoadAkkudoktor)
assert isinstance(prediction.providers[11], LoadAkkudoktorAdjusted)
assert isinstance(prediction.providers[12], LoadVrm)
assert isinstance(prediction.providers[13], LoadImport)
assert isinstance(prediction.providers[14], PVForecastAkkudoktor)
assert isinstance(prediction.providers[15], PVForecastVrm)
assert isinstance(prediction.providers[16], PVForecastPVNode)
assert isinstance(prediction.providers[17], PVForecastForecastSolar)
assert isinstance(prediction.providers[18], PVForecastSolcast)
assert isinstance(prediction.providers[19], PVForecastImport)
assert isinstance(prediction.providers[20], WeatherBrightSky)
assert isinstance(prediction.providers[21], WeatherClearOutside)
assert isinstance(prediction.providers[22], WeatherOpenMeteo)
assert isinstance(prediction.providers[23], WeatherImport)
assert isinstance(prediction.providers[6], FeedInTariffDvhubOnline)
assert isinstance(prediction.providers[7], FeedInTariffEnergyCharts)
assert isinstance(prediction.providers[8], FeedInTariffFixed)
assert isinstance(prediction.providers[9], FeedInTariffImport)
assert isinstance(prediction.providers[10], FeedInTariffTibber)
assert isinstance(prediction.providers[11], LoadAkkudoktor)
assert isinstance(prediction.providers[12], LoadAkkudoktorAdjusted)
assert isinstance(prediction.providers[13], LoadVrm)
assert isinstance(prediction.providers[14], LoadImport)
assert isinstance(prediction.providers[15], PVForecastAkkudoktor)
assert isinstance(prediction.providers[16], PVForecastVrm)
assert isinstance(prediction.providers[17], PVForecastPVNode)
assert isinstance(prediction.providers[18], PVForecastForecastSolar)
assert isinstance(prediction.providers[19], PVForecastSolcast)
assert isinstance(prediction.providers[20], PVForecastImport)
assert isinstance(prediction.providers[21], WeatherBrightSky)
assert isinstance(prediction.providers[22], WeatherClearOutside)
assert isinstance(prediction.providers[23], WeatherOpenMeteo)
assert isinstance(prediction.providers[24], WeatherImport)
def test_provider_by_id(prediction, forecast_providers):

View File

@@ -130,6 +130,10 @@
"import_file_path": null,
"import_json": null
},
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
},
"energycharts": {
"bidding_zone": "DE-LU"
}

View File

@@ -7,6 +7,7 @@
| Name | Environment Variable | Type | Read-Only | Default | Description |
| ---- | -------------------- | ---- | --------- | ------- | ----------- |
| dvhubonline | `EOS_FEEDINTARIFF__DVHUBONLINE` | `FeedInTariffDvhubOnlineCommonSettings` | `rw` | `required` | DvhubOnline feed in tariff provider settings. |
| energycharts | `EOS_FEEDINTARIFF__ENERGYCHARTS` | `FeedInTariffEnergyChartsCommonSettings` | `rw` | `required` | EnergyCharts feed in tariff provider settings. |
| feedintarifffixed | `EOS_FEEDINTARIFF__FEEDINTARIFFFIXED` | `FeedInTariffFixedCommonSettings` | `rw` | `required` | Fixed feed in tariff provider settings. |
| feedintariffimport | `EOS_FEEDINTARIFF__FEEDINTARIFFIMPORT` | `FeedInTariffImportCommonSettings` | `rw` | `required` | Feed in tarif import provider settings. |
@@ -31,6 +32,10 @@
"import_file_path": null,
"import_json": null
},
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
},
"energycharts": {
"bidding_zone": "DE-LU"
}
@@ -55,11 +60,16 @@
"import_file_path": null,
"import_json": null
},
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
},
"energycharts": {
"bidding_zone": "DE-LU"
},
"providers": [
"FeedInTariffAkkudoktor",
"FeedInTariffDvhubOnline",
"FeedInTariffEnergyCharts",
"FeedInTariffFixed",
"FeedInTariffImport",
@@ -158,3 +168,34 @@
}
```
<!-- pyml enable line-length -->
### Common settings for the dvhub.online feed-in tariff provider
<!-- pyml disable line-length -->
:::{table} feedintariff::dvhubonline
:widths: 10 10 5 5 30
:align: left
| Name | Type | Read-Only | Default | Description |
| ---- | ---- | --------- | ------- | ----------- |
| base_url | `str` | `rw` | `https://dvhub.online` | Base URL of the dvhub.online price API. |
| zone | `str` | `rw` | `DE-LU` | Bidding zone passed to the dvhub.online price API. |
:::
<!-- pyml enable line-length -->
<!-- pyml disable no-emphasis-as-heading -->
**Example Input/Output**
<!-- pyml enable no-emphasis-as-heading -->
<!-- pyml disable line-length -->
```json
{
"feedintariff": {
"dvhubonline": {
"base_url": "https://dvhub.online",
"zone": "DE-LU"
}
}
}
```
<!-- pyml enable line-length -->