From d15c639ee87c3a438c851e200b21537154c6bfbb Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 12 Mar 2025 12:25:16 +0100 Subject: [PATCH 1/2] scheduled charging: show charging times in info box --- packages/control/ev/charge_template.py | 25 +++++++++++++++------ packages/control/ev/charge_template_test.py | 11 +++++---- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/control/ev/charge_template.py b/packages/control/ev/charge_template.py index ed0493350c..a9178f5462 100644 --- a/packages/control/ev/charge_template.py +++ b/packages/control/ev/charge_template.py @@ -1,4 +1,5 @@ from dataclasses import asdict, dataclass, field +import datetime import logging import traceback from typing import Dict, Optional, Tuple @@ -381,7 +382,7 @@ def _calculate_duration(self, "für Zielladen bereits erreicht wurde.") SCHEDULED_CHARGING_NO_PLANS_CONFIGURED = "Keine Ladung, da keine Ziel-Termine konfiguriert sind." SCHEDULED_CHARGING_NO_DATE_PENDING = "Kein Zielladen, da kein Ziel-Termin ansteht." - SCHEDULED_CHARGING_USE_PV = ("Kein Zielladen, da noch Zeit bis zum Zieltermin ist. Falls vorhanden, " + SCHEDULED_CHARGING_USE_PV = ("Laden startet {}. Falls vorhanden, " "wird mit Überschuss geladen.") SCHEDULED_CHARGING_MAX_CURRENT = ("Zielladen mit {}A. Der Ladestrom wurde erhöht, um den Zieltermin zu erreichen. " "Es wird bis max. 20 Minuten nach dem angegebenen Zieltermin geladen.") @@ -389,9 +390,9 @@ def _calculate_duration(self, SCHEDULED_CHARGING_LIMITED_BY_AMOUNT = '{}kWh geladene Energie' SCHEDULED_CHARGING_IN_TIME = ('Zielladen mit mindestens {}A, um {} um {} zu erreichen. Falls vorhanden wird ' 'zusätzlich EVU-Überschuss geladen.') - SCHEDULED_CHARGING_CHEAP_HOUR = "Zielladen, da ein günstiger Zeitpunkt zum preisbasierten Laden ist." + SCHEDULED_CHARGING_CHEAP_HOUR = "Zielladen, da ein günstiger Zeitpunkt zum preisbasierten Laden ist. {}" SCHEDULED_CHARGING_EXPENSIVE_HOUR = ("Zielladen ausstehend, da jetzt kein günstiger Zeitpunkt zum preisbasierten " - "Laden ist. Falls vorhanden, wird mit Überschuss geladen.") + "Laden ist. {} Falls vorhanden, wird mit Überschuss geladen.") def scheduled_charging_calc_current(self, plan_data: Optional[SelectedPlan], @@ -447,14 +448,17 @@ def scheduled_charging_calc_current(self, # ist. if self.data.et.active and data.data.optional_data.et_provider_available(): hour_list = data.data.optional_data.et_get_loading_hours(plan_data.duration, plan_data.remaining_time) - log.debug(f"Günstige Ladezeiten: {hour_list}") + hours_message = ("Geladen wird zu folgenden Uhrzeiten: " + + ", ".join([datetime.datetime.fromtimestamp(hour).strftime('%-H:%M') + for hour in sorted(hour_list)]) + + ".") if timecheck.is_list_valid(hour_list): - message = self.SCHEDULED_CHARGING_CHEAP_HOUR + message = self.SCHEDULED_CHARGING_CHEAP_HOUR.format(hours_message) current = plan_data.available_current submode = "instant_charging" elif ((limit.selected == "soc" and soc <= limit.soc_limit) or (limit.selected == "amount" and used_amount < limit.amount)): - message = self.SCHEDULED_CHARGING_EXPENSIVE_HOUR + message = self.SCHEDULED_CHARGING_EXPENSIVE_HOUR.format(hours_message) current = min_current submode = "pv_charging" phases = control_parameter_phases @@ -465,7 +469,14 @@ def scheduled_charging_calc_current(self, if limit.selected == "soc" and soc >= limit.soc_limit: message = self.SCHEDULED_REACHED_LIMIT_SOC else: - message = self.SCHEDULED_CHARGING_USE_PV + now = datetime.datetime.today() + start_time = now + datetime.timedelta(seconds=plan_data.remaining_time) + if start_time.year == now.year and start_time.month == now.month and start_time.day == now.day: + message = self.SCHEDULED_CHARGING_USE_PV.format( + f"um {start_time.strftime('%-H:%M')} Uhr") + else: + message = self.SCHEDULED_CHARGING_USE_PV.format( + f"am {start_time.strftime('%d.%m')} um {start_time.strftime('%-H:%M')} Uhr") current = min_current submode = "pv_charging" phases = control_parameter_phases diff --git a/packages/control/ev/charge_template_test.py b/packages/control/ev/charge_template_test.py index a036ffed0a..665bdb06d4 100644 --- a/packages/control/ev/charge_template_test.py +++ b/packages/control/ev/charge_template_test.py @@ -244,7 +244,8 @@ def test_search_plan(check_duration_return1: Tuple[Optional[float], bool], ChargeTemplate.SCHEDULED_CHARGING_MAX_CURRENT.format(16), 3), id="few minutes too late, but didn't miss for today"), pytest.param(SelectedPlan(remaining_time=301, duration=3600), 79, 0, "soc", - (6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_USE_PV, 3), id="too early, use pv"), + (6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_USE_PV.format("um 8:45 Uhr"), 3), + id="too early, use pv"), ]) def test_scheduled_charging_calc_current(plan_data: SelectedPlan, soc: int, @@ -279,8 +280,10 @@ def test_scheduled_charging_calc_current_no_plans(): @pytest.mark.parametrize( "loading_hour, expected", [ - pytest.param(True, (14, "instant_charging", ChargeTemplate.SCHEDULED_CHARGING_CHEAP_HOUR, 3)), - pytest.param(False, (6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_EXPENSIVE_HOUR, 3)), + pytest.param(True, (14, "instant_charging", ChargeTemplate.SCHEDULED_CHARGING_CHEAP_HOUR.format( + "Geladen wird zu folgenden Uhrzeiten: 8:00."), 3)), + pytest.param(False, (6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_EXPENSIVE_HOUR.format( + "Geladen wird zu folgenden Uhrzeiten: 8:00."), 3)), ]) def test_scheduled_charging_calc_current_electricity_tariff(loading_hour, expected, monkeypatch): # setup @@ -289,7 +292,7 @@ def test_scheduled_charging_calc_current_electricity_tariff(loading_hour, expect plan.limit.selected = "soc" ct.data.chargemode.scheduled_charging.plans = {"0": plan} ct.data.et.active = True - mock_et_get_loading_hours = Mock(return_value=[]) + mock_et_get_loading_hours = Mock(return_value=[1652680800]) monkeypatch.setattr(data.data.optional_data, "et_get_loading_hours", mock_et_get_loading_hours) mock_et_provider_available = Mock(return_value=True) monkeypatch.setattr(data.data.optional_data, "et_provider_available", mock_et_provider_available) From f12b5ef95a3277d44e50f6946fa9673ebf22742d Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 12 Mar 2025 16:01:40 +0100 Subject: [PATCH 2/2] pytest --- packages/control/ev/charge_template_test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/control/ev/charge_template_test.py b/packages/control/ev/charge_template_test.py index 665bdb06d4..9b17b7c716 100644 --- a/packages/control/ev/charge_template_test.py +++ b/packages/control/ev/charge_template_test.py @@ -1,3 +1,4 @@ +import datetime from typing import Dict, NamedTuple, Optional, Tuple from unittest.mock import Mock @@ -292,7 +293,9 @@ def test_scheduled_charging_calc_current_electricity_tariff(loading_hour, expect plan.limit.selected = "soc" ct.data.chargemode.scheduled_charging.plans = {"0": plan} ct.data.et.active = True - mock_et_get_loading_hours = Mock(return_value=[1652680800]) + # für Github-Test keinen Zeitstempel verwenden + mock_et_get_loading_hours = Mock(return_value=[datetime.datetime( + year=2022, month=5, day=16, hour=8, minute=0).timestamp()]) monkeypatch.setattr(data.data.optional_data, "et_get_loading_hours", mock_et_get_loading_hours) mock_et_provider_available = Mock(return_value=True) monkeypatch.setattr(data.data.optional_data, "et_provider_available", mock_et_provider_available)