Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion packages/helpermodules/update_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

class UpdateConfig:

DATASTORE_VERSION = 124
DATASTORE_VERSION = 125

valid_topic = [
"^openWB/bat/config/bat_control_activated$",
Expand Down Expand Up @@ -3132,3 +3132,31 @@ def upgrade(topic: str, payload) -> Optional[dict]:
return {topic: configuration_payload}
self._loop_all_received_topics(upgrade)
self._append_datastore_version(124)

def upgrade_datastore_125(self) -> None:
def upgrade(topic: str, payload) -> None:
if "openWB/optional/ep/flexible_tariff/provider" == topic:
provider = decode_payload(payload)
if provider["type"] == "energycharts":
surcharge = provider["configuration"]["surcharge"]
if surcharge > 0.1: # entspricht mehr als 0.1ct/kWh konfiguriertem Zuschlag
provider["configuration"]["surcharge"] = surcharge / 100000
return {topic: provider}
if ("openWB/optional/ep/flexible_tariff/provider" == topic or
"openWB/optional/ep/grid_fee/provider" == topic):
provider = decode_payload(payload)
if provider["type"] == "fixed_hours":
changed = False
for i, tarif in enumerate(provider["configuration"]["tariffs"]):
price = tarif.get("price", 0)
if price > 0.001: # entspricht mehr als 0,1ct/kWh konfiguriertem Tarifpreis
provider["configuration"]["tariffs"][i]["price"] = price / 1000
changed = True
default_price = provider["configuration"].get("default_price", 0)
if default_price > 0.001:
provider["configuration"]["default_price"] = default_price / 1000
changed = True
if changed:
return {topic: provider}
self._loop_all_received_topics(upgrade)
self._append_datastore_version(125)
84 changes: 84 additions & 0 deletions packages/helpermodules/update_config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,3 +149,87 @@ def test_upgrade_datastore_122(name, monkeypatch):
# Assert
assert mock_dump.call_args_list[0].args[0] == expected_content
assert uc.all_received_topics["openWB/system/datastore_version"] == [122]


def test_upgrade_datastore_125_converts_only_tariff_prices_and_persists(mock_pub):
uc = UpdateConfig()
uc.all_received_topics = {
"openWB/optional/ep/flexible_tariff/provider": {
"type": "fixed_hours",
"configuration": {
"tariffs": [
{"price": 0.15},
{"price": 0.09},
],
"default_price": 0.01,
},
},
"openWB/system/datastore_version": [123],
}

uc.upgrade_datastore_125()

provider = uc.all_received_topics["openWB/optional/ep/flexible_tariff/provider"]
assert provider["configuration"]["tariffs"][0]["price"] == pytest.approx(0.00015)
assert provider["configuration"]["tariffs"][1]["price"] == pytest.approx(0.00009)
assert provider["configuration"]["default_price"] == pytest.approx(0.00001)
assert uc.all_received_topics["openWB/system/datastore_version"] == [123, 125]

updated_topics = [call.args[0] for call in mock_pub.pub.call_args_list]
assert "openWB/optional/ep/flexible_tariff/provider" in updated_topics
assert "openWB/system/datastore_version" in updated_topics


def test_upgrade_datastore_125_converts_energycharts_surcharge(mock_pub):
uc = UpdateConfig()
uc.all_received_topics = {
"openWB/optional/ep/flexible_tariff/provider": {
"type": "energycharts",
"configuration": {
"surcharge": 10,
},
},
"openWB/system/datastore_version": [123],
}

uc.upgrade_datastore_125()

provider = uc.all_received_topics["openWB/optional/ep/flexible_tariff/provider"]
assert provider["configuration"]["surcharge"] == pytest.approx(0.0001)
assert uc.all_received_topics["openWB/system/datastore_version"] == [123, 125]

updated_topics = [call.args[0] for call in mock_pub.pub.call_args_list]
assert "openWB/optional/ep/flexible_tariff/provider" in updated_topics


def test_upgrade_datastore_125_is_idempotent_for_already_converted_values(mock_pub):
uc = UpdateConfig()
uc.all_received_topics = {
"openWB/optional/ep/flexible_tariff/provider": {
"type": "energycharts",
"configuration": {
"surcharge": 0.00015,
},
},
"openWB/optional/ep/grid_fee/provider": {
"type": "fixed_hours",
"configuration": {
"tariffs": [
{"price": 0.00006},
{"price": 0.00099},
],
"default_price": 0.00008,
},
},
"openWB/system/datastore_version": [123, 124],
}

expected_flexible = json.loads(json.dumps(uc.all_received_topics["openWB/optional/ep/flexible_tariff/provider"]))
expected_grid_fee = json.loads(json.dumps(uc.all_received_topics["openWB/optional/ep/grid_fee/provider"]))

uc.upgrade_datastore_125()

assert uc.all_received_topics["openWB/optional/ep/flexible_tariff/provider"] == expected_flexible
assert uc.all_received_topics["openWB/optional/ep/grid_fee/provider"] == expected_grid_fee
assert uc.all_received_topics["openWB/system/datastore_version"] == [123, 124, 125]
assert mock_pub.pub.call_count == 1 # einmal publishen für Upgrade der Datastore-Version
12 changes: 6 additions & 6 deletions packages/modules/common/store/_tariff.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,11 @@ def __reduce_prices(prices: Dict[str, float]) -> Dict[int, float]:

def __get_default_grid_fee_price(prices: Dict[str, float]) -> float:
if (data.data.optional_data.grid_fee_module is not None and
hasattr(data.data.optional_data.grid_fee_module.config, "default_price") and
data.data.optional_data.grid_fee_module.config.default_price is not None):
hasattr(data.data.optional_data.grid_fee_module.config.configuration, "default_price") and
data.data.optional_data.grid_fee_module.config.configuration.default_price is not None):
log.debug("Using default grid fee price from configuration: " +
f"{data.data.optional_data.grid_fee_module.config.default_price}")
return data.data.optional_data.grid_fee_module.config.default_price
f"{data.data.optional_data.grid_fee_module.config.configuration.default_price}")
return data.data.optional_data.grid_fee_module.config.configuration.default_price
else:
# Fallback: Median der vorhandenen Netzentgelte wird
# als Schätzung für das Standard-Netzentgelt verwenden
Expand All @@ -95,8 +95,8 @@ def __normalize_grid_fee_prices(grid_fee_prices: Dict[int, float], max_timestamp
grid_fee_prices = {int(float(k)): v for k, v in grid_fee_prices.items() if int(float(k)) <= max_timestamp}

if (data.data.optional_data.flexible_tariff_module is not None and
hasattr(data.data.optional_data.flexible_tariff_module.config, "includes_grid_fee") and
data.data.optional_data.flexible_tariff_module.config.includes_grid_fee is False):
hasattr(data.data.optional_data.flexible_tariff_module.config.configuration, "includes_grid_fee") and
data.data.optional_data.flexible_tariff_module.config.configuration.includes_grid_fee is False):
return grid_fee_prices
else:
# Bei flexiblen Tarifen, die das Netzentgelt _nicht_ enthalten,
Expand Down
19 changes: 12 additions & 7 deletions packages/modules/common/store/_tariff_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from datetime import timedelta
import datetime
from types import SimpleNamespace
from typing import Dict
from unittest.mock import Mock

