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
19 changes: 8 additions & 11 deletions packages/control/auto_phase_switch_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(self,
expected_state=ChargepointState.PHASE_SWITCH_DELAY),
Params("1to3, not enough power, timer not expired", max_current_single_phase=16,
timestamp_phase_switch_buffer_start=1652683202.0, phases_to_use=1, required_current=6,
evu_surplus=460, get_currents=[15.6, 0, 0], get_power=3450,
evu_surplus=0, get_currents=[15.6, 0, 0], get_power=3450,
state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=1, expected_current=6,
expected_message=f"Verzögerung für die Umschaltung von 1 auf 3 Phasen abgebrochen{Ev.NOT_ENOUGH_POWER}",
expected_state=ChargepointState.CHARGING_ALLOWED),
Expand Down Expand Up @@ -116,7 +116,7 @@ def __init__(self,


@pytest.mark.parametrize("params", cases, ids=[c.name for c in cases])
def test_auto_phase_switch(monkeypatch, vehicle: Ev, params: Params):
def test_auto_phase_switch(monkeypatch: pytest.MonkeyPatch, vehicle: Ev, params: Params):
# setup
mock_evu = Mock(spec=Counter, data=Mock(spec=CounterData,
set=Mock(spec=Set, reserved_surplus=0,
Expand Down Expand Up @@ -153,7 +153,7 @@ def test_auto_phase_switch(monkeypatch, vehicle: Ev, params: Params):


@pytest.mark.parametrize(
"evse_current, get_currents, all_surplus, limit, expected",
"evse_current, get_currents, surplus, limit, expected",
[
pytest.param(8, [7.7]*3, 100, LoadmanagementLimit(None, None), (False, Ev.ENOUGH_POWER),
id="kein 1p3p, genug Leistung für mehrphasige Ladung"),
Expand All @@ -177,24 +177,21 @@ def test_auto_phase_switch(monkeypatch, vehicle: Ev, params: Params):
])
def test_check_phase_switch_conditions(evse_current: int,
get_currents: List[float],
all_surplus: int,
surplus: int,
limit: LoadmanagementLimit,
expected: Tuple[bool, Optional[str]],
monkeypatch):
expected: Tuple[bool, Optional[str]]):
# setup
ev = Ev(0)
mock_get_evu_counter = Mock(return_value=Mock(get_usable_surplus=Mock(return_value=all_surplus)))
monkeypatch.setattr(data.data.counter_all_data, "get_evu_counter", mock_get_evu_counter)

# execution
phase_switch, condition_msg = ev._check_phase_switch_conditions(
ChargeTemplate(),
phase_switch, condition_msg = ev._check_phase_switch_conditions( # type: ignore
ControlParameter(phases=3-get_currents.count(0)),
evse_current,
get_currents,
sum(get_currents)*230,
16,
limit)
limit,
surplus)

# evaluation
assert (phase_switch, condition_msg) == expected
36 changes: 18 additions & 18 deletions packages/control/ev/ev.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,41 +257,35 @@ def check_min_max_current(self,
NOT_ENOUGH_POWER = ", da nicht ausreichend Überschuss für mehrphasiges Laden zur Verfügung steht."

def _check_phase_switch_conditions(self,
charge_template: ChargeTemplate,
control_parameter: ControlParameter,
evse_current: float,
get_currents: List[float],
get_power: float,
max_current_cp: int,
limit: LoadmanagementLimit) -> Tuple[bool, Optional[str]]:
limit: LoadmanagementLimit,
surplus: float) -> Tuple[bool, Optional[str]]:
# Manche EV laden mit 6.1A bei 6A Soll-Strom
min_current = max(control_parameter.min_current, control_parameter.required_current)
min_current_range = min_current + self.ev_template.data.nominal_difference
max_current = min(self.ev_template.data.max_current_single_phase, max_current_cp)
max_current_range = max_current - self.ev_template.data.nominal_difference
phases_in_use = control_parameter.phases
pv_config = data.data.general_data.data.chargemode_config.pv_charging
max_phases_ev = self.ev_template.data.max_phases
if charge_template.data.chargemode.pv_charging.feed_in_limit:
feed_in_yield = pv_config.feed_in_yield
else:
feed_in_yield = 0
all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus(feed_in_yield)
required_surplus = control_parameter.min_current * max_phases_ev * 230 - get_power
unbalanced_load_limit_reached = limit.limiting_value == LimitingValue.UNBALANCED_LOAD
current_limit_reached = limit.limiting_value == LimitingValue.CURRENT
condition_1_to_3 = ((((get_medium_charging_current(get_currents) > max_current_range or current_limit_reached)
and all_surplus > required_surplus) or unbalanced_load_limit_reached) and
and surplus > required_surplus) or unbalanced_load_limit_reached) and
phases_in_use == 1)
condition_3_to_1 = get_medium_charging_current(
get_currents) < min_current_range and all_surplus <= 0 and phases_in_use > 1
get_currents) < min_current_range and surplus <= 0 and phases_in_use > 1
if condition_1_to_3 or condition_3_to_1:
return True, None
else:
if phases_in_use > 1 and all_surplus > 0:
if phases_in_use > 1 and surplus > 0:
# genug Leistung, um weiter mehrphasig zu laden
return False, self.ENOUGH_POWER
elif phases_in_use == 1 and (all_surplus < required_surplus or unbalanced_load_limit_reached):
elif phases_in_use == 1 and (surplus < required_surplus or unbalanced_load_limit_reached):
# nicht genug Leistung, um mehrphasig zu laden, also einphasig laden
return False, self.NOT_ENOUGH_POWER
elif ((get_medium_charging_current(get_currents) < max_current_range and
Expand Down Expand Up @@ -326,7 +320,6 @@ def auto_phase_switch(self,
feed_in_yield = pv_config.feed_in_yield
else:
feed_in_yield = 0
all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus(feed_in_yield)
delay = pv_config.phase_switch_delay * 60
if phases_in_use == 1:
direction_str = f"Umschaltung von 1 auf {max_phases}"
Expand All @@ -343,19 +336,26 @@ def auto_phase_switch(self,
new_phase = 1
new_current = self.ev_template.data.max_current_single_phase
waiting_time = pv_config.switch_off_delay
all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus(feed_in_yield)
if control_parameter.state == ChargepointState.PHASE_SWITCH_DELAY:
# eigene reservierte Leistung addieren, wenn die Verzögerung für die Umschaltung läuft,
# da diese Leistung bereits für die Umschaltung reserviert ist.
surplus = all_surplus + max(0, required_reserved_power)
else:
surplus = all_surplus

log.debug(
f'Genutzter Strom: {get_medium_charging_current(get_currents)}A, Überschuss: {all_surplus}W, benötigte '
f'Genutzter Strom: {get_medium_charging_current(get_currents)}A, Überschuss: {surplus}W, benötigte '
f'neue Leistung: {required_reserved_power}W')
# Wenn gerade umgeschaltet wird, darf kein Timer gestartet werden.
if not self.ev_template.data.prevent_phase_switch:
condition, condition_msg = self._check_phase_switch_conditions(charge_template,
control_parameter,
condition, condition_msg = self._check_phase_switch_conditions(control_parameter,
evse_current,
get_currents,
get_power,
max_current_cp,
limit)
limit,
surplus)
if control_parameter.state not in PHASE_SWITCH_STATES:
if condition:
# Wenn nach der Umschaltung weniger Leistung benötigt wird, soll während der Verzögerung keine
Expand Down Expand Up @@ -404,7 +404,7 @@ def auto_phase_switch(self,

def _remaining_phase_switch_time(self, control_parameter: ControlParameter,
waiting_time: float,
buffer: float) -> float:
buffer: float) -> Tuple[bool, Optional[str]]:
if control_parameter.timestamp_phase_switch_buffer_start is None:
control_parameter.timestamp_phase_switch_buffer_start = timecheck.create_timestamp()
# Wenn der Puffer seit der letzen Umschaltung abgelaufen ist, warte noch die Umschaltverzögerung ab. ODER
Expand Down