diff --git a/packages/control/algorithm/algorithm.py b/packages/control/algorithm/algorithm.py index 4c4ed46aa5..f507ab0817 100644 --- a/packages/control/algorithm/algorithm.py +++ b/packages/control/algorithm/algorithm.py @@ -60,7 +60,7 @@ def _check_auto_phase_switch_delay(self) -> None: if cp.data.set.charging_ev != -1: charging_ev = cp.data.set.charging_ev_data control_parameter = cp.data.control_parameter - if cp.cp_ev_chargemode_support_phase_switch(): + if cp.cp_state_hw_support_phase_switch() and control_parameter.template_phases == 0: # Gibt die Stromstärke und Phasen zurück, mit denen nach der Umschaltung geladen werden # soll. Falls keine Umschaltung erforderlich ist, werden Strom und Phasen, die übergeben # wurden, wieder zurückgegeben. diff --git a/packages/control/algorithm/integration_test/pv_charging_test.py b/packages/control/algorithm/integration_test/pv_charging_test.py index c21eae69dc..aa7c6e25fd 100644 --- a/packages/control/algorithm/integration_test/pv_charging_test.py +++ b/packages/control/algorithm/integration_test/pv_charging_test.py @@ -223,9 +223,9 @@ def test_surplus(params: ParamsSurplus, all_cp_pv_charging_3p, all_cp_charging_3 data.data.counter_data["counter6"].data.set.raw_currents_left = params.raw_currents_left_counter6 mock_get_component_name_by_id = Mock(return_value="Garage") monkeypatch.setattr(loadmanagement, "get_component_name_by_id", mock_get_component_name_by_id) - data.data.cp_data["cp3"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1 - data.data.cp_data["cp4"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1 - data.data.cp_data["cp5"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1 + for i in range(3, 6): + data.data.cp_data[f"cp{i}"].data.set.charge_template.data.chargemode.pv_charging.phases_to_use = 1 + data.data.cp_data[f"cp{i}"].data.control_parameter.template_phases = 1 # execution Algorithm().calc_current() @@ -276,6 +276,8 @@ def test_phase_switch(all_cp_pv_charging_3p, all_cp_charging_3p, monkeypatch): "cp3"].data.control_parameter.state = ChargepointState.CHARGING_ALLOWED data.data.cp_data[ "cp3"].data.control_parameter.timestamp_last_phase_switch = 1652682252 + for i in range(3, 6): + data.data.cp_data[f"cp{i}"].data.control_parameter.template_phases = 0 # execution Algorithm().calc_current() @@ -298,6 +300,8 @@ def test_phase_switch_1p_3p(all_cp_pv_charging_1p, monkeypatch): data.data.cp_data["cp3"].data.control_parameter.timestamp_last_phase_switch = 1652682252 data.data.cp_data["cp4"].data.get.currents = [0, 0, 0] data.data.cp_data["cp5"].data.get.currents = [0, 0, 0] + for i in range(3, 6): + data.data.cp_data[f"cp{i}"].data.control_parameter.template_phases = 0 # execution Algorithm().calc_current() diff --git a/packages/control/algorithm/surplus_controlled.py b/packages/control/algorithm/surplus_controlled.py index d4ceadca27..cca250528d 100644 --- a/packages/control/algorithm/surplus_controlled.py +++ b/packages/control/algorithm/surplus_controlled.py @@ -127,10 +127,12 @@ def check_submode_pv_charging(self) -> None: for cp in get_chargepoints_by_chargemodes(CONSIDERED_CHARGE_MODES_PV_ONLY): try: def phase_switch_necessary() -> bool: - return cp.cp_ev_chargemode_support_phase_switch() and cp.data.get.phases_in_use != 1 + return (cp.cp_state_hw_support_phase_switch() and + cp.data.get.phases_in_use != 1 and + cp.data.control_parameter.template_phases == 0) control_parameter = cp.data.control_parameter if cp.chargemode_changed or cp.submode_changed: - if control_parameter.state == ChargepointState.CHARGING_ALLOWED: + if (control_parameter.state in CHARGING_STATES): if cp.data.set.charging_ev_data.ev_template.data.prevent_charge_stop is False: threshold = evu_counter.calc_switch_off_threshold(cp)[0] if evu_counter.calc_raw_surplus() - cp.data.set.required_power < threshold: diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index 0d403dea61..1d5ec48a2e 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -440,7 +440,7 @@ def check_phase_switch_completed(self): if self.data.control_parameter.state == ChargepointState.WAIT_FOR_USING_PHASES: if check_timestamp(self.data.control_parameter.timestamp_charge_start, charging_ev.ev_template.data.keep_charge_active_duration) is False: - if self.cp_ev_support_phase_switch() and self.failed_phase_switches_reached(): + if self.hw_supports_phase_switch() and self.failed_phase_switches_reached(): if phase_switch.phase_switch_thread_alive(self.num) is False: self.data.control_parameter.state = ChargepointState.PHASE_SWITCH_AWAITED if self._is_phase_switch_required() is False: @@ -467,7 +467,7 @@ def initiate_phase_switch(self): Pub().pub("openWB/set/chargepoint/"+str(self.num)+"/set/phases_to_use", self.data.control_parameter.phases) self.data.set.phases_to_use = self.data.control_parameter.phases - if self.cp_ev_support_phase_switch(): + if self.hw_supports_phase_switch(): if self._is_phase_switch_required(): # Wenn die Umschaltverzögerung aktiv ist, darf nicht umgeschaltet werden. if (self.data.control_parameter.state != ChargepointState.PERFORMING_PHASE_SWITCH and @@ -569,7 +569,7 @@ def hw_bidi_capable(self) -> BidiState: else: return BidiState.BIDI_CAPABLE - def set_phases(self, phases: int) -> int: + def set_phases(self, phases: int, template_phases: int) -> int: charging_ev = self.data.set.charging_ev_data phases = min(phases, self.get_max_phase_hw()) @@ -584,12 +584,13 @@ def set_phases(self, phases: int) -> int: phases = self.data.get.phases_in_use else: phases = self.data.control_parameter.phases - elif self.cp_ev_support_phase_switch() is False: + elif self.hw_supports_phase_switch() is False: # sonst passt die Phasenzahl nicht bei Autos, die eine Phase weg schalten. log.info(f"Phasenumschaltung an Ladepunkt {self.num} wird durch die Hardware nicht unterstützt.") phases = phases if phases != self.data.control_parameter.phases: self.data.control_parameter.phases = phases + self.data.control_parameter.template_phases = template_phases return phases def check_cp_max_current(self, required_current: float, phases: int) -> float: @@ -698,18 +699,18 @@ def update(self, ev_list: Dict[str, Ev]) -> None: if charging_possible: try: charging_ev = self._get_charging_ev(vehicle, ev_list) - state, message_ev, submode, required_current, phases = charging_ev.get_required_current( + state, message_ev, submode, required_current, template_phases = charging_ev.get_required_current( self.data.set.charge_template, self.data.control_parameter, self.get_max_phase_hw(), - self.cp_ev_support_phase_switch(), + self.hw_supports_phase_switch(), self.template.data.charging_type, self.data.control_parameter.timestamp_chargemode_changed or create_timestamp(), self.data.set.log.imported_since_plugged, self.hw_bidi_capable(), self.data.get.phases_in_use) - phases = self.get_phases_by_selected_chargemode(phases) - phases = self.set_phases(phases) + 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) required_current = self.chargepoint_module.add_conversion_loss_to_current(required_current) self.set_chargemode_changed(submode) @@ -900,40 +901,21 @@ def _pub_connected_vehicle(self, vehicle: Ev): except Exception: log.exception("Fehler im Prepare-Modul") - def cp_ev_chargemode_support_phase_switch(self) -> bool: - if (self.cp_ev_support_phase_switch() and + def cp_state_hw_support_phase_switch(self) -> bool: + if (self.hw_supports_phase_switch() and self.data.get.charge_state and - self.chargemode_support_phase_switch() and (self.data.control_parameter.state == ChargepointState.CHARGING_ALLOWED or self.data.control_parameter.state == ChargepointState.PHASE_SWITCH_DELAY)): return self.failed_phase_switches_reached() else: return False - def cp_ev_support_phase_switch(self) -> bool: + def hw_supports_phase_switch(self) -> bool: return (self.data.config.auto_phase_switch_hw and self.data.get.evse_signaling != EvseSignaling.HLC and (self.data.set.charging_ev_data.ev_template.data.prevent_phase_switch is False or self.data.set.log.imported_since_plugged == 0)) - def chargemode_support_phase_switch(self) -> bool: - control_parameter = self.data.control_parameter - pv_auto_switch = ((control_parameter.chargemode == Chargemode.PV_CHARGING or - control_parameter.chargemode == Chargemode.ECO_CHARGING) and - control_parameter.submode == Chargemode.PV_CHARGING and - self.data.set.charge_template.data.chargemode.pv_charging.phases_to_use == 0) - for p in self.data.set.charge_template.data.chargemode.scheduled_charging.plans: - if p.id == self.data.control_parameter.current_plan: - phases_to_use_pv = p.phases_to_use_pv - break - else: - phases_to_use_pv = 1 - scheduled_auto_switch = ( - control_parameter.chargemode == Chargemode.SCHEDULED_CHARGING and - control_parameter.submode == Chargemode.PV_CHARGING and - phases_to_use_pv == 0) - return (pv_auto_switch or scheduled_auto_switch) - def failed_phase_switches_reached(self) -> bool: if ((data.data.general_data.data.chargemode_config.retry_failed_phase_switches and self.data.control_parameter.failed_phase_switches > self.MAX_FAILED_PHASE_SWITCHES) or diff --git a/packages/control/chargepoint/control_parameter.py b/packages/control/chargepoint/control_parameter.py index e1bbe8c4a5..ee671f705b 100644 --- a/packages/control/chargepoint/control_parameter.py +++ b/packages/control/chargepoint/control_parameter.py @@ -23,6 +23,7 @@ class ControlParameter: state: ChargepointState = field(default=ChargepointState.NO_CHARGING_ALLOWED, metadata={"topic": "control_parameter/state"}) submode: Chargemode_enum = field(default=Chargemode_enum.STOP, metadata={"topic": "control_parameter/submode"}) + template_phases: int = field(default=None, metadata={"topic": "control_parameter/template_phases"}) timestamp_charge_start: Optional[float] = field( default=None, metadata={"topic": "control_parameter/timestamp_charge_start"}) timestamp_chargemode_changed: Optional[float] = field( diff --git a/packages/control/chargepoint/get_phases_test.py b/packages/control/chargepoint/get_phases_test.py index 555a0529bd..41d32943e2 100644 --- a/packages/control/chargepoint/get_phases_test.py +++ b/packages/control/chargepoint/get_phases_test.py @@ -160,7 +160,7 @@ def __init__(self, def test_set_phases(monkeypatch, cp: Chargepoint, params: SetPhasesParams): # setup mock_phase_switch_supported = Mock(name="phase_switch_supported", return_value=params.phase_switch_supported) - monkeypatch.setattr(Chargepoint, "cp_ev_support_phase_switch", mock_phase_switch_supported) + monkeypatch.setattr(Chargepoint, "hw_supports_phase_switch", mock_phase_switch_supported) cp.data.get.phases_in_use = params.phases_in_use cp.data.set.log.imported_since_plugged = params.imported_since_plugged charging_ev_data = cp.data.set.charging_ev_data @@ -168,7 +168,7 @@ def test_set_phases(monkeypatch, cp: Chargepoint, params: SetPhasesParams): cp.data.control_parameter.phases = params.phases_in_use # execution - phases = cp.set_phases(params.phases) + phases = cp.set_phases(params.phases, 3) # evaluation assert phases == params.expected_phases diff --git a/packages/control/counter.py b/packages/control/counter.py index d82b106be1..b00b0f79a1 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -349,7 +349,7 @@ def switch_on_timer_expired(self, chargepoint: Chargepoint) -> None: max_phases_power = ev_template.data.min_current * ev_template.data.max_phases * 230 if (control_parameter.submode == Chargemode.PV_CHARGING and chargepoint.data.set.charge_template.data.chargemode.pv_charging.phases_to_use == 0 and - chargepoint.cp_ev_support_phase_switch() and + chargepoint.hw_supports_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) diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index 2846b1db46..a18eaebb9d 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -485,7 +485,8 @@ def process_chargepoint_topic(self, msg: mqtt.MQTTMessage): self._validate_value(msg, float, [(0, 0), (6, 32), (0, 450)]) else: self._validate_value(msg, float, [(6, 32), (0, 0)]) - elif "/control_parameter/phases" in msg.topic: + elif ("/control_parameter/phases" in msg.topic or + "/control_parameter/template_phases" in msg.topic): self._validate_value(msg, int, [(0, 3)]) elif "/control_parameter/failed_phase_switches" in msg.topic: self._validate_value(msg, int, [(0, 4)]) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 094067adcd..deca0711f7 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -106,6 +106,7 @@ class UpdateConfig: "^openWB/chargepoint/[0-9]+/control_parameter/required_currents$", "^openWB/chargepoint/[0-9]+/control_parameter/state$", "^openWB/chargepoint/[0-9]+/control_parameter/submode$", + "^openWB/chargepoint/[0-9]+/control_parameter/template_phases$", "^openWB/chargepoint/[0-9]+/control_parameter/timestamp_charge_start$", "^openWB/chargepoint/[0-9]+/control_parameter/timestamp_chargemode_changed$", "^openWB/chargepoint/[0-9]+/control_parameter/timestamp_last_phase_switch$",