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
3 changes: 2 additions & 1 deletion packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -667,7 +667,8 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
self.hw_supports_phase_switch(),
self.template.data.charging_type,
self.data.set.log.imported_since_plugged,
self.hw_bidi_capable())
self.hw_bidi_capable(),
self.data.get.charge_state)
required_phases = self.get_phases_by_selected_chargemode(template_phases)
required_phases = self.set_phases(required_phases, template_phases)
self._pub_connected_vehicle(charging_ev)
Expand Down
14 changes: 10 additions & 4 deletions packages/control/ev/charge_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,8 @@ def scheduled_charging(self,
charging_type: str,
control_parameter: ControlParameter,
soc_request_interval_offset: int,
bidi_state: BidiState) -> Optional[SelectedPlan]:
bidi_state: BidiState,
charge_state: bool) -> Optional[SelectedPlan]:
if bidi_state == BidiState.BIDI_CAPABLE and soc is None:
raise Exception("Für den Lademodis Bidi ist zwingend ein SoC-Modul erforderlich. Soll der "
"SoC ausschließlich aus dem Fahrzeug ausgelesen werden, bitte auf "
Expand Down Expand Up @@ -402,7 +403,8 @@ def scheduled_charging(self,
soc_request_interval_offset,
charging_type,
ev_template,
bidi_state)
bidi_state,
charge_state)

def _calc_remaining_time(self,
plan: ScheduledChargingPlan,
Expand Down Expand Up @@ -538,7 +540,8 @@ def scheduled_charging_calc_current(self,
soc_request_interval_offset: int,
charging_type: str,
ev_template: EvTemplate,
bidi_state: BidiState) -> Tuple[float, str, str, int]:
bidi_state: BidiState,
charge_state: bool) -> Tuple[float, str, str, int]:
current = 0
submode = "stop"
if selected_plan is None:
Expand All @@ -555,7 +558,10 @@ 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":
if plan.limit.selected != "soc" or charge_state is False:
# das Abfrageintervall nur einbeziehen, wenn die Ladung bereits gestartet wurde und
# SoC-basiertes Laden aktiv ist, sonst wird einfach alles
# um das Abfrageintervall früher gestartet, und nicht die Pufferzeit um das Abfrageintervall erhöht.
soc_request_interval_offset = 0
log.debug("Verwendeter Plan: "+str(plan.name))
if (limit.selected == "soc" and
Expand Down
39 changes: 36 additions & 3 deletions packages/control/ev/charge_template_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ def test_scheduled_charging_calc_current(plan_data: SelectedPlan,

# execution
ret = ct.scheduled_charging_calc_current(plan_data, soc, used_amount, 3, 3, 6,
0, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE)
0, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE, True)

# evaluation
assert ret == expected
Expand All @@ -288,12 +288,45 @@ def test_scheduled_charging_calc_current_no_plans():

# execution
ret = ct.scheduled_charging_calc_current(
None, 63, 5, 3, 3, 6, 0, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE)
None, 63, 5, 3, 3, 6, 0, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE, True)
Comment on lines 279 to +291

Copilot AI Feb 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All existing tests use charge_state=True. Consider adding test cases with charge_state=False and plan.limit.selected="amount" to verify the new logic at line 561-564 of charge_template.py that sets soc_request_interval_offset to 0 for amount-based plans before charging starts. This would ensure the conditional behavior works correctly for both SOC and amount-based plans.

Copilot uses AI. Check for mistakes.

# evaluation
assert ret == (0, "stop", ChargeTemplate.SCHEDULED_CHARGING_NO_PLANS_CONFIGURED, 3)


@pytest.mark.parametrize(
"selected_limit, charge_state, expected",
[
pytest.param("soc", False,
(6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_USE_PV.format("um 8:50 Uhr"), 0),
id="soc request interval not considered, use pv"),
pytest.param("soc", True,
(14, "instant_charging",
ChargeTemplate.SCHEDULED_CHARGING_IN_TIME.format(14, 'einen SoC von 80%', "07:00"), 3),
id="soc request interval considered"),
pytest.param("amount", True,
(6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_USE_PV.format("um 8:50 Uhr"), 0),
id="amount, charging, soc request interval not considered, no soc limit configured"),
pytest.param("amount", False,
(6, "pv_charging", ChargeTemplate.SCHEDULED_CHARGING_USE_PV.format("um 8:50 Uhr"), 0),
id="amount, not charging, soc request interval not considered, no soc limit configured"),
])
def test_scheduled_charging_calc_current_consider_soc_request_interval_offset(
selected_limit: str, charge_state: bool, expected: Tuple[float, str, str, int]):
# setup
ct = ChargeTemplate()
plan = ScheduledChargingPlan()
plan.limit.selected = selected_limit

# execution
ret = ct.scheduled_charging_calc_current(
SelectedPlan(plan=plan, remaining_time=601, phases=3, duration=3600),
79, 0, 3, 3, 6, 800, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE, charge_state)

# evaluation
assert ret == expected


LOADING_HOURS_TODAY = [datetime.datetime(
year=2022, month=5, day=16, hour=8, minute=0).timestamp()]

Expand Down Expand Up @@ -383,7 +416,7 @@ def test_scheduled_charging_calc_current_electricity_tariff(
# execution
ret = ct.scheduled_charging_calc_current(
SelectedPlan(plan=plan, remaining_time=601, phases=3, duration=3600),
current_soc, 0, 3, 3, 6, 0, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE)
current_soc, 0, 3, 3, 6, 0, ChargingType.AC.value, EvTemplate(), BidiState.BIDI_CAPABLE, True)

# evaluation
assert ret == expected
6 changes: 4 additions & 2 deletions packages/control/ev/ev.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,8 @@ def get_required_current(self,
phase_switch_supported: bool,
charging_type: str,
imported_since_plugged: float,
bidi: BidiState) -> Tuple[bool, Optional[str], str, float, int]:
bidi: BidiState,
charge_state: bool) -> Tuple[bool, Optional[str], str, float, int]:
""" ermittelt, ob und mit welchem Strom das EV geladen werden soll (unabhängig vom Lastmanagement)

Parameter
Expand Down Expand Up @@ -166,7 +167,8 @@ def get_required_current(self,
charging_type,
control_parameter,
soc_request_interval_offset,
bidi)
bidi,
charge_state)
message = f"{tmp_message or ''}".strip()

# Wenn Zielladen auf Überschuss wartet, prüfen, ob Zeitladen aktiv ist.
Expand Down