Expand Down Expand Up @@ -30,12 +31,16 @@ def mock_data() -> None:
data.data_init(Mock())
data.data.optional_data = Optional()
data.data.optional_data.grid_fee_module = Mock()
data.data.optional_data.grid_fee_module.config = Mock()
data.data.optional_data.grid_fee_module.config.default_price = None
data.data.optional_data.grid_fee_module.config = SimpleNamespace(
configuration=SimpleNamespace(default_price=None)
)
data.data.optional_data.flexible_tariff_module = Mock()
data.data.optional_data.flexible_tariff_module.config = Mock()
data.data.optional_data.flexible_tariff_module.config.default_price = None
data.data.optional_data.flexible_tariff_module.config.includes_grid_fee = True
data.data.optional_data.flexible_tariff_module.config = SimpleNamespace(
configuration=SimpleNamespace(
default_price=None,
includes_grid_fee=True
)
)


@pytest.mark.parametrize(
Expand Down Expand Up @@ -146,8 +151,8 @@ def test_sum_prices(
flexible_tariff
)
data.data.optional_data.data.electricity_pricing.grid_fee.get.prices = grid_fee
data.data.optional_data.flexible_tariff_module.config.includes_grid_fee = includes_grid_fee
data.data.optional_data.grid_fee_module.config.default_price = default_grid_fee_price
data.data.optional_data.flexible_tariff_module.config.configuration.includes_grid_fee = includes_grid_fee
data.data.optional_data.grid_fee_module.config.configuration.default_price = default_grid_fee_price
summed = value_Store.sum_prices()
assert summed == expected_prices

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ def create_request_url(config: EnergyChartsTariffConfiguration) -> str:
return url


def parse_response(config: EnergyChartsTariffConfiguration, raw_prices: dict) -> Dict[str, float]:
prices: Dict[int, float] = {}
def parse_response(config: EnergyChartsTariffConfiguration, raw_prices: Dict[str, float]) -> Dict[str, float]:
prices: Dict[str, float] = {}
for timestamp, price_per_MWh in zip(raw_prices['unix_seconds'], raw_prices['price']):
prices[str(int(timestamp))] = float(price_per_MWh + (config.surcharge*10))/1000000
prices[str(int(timestamp))] = float(price_per_MWh)/1000000 + config.surcharge
log.debug("converted prices: %s : %s", len(prices), prices)
return prices

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
from modules.common.component_state import TariffState

log = logging.getLogger(__name__)
AS_EURO_PER_WH = 1000


def _to_time(time_str: str) -> datetime.time:
Expand Down Expand Up @@ -69,7 +68,7 @@ def _calculate_price_timeslots(config: FixedHoursTariffConfiguration) -> TariffS
for j in range(4): # get prices for quarter hours
time_slot = current_hour + datetime.timedelta(hours=i, minutes=j * 15)
epoch_time = int(time.mktime(time_slot.timetuple()))
prices[str(epoch_time)] = _fetch_price_for_time_slot(config, time_slot) / AS_EURO_PER_WH
prices[str(epoch_time)] = _fetch_price_for_time_slot(config, time_slot)
Comment on lines 69 to +71
return TariffState(prices=prices)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class TestFetch:
"default_price,tariffs,expected_price",
[
# No tariffs, use default price
pytest.param(1500, [], 1.5, id="no_tariffs"),
pytest.param(1500, [], 1500, id="no_tariffs"),
# All-day tariff
pytest.param(
1500,
Expand All @@ -169,7 +169,7 @@ class TestFetch:
},
}
],
2.0,
2000,
id="all_day_tariff",
),
# Tariff that matches all times
Expand All @@ -185,13 +185,13 @@ class TestFetch:
},
}
],
2.5,
2500,
id="full_day_tariff",
),
# Very low price
pytest.param(500, [], 0.5, id="low_price"),
pytest.param(500, [], 500, id="low_price"),
# Very high price
pytest.param(5000, [], 5.0, id="high_price"),
pytest.param(5000, [], 5000, id="high_price"),
],
)
def test_fetch_price_configurations(self, default_price, tariffs, expected_price):
Expand All @@ -205,7 +205,7 @@ def test_fetch_price_configurations(self, default_price, tariffs, expected_price
assert isinstance(result, TariffState)
assert len(result.prices) > 0
for price in result.prices.values():
assert isinstance(price, float)
assert isinstance(price, (float, int))
assert price == expected_price

@pytest.mark.parametrize(
Expand Down Expand Up @@ -262,7 +262,7 @@ class TestCreateElectricityTariff:
"default_price,tariffs,expected_price",
[
# No tariffs, use default
pytest.param(1500, [], 1.5, id="no_tariffs"),
pytest.param(1500, [], 1500, id="no_tariffs"),
# With all-day tariff
pytest.param(
1500,
Expand All @@ -276,7 +276,7 @@ class TestCreateElectricityTariff:
},
}
],
2.5,
2500,
id="all_day_tariff",
),
# Another tariff configuration
Expand All @@ -292,7 +292,7 @@ class TestCreateElectricityTariff:
},
}
],
3.5,
3500,
id="premium_tariff",
),
pytest.param(
Expand All @@ -307,7 +307,7 @@ class TestCreateElectricityTariff:
},
}
],
2.0,
2000,
id="not_matching_tariff returns default price",
),
],
Expand Down
Loading