diff --git a/packages/control/auto_phase_switch_test.py b/packages/control/auto_phase_switch_test.py index 97aa74456c..f1f39adeef 100644 --- a/packages/control/auto_phase_switch_test.py +++ b/packages/control/auto_phase_switch_test.py @@ -35,7 +35,6 @@ def __init__(self, phases_to_use: int, required_current: float, evu_surplus: int, - reserved_evu_overhang: int, get_currents: List[float], get_power: float, state: ChargepointState, @@ -50,7 +49,6 @@ def __init__(self, self.phases_to_use = phases_to_use self.required_current = required_current self.available_power = evu_surplus - self.reserved_evu_overhang = reserved_evu_overhang self.get_currents = get_currents self.get_power = get_power self.state = state @@ -63,37 +61,37 @@ def __init__(self, cases = [ Params("1to3, enough power, start timer", max_current_single_phase=16, timestamp_auto_phase_switch=None, - phases_to_use=1, required_current=6, evu_surplus=-800, reserved_evu_overhang=0, get_currents=[15.6, 0, 0], + phases_to_use=1, required_current=6, evu_surplus=800, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.CHARGING_ALLOWED, expected_phases_to_use=1, expected_current=6, expected_message=Ev.PHASE_SWITCH_DELAY_TEXT.format("Umschaltung von 1 auf 3", "7 Min. 0 Sek."), expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("1to3, not enough power, start timer", max_current_single_phase=16, timestamp_auto_phase_switch=None, - phases_to_use=1, required_current=6, evu_surplus=-300, reserved_evu_overhang=0, get_currents=[15.6, 0, 0], + phases_to_use=1, required_current=6, evu_surplus=300, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.CHARGING_ALLOWED, expected_phases_to_use=1, expected_current=6, expected_state=ChargepointState.CHARGING_ALLOWED), Params("1to3, enough power, timer not expired", max_current_single_phase=16, timestamp_auto_phase_switch=1652682952.0, phases_to_use=1, required_current=6, - evu_surplus=-1200, reserved_evu_overhang=460, get_currents=[15.6, 0, 0], get_power=3450, + evu_surplus=1460, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=1, expected_current=6, expected_message=Ev.PHASE_SWITCH_DELAY_TEXT.format("Umschaltung von 1 auf 3", "2 Min. 0 Sek."), expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("1to3, not enough power, timer not expired", max_current_single_phase=16, timestamp_auto_phase_switch=1652682952.0, phases_to_use=1, required_current=6, - evu_surplus=0, reserved_evu_overhang=460, get_currents=[15.6, 0, 0], get_power=3450, + evu_surplus=460, 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_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.CHARGING_ALLOWED), Params("1to3, enough power, timer expired", max_current_single_phase=16, timestamp_auto_phase_switch=1652682772.0, phases_to_use=1, required_current=6, - evu_surplus=-1200, reserved_evu_overhang=460, get_currents=[15.6, 0, 0], get_power=3450, + evu_surplus=1640, get_currents=[15.6, 0, 0], get_power=3450, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=3, expected_current=6, expected_state=ChargepointState.PHASE_SWITCH_DELAY_EXPIRED), Params("3to1, not enough power, start timer", max_current_single_phase=16, timestamp_auto_phase_switch=None, - phases_to_use=3, required_current=6, evu_surplus=0, reserved_evu_overhang=0, + phases_to_use=3, required_current=6, evu_surplus=0, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.CHARGING_ALLOWED, expected_phases_to_use=3, expected_current=6, expected_message="Umschaltung von 3 auf 1 Phasen in 9 Min. 0 Sek..", @@ -101,7 +99,7 @@ def __init__(self, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("3to1, not enough power, timer not expired", max_current_single_phase=16, timestamp_auto_phase_switch=1652682952.0, - phases_to_use=3, required_current=6, evu_surplus=0, reserved_evu_overhang=-460, + phases_to_use=3, required_current=6, evu_surplus=-460, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=3, expected_current=6, expected_message="Umschaltung von 3 auf 1 Phasen in 4 Min. 0 Sek..", @@ -109,14 +107,14 @@ def __init__(self, expected_state=ChargepointState.PHASE_SWITCH_DELAY), Params("3to1, enough power, timer not expired", max_current_single_phase=16, timestamp_auto_phase_switch=1652682952.0, phases_to_use=3, required_current=6, - evu_surplus=-860, reserved_evu_overhang=0, get_currents=[4.5, 4.4, 5.8], + evu_surplus=860, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=3, expected_current=6, expected_message=f"Verzögerung für die Umschaltung von 3 auf 1 Phasen abgebrochen{Ev.ENOUGH_POWER}", expected_timestamp_auto_phase_switch=1652683252.0, expected_state=ChargepointState.CHARGING_ALLOWED), Params("3to1, not enough power, timer expired", max_current_single_phase=16, timestamp_auto_phase_switch=1652682592.0, phases_to_use=3, required_current=6, - evu_surplus=0, reserved_evu_overhang=-460, get_currents=[4.5, 4.4, 5.8], + evu_surplus=-460, get_currents=[4.5, 4.4, 5.8], get_power=3381, state=ChargepointState.PHASE_SWITCH_DELAY, expected_phases_to_use=1, expected_current=16, expected_state=ChargepointState.PHASE_SWITCH_DELAY_EXPIRED), ] @@ -126,12 +124,12 @@ def __init__(self, def test_auto_phase_switch(monkeypatch, vehicle: Ev, params: Params): # setup mock_evu = Mock(spec=Counter, data=Mock(spec=CounterData, - set=Mock(spec=Set, reserved_surplus=params.reserved_evu_overhang, + set=Mock(spec=Set, reserved_surplus=0, released_surplus=0))) mock_get_evu_counter = Mock(name="power_for_bat_charging", return_value=mock_evu) monkeypatch.setattr(data.data.counter_all_data, "get_evu_counter", mock_get_evu_counter) mock_evu_counter_surplus = Mock(return_value=params.available_power) - monkeypatch.setattr(mock_evu, "calc_surplus", mock_evu_counter_surplus) + monkeypatch.setattr(mock_evu, "get_usable_surplus", mock_evu_counter_surplus) vehicle.ev_template.data.max_current_single_phase = params.max_current_single_phase control_parameter = ControlParameter() diff --git a/packages/control/counter.py b/packages/control/counter.py index 6cf4252960..c00a0621e0 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -7,6 +7,7 @@ from typing import List, Tuple from control import data +from control.chargemode import Chargemode from control.ev import Ev from control.chargepoint.chargepoint import Chargepoint from control.chargepoint.chargepoint_state import ChargepointState @@ -249,11 +250,17 @@ def _control_range_offset(self): log.debug(f"Anpassen des Regelbereichs {range_offset}W") return range_offset + def get_usable_surplus(self, feed_in_yield: float) -> float: + # verbleibender EVU-Überschuss unter Berücksichtigung der Einspeisegrenze und Speicherleistung + return (-self.calc_surplus() - self.data.set.released_surplus + + self.data.set.reserved_surplus - feed_in_yield) + SWITCH_ON_FALLEN_BELOW = "Einschaltschwelle während der Einschaltverzögerung unterschritten." SWITCH_ON_WAITING = "Die Ladung wird gestartet, sobald in {} die Einschaltverzögerung abgelaufen ist." SWITCH_ON_NOT_EXCEEDED = ("Die Ladung kann nicht gestartet werden, da die Einschaltschwelle nicht erreicht " "wird.") SWITCH_ON_EXPIRED = "Einschaltschwelle für die Dauer der Einschaltverzögerung überschritten." + SWITCH_ON_MAX_PHASES = "Der Überschuss ist ausreichend, um direkt mit {} Phasen zu laden." def calc_switch_on_power(self, chargepoint: Chargepoint) -> Tuple[float, float]: surplus = self.data.set.surplus_power_left - self.data.set.reserved_surplus @@ -329,6 +336,18 @@ def switch_on_timer_expired(self, chargepoint: Chargepoint) -> None: self.data.set.reserved_surplus -= pv_config.switch_on_threshold*control_parameter.phases msg = self.SWITCH_ON_EXPIRED.format(pv_config.switch_on_threshold) control_parameter.state = ChargepointState.CHARGING_ALLOWED + + if chargepoint.data.set.charging_ev_data.charge_template.data.chargemode.pv_charging.feed_in_limit: + feed_in_yield = pv_config.feed_in_yield + else: + feed_in_yield = 0 + ev_template = chargepoint.data.set.charging_ev_data.ev_template + max_phases_power = ev_template.data.min_current * ev_template.data.max_phases * 230 + if (data.data.general_data.get_phases_chargemode(Chargemode.PV_CHARGING.value) == 0 and + chargepoint.cp_ev_support_phase_switch() and + self.get_usable_surplus(feed_in_yield) > max_phases_power): + control_parameter.phases = ev_template.data.max_phases + msg += self.SWITCH_ON_MAX_PHASES.format(ev_template.data.max_phases) chargepoint.set_state_and_log(msg) except Exception: log.exception("Fehler im allgemeinen PV-Modul") diff --git a/packages/control/ev.py b/packages/control/ev.py index 6c8e173294..78b762f5bf 100644 --- a/packages/control/ev.py +++ b/packages/control/ev.py @@ -398,10 +398,7 @@ def _check_phase_switch_conditions(self, feed_in_yield = pv_config.feed_in_yield else: feed_in_yield = 0 - evu_counter = data.data.counter_all_data.get_evu_counter() - # verbleibender EVU-Überschuss unter Berücksichtigung der Einspeisegrenze und Speicherleistung - all_surplus = (-evu_counter.calc_surplus() - evu_counter.data.set.released_surplus + - evu_counter.data.set.reserved_surplus - feed_in_yield) + all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus(feed_in_yield) condition_1_to_3 = (((max(get_currents) > max_current and all_surplus > self.ev_template.data.min_current * max_phases_ev * 230 - get_power) or limit == LimitingValue.UNBALANCED_LOAD.value) and @@ -439,10 +436,7 @@ def auto_phase_switch(self, feed_in_yield = pv_config.feed_in_yield else: feed_in_yield = 0 - evu_counter = data.data.counter_all_data.get_evu_counter() - # verbleibender EVU-Überschuss unter Berücksichtigung der Einspeisegrenze und Speicherleistung - all_surplus = (-evu_counter.calc_surplus() - evu_counter.data.set.released_surplus + - evu_counter.data.set.reserved_surplus - feed_in_yield) + all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus(feed_in_yield) if phases_in_use == 1: direction_str = f"Umschaltung von 1 auf {max_phases}" delay = pv_config.phase_switch_delay * 60