From bd80107bfcbbe13360fd4aa2d87e754970ff83cf Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 6 Nov 2023 15:02:42 +0100 Subject: [PATCH] fix calc costs --- packages/control/chargelog/chargelog.py | 90 ++++++++++++++------ packages/control/chargelog/chargelog_test.py | 44 +++++++--- packages/main.py | 3 +- 3 files changed, 98 insertions(+), 39 deletions(-) diff --git a/packages/control/chargelog/chargelog.py b/packages/control/chargelog/chargelog.py index 1bfc05e0c7..f52e88564b 100644 --- a/packages/control/chargelog/chargelog.py +++ b/packages/control/chargelog/chargelog.py @@ -1,4 +1,5 @@ import datetime +from enum import Enum import json import logging import math @@ -96,6 +97,7 @@ def save_data(chargepoint, charging_ev, immediately: bool = True, reset: bool = power = 0 if duration > 0: power = log_data.imported_since_mode_switch / duration + calculate_charge_cost(chargepoint, True) costs = log_data.costs new_entry = { "chargepoint": @@ -318,34 +320,68 @@ def truncate(number: Union[int, float], decimals: int = 0): log.exception("Fehler im Ladelog-Modul") -def calculate_charge_cost(create_log_entry: bool = False): +def calculate_charge_cost(cp, create_log_entry: bool = False): content = get_todays_daily_log() - for cp in data.data.cp_data.values(): - try: - reference_time = _get_reference_time(cp, create_log_entry) - reference_entry = _get_reference_entry(content["entries"], reference_time) - energy_entry = process_entry(reference_entry, content["entries"][-1], CalculationType.ENERGY) - power_source_entry = analyse_percentage(energy_entry) - cp.data.set.log.costs += _calc(power_source_entry["power_source"], - # energy_imported in kWh - power_source_entry["cp"][f"cp{cp.num}"]["energy_imported"]*1000, - (data.data.optional_data.et_module is not None)) - except Exception: - log.exception(f"Fehler beim Berechnen der Ladekosten für Ladepunkt {cp.num}") - - -def _get_reference_time(cp, create_log_entry: bool) -> float: + try: + reference = _get_reference_position(cp, create_log_entry) + reference_time = get_reference_time(cp, reference) + reference_entry = _get_reference_entry(content["entries"], reference_time) + energy_entry = process_entry(reference_entry, content["entries"][-1], CalculationType.ENERGY) + power_source_entry = analyse_percentage(energy_entry) + if reference == ReferenceTime.START: + charged_energy = cp.data.set.log.imported_since_mode_switch + elif reference == ReferenceTime.MIDDLE: + # energy_imported in kWh + charged_energy = (content["entries"][-1]["cp"][f"cp{cp.num}"]["imported"] - + power_source_entry["cp"][f"cp{cp.num}"]["energy_imported"]*1000) + elif reference == ReferenceTime.END: + reference_start_position = _get_reference_position(cp, False) + if reference_start_position == ReferenceTime.START: + charged_energy = cp.data.set.log.imported_since_mode_switch + else: + last_considered_entry = _get_reference_entry( + content["entries"], timecheck.create_unix_timestamp_current_full_hour()) + charged_energy = cp.data.get.imported - \ + last_considered_entry["cp"][f"cp{cp.num}"]["energy_imported"]*1000 + else: + raise TypeError(f"Unbekannter Referenz-Zeitpunkt {reference}") + cp.data.set.log.costs += _calc(power_source_entry["power_source"], + charged_energy, + (data.data.optional_data.et_module is not None)) + except Exception: + log.exception(f"Fehler beim Berechnen der Ladekosten für Ladepunkt {cp.num}") + + +class ReferenceTime(Enum): + START = 0 + MIDDLE = 1 + END = 2 + + +def _get_reference_position(cp, create_log_entry: bool) -> ReferenceTime: # Referenz-Zeitpunkt ermitteln (angesteckt oder letzte volle Stunde) # Wurde innerhalb der letzten Stunde angesteckt? if create_log_entry: # Ladekosten für angefangene Stunde ermitteln - return timecheck.create_unix_timestamp_current_full_hour() + return ReferenceTime.END else: one_hour_back = (datetime.datetime.today()-datetime.timedelta(hours=1)) - if timecheck.get_difference(cp.data.set.plug_time, one_hour_back.strftime("%m/%d/%Y, %H:%M:%S")) < 0: - return datetime.datetime.strptime(cp.data.set.plug_time, "%m/%d/%Y, %H:%M:%S").timestamp() + if (timecheck.get_difference(cp.data.set.log.timestamp_start_charging, + one_hour_back.strftime("%m/%d/%Y, %H:%M:%S")) < 0): + return ReferenceTime.START else: - return one_hour_back.timestamp() + return ReferenceTime.MIDDLE + + +def get_reference_time(cp, reference_position): + if reference_position == ReferenceTime.START: + return datetime.datetime.strptime(cp.data.set.log.timestamp_start_charging, "%m/%d/%Y, %H:%M:%S").timestamp() + elif reference_position == ReferenceTime.MIDDLE: + return (datetime.datetime.today()-datetime.timedelta(hours=1)).timestamp() + elif reference_position == ReferenceTime.END: + return timecheck.create_unix_timestamp_current_full_hour() + else: + raise TypeError(f"Unbekannter Referenz-Zeitpunkt {reference_position}") def _get_reference_entry(entries: List[Dict], reference_time: float) -> Dict: @@ -371,7 +407,7 @@ def get_todays_daily_log(): def get_daily_log(day): - filepath = str(pathlib.Path(__file__).resolve().parents[2] / "data" / "daily_log" / f"{day}.json") + filepath = str(pathlib.Path(__file__).resolve().parents[3] / "data" / "daily_log" / f"{day}.json") try: with open(filepath, "r", encoding="utf-8") as json_file: return json.load(json_file) @@ -379,16 +415,16 @@ def get_daily_log(day): return [] -def _calc(power_source: Dict[str, float], charged_power_last_hour: float, et_active: bool) -> float: +def _calc(power_source: Dict[str, float], charged_energy_last_hour: float, et_active: bool) -> float: prices = data.data.general_data.data.prices - bat_costs = prices.bat * charged_power_last_hour * power_source["bat"] - cp_costs = prices.cp * charged_power_last_hour * power_source["cp"] + bat_costs = prices.bat * charged_energy_last_hour * power_source["bat"] + cp_costs = prices.cp * charged_energy_last_hour * power_source["cp"] if et_active: - grid_costs = data.data.optional_data.et_get_current_price() * charged_power_last_hour * power_source["grid"] + grid_costs = data.data.optional_data.et_get_current_price() * charged_energy_last_hour * power_source["grid"] else: - grid_costs = prices.grid * charged_power_last_hour * power_source["grid"] - pv_costs = prices.pv * charged_power_last_hour * power_source["pv"] + grid_costs = prices.grid * charged_energy_last_hour * power_source["grid"] + pv_costs = prices.pv * charged_energy_last_hour * power_source["pv"] log.debug( f'Ladepreis für die letzte Stunde: {bat_costs}€ Speicher ({power_source["bat"]}%), {grid_costs}€ Netz ' diff --git a/packages/control/chargelog/chargelog_test.py b/packages/control/chargelog/chargelog_test.py index 802e530c06..5cbcef479a 100644 --- a/packages/control/chargelog/chargelog_test.py +++ b/packages/control/chargelog/chargelog_test.py @@ -5,7 +5,8 @@ import pytest from control import data from control.chargelog import chargelog -from control.chargelog.chargelog import _calc, _get_reference_entry, _get_reference_time, calculate_charge_cost +from control.chargelog.chargelog import (ReferenceTime, _calc, _get_reference_entry, _get_reference_position, + calculate_charge_cost, get_reference_time) from control.chargepoint.chargepoint import Chargepoint from control.general import General from control.optional import Optional @@ -60,20 +61,41 @@ def data_module() -> None: @pytest.mark.parametrize( - "plug_time, create_log_entry, expected_timestamp", - (pytest.param("05/16/2022, 07:42:52", False, 1652679772, id="innerhalb der letzten Stunde angesteckt"), - pytest.param("05/16/2022, 06:40:52", False, 1652679652, id="vor mehr als einer Stunde angesteckt"), - pytest.param("05/16/2022, 06:40:52", True, 1652680800, + "start_charging, create_log_entry, expected_timestamp", + (pytest.param("05/16/2022, 07:42:52", False, ReferenceTime.START, id="innerhalb der letzten Stunde angesteckt"), + pytest.param("05/16/2022, 06:40:52", False, ReferenceTime.MIDDLE, id="vor mehr als einer Stunde angesteckt"), + pytest.param("05/16/2022, 06:40:52", True, ReferenceTime.END, id="vor mehr als einer Stunde angesteckt, Ladevorgang beenden"), ) ) -def test_get_reference_time(plug_time: bool, create_log_entry: bool, expected_timestamp: float): +def test_get_reference_position(start_charging: str, create_log_entry: bool, expected_timestamp: float): # setup cp = Chargepoint(0, Mock()) - cp.data.set.plug_time = plug_time + cp.data.set.log.timestamp_start_charging = start_charging # execution - timestamp = _get_reference_time(cp, create_log_entry) + timestamp = _get_reference_position(cp, create_log_entry) + + # evaluation + assert timestamp == expected_timestamp + + +@pytest.mark.parametrize( + "reference_position, start_charging, expected_timestamp", + (pytest.param(ReferenceTime.START, "05/16/2022, 07:42:52", 1652679772, + id="innerhalb der letzten Stunde angesteckt"), + pytest.param(ReferenceTime.MIDDLE, "05/16/2022, 06:40:52", 1652679652, id="vor mehr als einer Stunde angesteckt"), + pytest.param(ReferenceTime.END, "05/16/2022, 06:40:52", 1652680800, + id="vor mehr als einer Stunde angesteckt, Ladevorgang beenden"), + ) +) +def test_get_reference_time(reference_position: ReferenceTime, start_charging: str, expected_timestamp: float): + # setup + cp = Chargepoint(0, Mock()) + cp.data.set.log.timestamp_start_charging = start_charging + + # execution + timestamp = get_reference_time(cp, reference_position) # evaluation assert timestamp == expected_timestamp @@ -121,7 +143,7 @@ def test_calc(et_active, expected_costs, monkeypatch): def test_calculate_charge_cost(monkeypatch): # integration test # setup - data.data.cp_data["cp3"].data.set.plug_time = "11/01/2023, 08:12:40" + data.data.cp_data["cp3"].data.set.log.timestamp_start_charging = "11/01/2023, 08:12:40" # Mock today() to values in log-file datetime_mock = MagicMock(wraps=datetime.datetime) # Thu Nov 02 2023 07:00:51 @@ -135,7 +157,7 @@ def test_calculate_charge_cost(monkeypatch): monkeypatch.setattr(chargelog, "get_todays_daily_log", Mock(return_value=content_today)) # execution - calculate_charge_cost() + calculate_charge_cost(data.data.cp_data["cp3"]) # evaluation - assert data.data.cp_data["cp3"].data.set.log.costs == 0.5441 + assert data.data.cp_data["cp3"].data.set.log.costs == 6.7509 diff --git a/packages/main.py b/packages/main.py index 0df25e2907..c7a052311f 100755 --- a/packages/main.py +++ b/packages/main.py @@ -153,7 +153,8 @@ def handler_random_nightly(self): @exit_after(10) def handler_hour(self): try: - calculate_charge_cost() + for cp in data.data.cp_data.values(): + calculate_charge_cost(cp) except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: