From 85886078afa7e438824bba4e0b66797c3b55542c Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 30 Jun 2025 14:17:25 +0200 Subject: [PATCH] scheduled charging: consider soc request interval for 1p3p decision --- packages/control/ev/charge_template.py | 14 ++++++++++---- packages/control/ev/charge_template_test.py | 6 +++--- packages/control/ev/ev.py | 16 ++++++++-------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/control/ev/charge_template.py b/packages/control/ev/charge_template.py index 386384e0bc..6e73c827c1 100644 --- a/packages/control/ev/charge_template.py +++ b/packages/control/ev/charge_template.py @@ -317,7 +317,8 @@ def scheduled_charging_recent_plan(self, phase_switch_supported: bool, charging_type: str, chargemode_switch_timestamp: float, - control_parameter: ControlParameter) -> Optional[SelectedPlan]: + control_parameter: ControlParameter, + soc_request_interval_offset: int) -> Optional[SelectedPlan]: plans_diff_end_date = [] for p in self.data.chargemode.scheduled_charging.plans.values(): if p.active: @@ -350,7 +351,7 @@ def scheduled_charging_recent_plan(self, remaining_time, missing_amount, phases, duration = self._calc_remaining_time( plan, plan_end_time, soc, ev_template, used_amount, max_hw_phases, phase_switch_supported, - charging_type, control_parameter.phases) + charging_type, control_parameter.phases, soc_request_interval_offset) return SelectedPlan(remaining_time=remaining_time, duration=duration, @@ -369,7 +370,8 @@ def _calc_remaining_time(self, max_hw_phases: int, phase_switch_supported: bool, charging_type: str, - control_parameter_phases) -> SelectedPlan: + control_parameter_phases: int, + soc_request_interval_offset: int) -> SelectedPlan: if plan.phases_to_use == 0: if max_hw_phases == 1: duration, missing_amount = self._calculate_duration( @@ -389,7 +391,9 @@ def _calc_remaining_time(self, duration_1p, missing_amount = self._calculate_duration( plan, soc, ev_template.data.battery_capacity, used_amount, 1, charging_type, ev_template) remaining_time_1p = plan_end_time - duration_1p - if remaining_time_1p < 0: + # Kurz vor dem nächsten Abfragen des SoC, wenn noch der alte SoC da ist, kann es sein, dass die Zeit + # für 1p nicht mehr reicht, weil die Regelung den neuen SoC noch nicht kennt. + if remaining_time_1p - (soc_request_interval_offset if plan.limit.selected == "soc" else 0) < 0: # Zeit reicht nicht mehr für einphasiges Laden remaining_time = remaining_time_3p duration = duration_3p @@ -477,6 +481,8 @@ def scheduled_charging_calc_current(self, else: plan_current = plan.dc_current max_current = ev_template.data.dc_max_current + if plan.limit.selected != "soc": + soc_request_interval_offset = 0 log.debug("Verwendeter Plan: "+str(plan.name)) if limit.selected == "soc" and soc >= limit.soc_limit and soc >= limit.soc_scheduled: message = self.SCHEDULED_CHARGING_REACHED_LIMIT_SOC diff --git a/packages/control/ev/charge_template_test.py b/packages/control/ev/charge_template_test.py index c54b343486..8c09973a89 100644 --- a/packages/control/ev/charge_template_test.py +++ b/packages/control/ev/charge_template_test.py @@ -153,7 +153,7 @@ def test_calc_remaining_time(phases_to_use, # execution remaining_time, missing_amount, phases, duration = ct._calc_remaining_time( - plan, 6000, 50, evt, 3000, max_hw_phases, phase_switch_supported, ChargingType.AC.value, 2) + plan, 6000, 50, evt, 3000, max_hw_phases, phase_switch_supported, ChargingType.AC.value, 2, 0) # end time 16.5.22 10:00 # evaluation @@ -203,7 +203,7 @@ def test_scheduled_charging_recent_plan(end_time_mock, # execution selected_plan = ct.scheduled_charging_recent_plan( - 60, EvTemplate(), 3, 200, 3, True, ChargingType.AC.value, 1652688000, Mock(spec=ControlParameter)) + 60, EvTemplate(), 3, 200, 3, True, ChargingType.AC.value, 1652688000, Mock(spec=ControlParameter), 0) # evaluation if selected_plan: @@ -234,7 +234,7 @@ def test_scheduled_charging_recent_plan_fulfilled(end_time_mock, expected_plan_n # execution selected_plan = ct.scheduled_charging_recent_plan( - 60, EvTemplate(), 3, 1200, 3, True, ChargingType.AC.value, 1652688000, Mock(spec=ControlParameter)) + 60, EvTemplate(), 3, 1200, 3, True, ChargingType.AC.value, 1652688000, Mock(spec=ControlParameter), 0) # evaluation if selected_plan: diff --git a/packages/control/ev/ev.py b/packages/control/ev/ev.py index 6b69689b1e..48cd47a41e 100644 --- a/packages/control/ev/ev.py +++ b/packages/control/ev/ev.py @@ -148,6 +148,12 @@ def get_required_current(self, required_current, submode, message = charge_template.stop() phases = control_parameter.phases or max_phases_hw else: + # Wenn der SoC ein paar Minuten alt ist, kann der Termin trotzdem gehalten werden. + # Zielladen kann nicht genauer arbeiten, als das Abfrageintervall vom SoC. + if self.soc_module: + soc_request_interval_offset = self.soc_module.general_config.request_interval_charging + else: + soc_request_interval_offset = 0 if charge_template.data.chargemode.selected == "scheduled_charging": plan_data = charge_template.scheduled_charging_recent_plan( self.data.get.soc, @@ -158,15 +164,9 @@ def get_required_current(self, phase_switch_supported, charging_type, chargemode_switch_timestamp, - control_parameter) - soc_request_interval_offset = 0 + control_parameter, + soc_request_interval_offset) if plan_data: - # Wenn der SoC ein paar Minuten alt ist, kann der Termin trotzdem gehalten werden. - # Zielladen kann nicht genauer arbeiten, als das Abfrageintervall vom SoC. - if (self.soc_module and - charge_template.data.chargemode. - scheduled_charging.plans[str(plan_data.plan.id)].limit.selected == "soc"): - soc_request_interval_offset = self.soc_module.general_config.request_interval_charging control_parameter.current_plan = plan_data.plan.id else: control_parameter.current_plan = None