From d2038838e0ab3d111680341f40a22f56e3e7a9c1 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Mon, 3 Aug 2026 13:42:51 +0200 Subject: [PATCH 1/6] untested --- .../public/default-dynamic-security.json | 74 +++++++++------- packages/control/algorithm/algorithm.py | 1 - .../algorithm/integration_test/conftest.py | 2 +- .../control/algorithm/surplus_controlled.py | 17 ++-- .../algorithm/surplus_controlled_test.py | 42 +++------ packages/control/auto_phase_switch_test.py | 4 +- packages/control/bat_all.py | 32 +++---- packages/control/bat_all_test.py | 58 +++++++------ packages/control/chargepoint/chargepoint.py | 4 +- .../control/chargepoint/chargepoint_test.py | 2 +- .../control/chargepoint/get_phases_test.py | 2 +- packages/control/counter.py | 87 +++++++++---------- packages/control/counter_test.py | 7 +- packages/control/ev/charge_template.py | 1 - packages/control/ev/ev.py | 15 ++-- packages/control/general.py | 72 +++++++++------ packages/control/loadmanagement.py | 18 ++-- packages/control/loadmanagement_test.py | 2 +- packages/helpermodules/create_debug.py | 38 ++++---- packages/helpermodules/setdata.py | 31 +++---- packages/helpermodules/update_config.py | 66 +++++++------- .../display_themes/cards/source/src/App.vue | 2 +- .../components/Battery/BatteryModeModal.vue | 4 +- .../cards/source/src/stores/mqtt.js | 12 +-- .../source/src/views/ChargePointsView.vue | 47 ---------- .../chargePointList/configPanels/ConfigPv.vue | 7 -- .../src/components/chargePointList/model.ts | 10 --- .../chargePointList/cpConfig/ConfigPv.vue | 9 -- .../src/components/chargePointList/model.ts | 11 --- .../src/components/ChargePointPvSettings.vue | 4 +- .../source/src/stores/mqtt-store-model.ts | 1 - .../koala/source/src/stores/mqtt-store.ts | 37 ++------ .../web_themes/standard_legacy/web/index.html | 16 +--- .../standard_legacy/web/processAllMqttMsg.js | 11 +-- .../standard_legacy/web/setupMqttServices.js | 2 +- simpleAPI/simpleAPI_mqtt.py | 2 +- simpleAPI/src/ParameterHandler.php | 2 +- 37 files changed, 303 insertions(+), 449 deletions(-) diff --git a/data/config/mosquitto/public/default-dynamic-security.json b/data/config/mosquitto/public/default-dynamic-security.json index 10ed378e2f..422e796189 100644 --- a/data/config/mosquitto/public/default-dynamic-security.json +++ b/data/config/mosquitto/public/default-dynamic-security.json @@ -1045,49 +1045,55 @@ "acls": [ { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/control_range", + "topic": "openWB/set/general/chargemode_config/surplus/control_range", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/feed_in_yield", + "topic": "openWB/set/general/chargemode_config/surplus/feed_in_limit", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/phase_switch_delay", + "topic": "openWB/set/general/chargemode_config/surplus/feed_in_yield", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/switch_on_threshold", + "topic": "openWB/set/general/chargemode_config/surplus/vehicle/phase_switch_delay", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/retry_failed_phase_switches", + "topic": "openWB/set/general/chargemode_config/surplus/vehicle/switch_on_threshold", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/switch_on_delay", + "topic": "openWB/set/general/chargemode_config/surplus/vehicle/retry_failed_phase_switches", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/switch_off_threshold", + "topic": "openWB/set/general/chargemode_config/surplus/vehicle/switch_on_delay", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/switch_off_delay", + "topic": "openWB/set/general/chargemode_config/surplus/vehicle/switch_off_threshold", + "priority": 0, + "allow": true + }, + { + "acltype": "publishClientSend", + "topic": "openWB/set/general/chargemode_config/surplus/vehicle/switch_off_delay", "priority": 0, "allow": true }, @@ -1099,49 +1105,55 @@ }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/control_range", + "topic": "openWB/general/chargemode_config/surplus/control_range", + "priority": 0, + "allow": true + }, + { + "acltype": "publishClientReceive", + "topic": "openWB/general/chargemode_config/surplus/feed_in_limit", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/feed_in_yield", + "topic": "openWB/general/chargemode_config/surplus/feed_in_yield", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/phase_switch_delay", + "topic": "openWB/general/chargemode_config/surplus/vehicle/phase_switch_delay", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/switch_on_threshold", + "topic": "openWB/general/chargemode_config/surplus/vehicle/switch_on_threshold", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/retry_failed_phase_switches", + "topic": "openWB/general/chargemode_config/surplus/vehicle/retry_failed_phase_switches", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/switch_on_delay", + "topic": "openWB/general/chargemode_config/surplus/vehicle/switch_on_delay", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/switch_off_threshold", + "topic": "openWB/general/chargemode_config/surplus/vehicle/switch_off_threshold", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/switch_off_delay", + "topic": "openWB/general/chargemode_config/surplus/vehicle/switch_off_delay", "priority": 0, "allow": true } @@ -1226,43 +1238,43 @@ }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/bat_mode", + "topic": "openWB/set/general/chargemode_config/bat/mode", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/bat_power_discharge", + "topic": "openWB/set/general/chargemode_config/bat/power_discharge", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/bat_power_discharge_active", + "topic": "openWB/set/general/chargemode_config/bat/power_discharge_active", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/bat_power_reserve", + "topic": "openWB/set/general/chargemode_config/bat/power_reserve", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/bat_power_reserve_active", + "topic": "openWB/set/general/chargemode_config/bat/power_reserve_active", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/max_bat_soc", + "topic": "openWB/set/general/chargemode_config/bat/max_soc", "priority": 0, "allow": true }, { "acltype": "publishClientSend", - "topic": "openWB/set/general/chargemode_config/pv_charging/min_bat_soc", + "topic": "openWB/set/general/chargemode_config/bat/min_soc", "priority": 0, "allow": true }, @@ -1358,43 +1370,43 @@ }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/bat_mode", + "topic": "openWB/general/chargemode_config/bat/mode", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/bat_power_discharge", + "topic": "openWB/general/chargemode_config/bat/power_discharge", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/bat_power_discharge_active", + "topic": "openWB/general/chargemode_config/bat/power_discharge_active", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/bat_power_reserve", + "topic": "openWB/general/chargemode_config/bat/power_reserve", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/bat_power_reserve_active", + "topic": "openWB/general/chargemode_config/bat/power_reserve_active", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/max_bat_soc", + "topic": "openWB/general/chargemode_config/bat/max_soc", "priority": 0, "allow": true }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/min_bat_soc", + "topic": "openWB/general/chargemode_config/bat/min_soc", "priority": 0, "allow": true }, @@ -2794,7 +2806,7 @@ }, { "acltype": "publishClientReceive", - "topic": "openWB/general/chargemode_config/pv_charging/bat_mode", + "topic": "openWB/general/chargemode_config/bat/mode", "priority": 0, "allow": true } diff --git a/packages/control/algorithm/algorithm.py b/packages/control/algorithm/algorithm.py index 2bfbeeb2a5..fa4b01ed8c 100644 --- a/packages/control/algorithm/algorithm.py +++ b/packages/control/algorithm/algorithm.py @@ -68,7 +68,6 @@ def _check_auto_phase_switch_delay(self) -> None: # wurden, wieder zurückgegeben. log.debug(f"Ladepunkt {cp.num}: Prüfen, ob Phasenumschaltung durchgeführt werden soll.") phases, current, message = charging_ev.auto_phase_switch( - cp.data.set.charge_template, cp.data.control_parameter, cp.num, cp.data.get.evse_current, diff --git a/packages/control/algorithm/integration_test/conftest.py b/packages/control/algorithm/integration_test/conftest.py index cbc98f72ff..6b6072c603 100644 --- a/packages/control/algorithm/integration_test/conftest.py +++ b/packages/control/algorithm/integration_test/conftest.py @@ -52,7 +52,7 @@ def data_() -> None: data.data.counter_all_data.data.get.hierarchy = NESTED_HIERARCHY data.data.counter_all_data.data.config.consider_less_charging = True data.data.io_actions = IoActions() - data.data.general_data.data.chargemode_config.pv_charging.retry_failed_phase_switches = True + data.data.general_data.data.chargemode_config.surplus.vehicle.retry_failed_phase_switches = True @dataclass diff --git a/packages/control/algorithm/surplus_controlled.py b/packages/control/algorithm/surplus_controlled.py index 1a39d27678..cca6647541 100644 --- a/packages/control/algorithm/surplus_controlled.py +++ b/packages/control/algorithm/surplus_controlled.py @@ -33,12 +33,7 @@ def set_surplus_current(self) -> None: for mode_tuple, counter in common.mode_and_counter_generator(CONSIDERED_CHARGE_MODES_SURPLUS): preferenced_chargepoints, preferenced_cps_without_set_current = get_preferenced_chargepoint_charging( get_chargepoints_by_mode_and_counter(mode_tuple, f"counter{counter.num}")) - cp_with_feed_in, cp_without_feed_in = self.filter_by_feed_in_limit(preferenced_chargepoints) - if cp_without_feed_in: - self._set(cp_without_feed_in, 0, mode_tuple, counter) - feed_in_yield = data.data.general_data.data.chargemode_config.pv_charging.feed_in_yield - if cp_with_feed_in: - self._set(cp_with_feed_in, feed_in_yield, mode_tuple, counter) + self._set(preferenced_chargepoints, mode_tuple, counter) if preferenced_cps_without_set_current: for cp in preferenced_cps_without_set_current: cp.data.set.current = cp.data.set.target_current @@ -48,7 +43,6 @@ def set_surplus_current(self) -> None: def _set(self, chargepoints: List[Chargepoint], - feed_in_yield: Optional[int], mode_tuple: Tuple[Optional[str], str, bool], counter: Counter) -> None: log.info(f"Mode-Tuple {mode_tuple[0]} - {mode_tuple[1]} - {mode_tuple[2]}, Zähler {counter.num}") @@ -60,20 +54,19 @@ def _set(self, missing_currents, voltages_mean(cp.data.get.voltages), counter, - cp, - feed_in=feed_in_yield + cp ) # im PV-Laden wird der Strom immer durch die Leistung begrenzt if limit.limiting_value is not None and limit.limiting_value != LimitingValue.POWER: cp.data.control_parameter.limit = limit available_for_cp = common.available_current_for_cp(cp, counts, available_currents, missing_currents) - if counter.get_control_range_state(feed_in_yield) == ControlRangeState.MIDDLE: - pv_charging = data.data.general_data.data.chargemode_config.pv_charging + if counter.get_control_range_state() == ControlRangeState.MIDDLE: + surplus = data.data.general_data.data.chargemode_config.surplus dif_to_old_current = available_for_cp + cp.data.set.target_current - cp.data.set.current_prev # Wenn die Differenz zwischen altem und neuem Soll-Strom größer als der Regelbereich ist, trotzdem # nachregeln, auch wenn der Regelbereich eingehalten wird. Sonst würde zB nicht berücksichtigt werden, # wenn noch ein Fahrzeug dazu kommt. - if ((pv_charging.control_range[1] - pv_charging.control_range[0]) / + if ((surplus.control_range[1] - surplus.control_range[0]) / (sum(counter.data.get.voltages) / len(counter.data.get.voltages)) < abs(dif_to_old_current)): current = available_for_cp else: diff --git a/packages/control/algorithm/surplus_controlled_test.py b/packages/control/algorithm/surplus_controlled_test.py index a77060c8b0..5e2d26fa03 100644 --- a/packages/control/algorithm/surplus_controlled_test.py +++ b/packages/control/algorithm/surplus_controlled_test.py @@ -15,6 +15,11 @@ from control.ev.ev import Ev +@pytest.fixture(autouse=True) +def init_data_store(): + data.data_init(Mock()) + + @pytest.fixture(autouse=True) def mock_cp1() -> Chargepoint: return Chargepoint(1, None) @@ -30,29 +35,6 @@ def mock_cp3() -> Chargepoint: return Chargepoint(3, None) -@pytest.mark.parametrize("feed_in_limit_1, feed_in_limit_2, feed_in_limit_3, expected_sorted", - [pytest.param(True, True, True, ([mock_cp1, mock_cp2, mock_cp3], [])), - pytest.param(True, False, True, ([mock_cp1, mock_cp3], [mock_cp2])), - pytest.param(False, False, False, ([], [mock_cp1, mock_cp2, mock_cp3]))]) -def test_filter_by_feed_in_limit(feed_in_limit_1: bool, - feed_in_limit_2: bool, - feed_in_limit_3: bool, - expected_sorted: int): - # setup - def setup_cp(cp: Chargepoint, feed_in_limit: bool) -> Chargepoint: - cp.data = ChargepointData() - cp.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit = feed_in_limit - return cp - - cp1 = setup_cp(mock_cp1, feed_in_limit_1) - cp2 = setup_cp(mock_cp2, feed_in_limit_2) - cp3 = setup_cp(mock_cp3, feed_in_limit_3) - # execution - cp_with_feed_in, cp_without_feed_in = SurplusControlled().filter_by_feed_in_limit([cp1, cp2, cp3]) - # evaluation - assert (cp_with_feed_in, cp_without_feed_in) == expected_sorted - - @pytest.mark.parametrize("new_current, expected_current", [ pytest.param(7, 10), @@ -134,24 +116,28 @@ def test_add_unused_evse_current(evse_current: float, @pytest.mark.parametrize( - "submode_1, submode_2, expected_chargepoints", + "submode_1, submode_2, expected_cp_keys", [ - pytest.param(Chargemode.PV_CHARGING, Chargemode.PV_CHARGING, [mock_cp1, mock_cp2]), - pytest.param(Chargemode.INSTANT_CHARGING, Chargemode.PV_CHARGING, [mock_cp2]), + pytest.param(Chargemode.PV_CHARGING, Chargemode.PV_CHARGING, ["cp1", "cp2"]), + pytest.param(Chargemode.INSTANT_CHARGING, Chargemode.PV_CHARGING, ["cp2"]), pytest.param(Chargemode.INSTANT_CHARGING, Chargemode.INSTANT_CHARGING, []), ]) def test_get_chargepoints_submode_pv_charging(submode_1: Chargemode, submode_2: Chargemode, - expected_chargepoints: List[Chargepoint]): + expected_cp_keys: List[str], + mock_cp1: Chargepoint, + mock_cp2: Chargepoint): # setup def setup_cp(cp: Chargepoint, submode: str) -> Chargepoint: + cp.data = ChargepointData() cp.data.set.charging_ev_data = Ev(0) cp.data.control_parameter.chargemode = Chargemode.PV_CHARGING cp.data.control_parameter.submode = submode cp.data.control_parameter.required_current = 6 return cp - data.Data.cp_data = {"cp1": setup_cp(mock_cp1, submode_1), + data.data.cp_data = {"cp1": setup_cp(mock_cp1, submode_1), "cp2": setup_cp(mock_cp2, submode_2)} + expected_chargepoints = [data.data.cp_data[key] for key in expected_cp_keys] # evaluation chargepoints = get_chargepoints_with_required_current_by_chargemode(CONSIDERED_CHARGE_MODES_PV_ONLY) diff --git a/packages/control/auto_phase_switch_test.py b/packages/control/auto_phase_switch_test.py index 1c2a887b2c..d69eebad74 100644 --- a/packages/control/auto_phase_switch_test.py +++ b/packages/control/auto_phase_switch_test.py @@ -6,7 +6,6 @@ from control.counter import Counter, CounterData, Set from control.limiting_value import LimitingValue, LoadmanagementLimit -from control.ev.charge_template import ChargeTemplate from control.pv_all import PvAll from control.bat_all import BatAll from control.general import General @@ -135,8 +134,7 @@ def test_auto_phase_switch(monkeypatch: pytest.MonkeyPatch, vehicle: Ev, params: control_parameter.state = params.state # execution - phases_to_use, current, message = vehicle.auto_phase_switch(ChargeTemplate(), - control_parameter, + phases_to_use, current, message = vehicle.auto_phase_switch(control_parameter, 0, max(params.get_currents), params.get_currents, diff --git a/packages/control/bat_all.py b/packages/control/bat_all.py index b3ad5851d2..6fb9c557ce 100644 --- a/packages/control/bat_all.py +++ b/packages/control/bat_all.py @@ -342,10 +342,10 @@ def _get_charging_power_left(self): """ ermittelt die Lade-Leistung des Speichers, die zum Laden der EV verwendet werden darf. """ try: - config = data.data.general_data.data.chargemode_config.pv_charging + config = data.data.general_data.data.chargemode_config.bat self.data.set.regulate_up = False - if config.bat_mode == BatConsiderationMode.BAT_MODE.value: + if config.mode == BatConsiderationMode.BAT_MODE.value: if self.data.get.power < 0: # Wenn der Speicher entladen wird, darf diese Leistung nicht zum Laden der Fahrzeuge genutzt werden. # Wenn der Speicher schneller regelt als die LP, würde sonst der Speicher reduziert werden. @@ -354,7 +354,7 @@ def _get_charging_power_left(self): charging_power_left = 0 self.data.set.regulate_up = True if self.data.get.soc < 100 else False # ev wird nach Speicher geladen - elif config.bat_mode == BatConsiderationMode.EV_MODE.value: + elif config.mode == BatConsiderationMode.EV_MODE.value: # Speicher sollte weder ge- noch entladen werden. # wenn aktive Speichersteuerung in Höhe PV-Leistung lädt # hat Speicher Priorität vor EV-Ladung @@ -365,7 +365,7 @@ def _get_charging_power_left(self): charging_power_left = self.data.get.power else: # Speicher soll geladen werden um min SoC zu erreichen - if self.data.get.soc < config.min_bat_soc: + if self.data.get.soc < config.min_soc: self.data.set.hysteresis_discharge = False if self.data.get.power < 0: # Wenn der Speicher entladen wird, darf diese Leistung nicht zum Laden der Fahrzeuge @@ -375,25 +375,25 @@ def _get_charging_power_left(self): self.data.set.regulate_up = True else: # Speicher-Vorrang bis zum Min-Soc - if config.bat_power_reserve_active: - if self.data.get.power > config.bat_power_reserve: + if config.power_reserve_active: + if self.data.get.power > config.power_reserve: # die Differenz darf nicht zum Laden der EV genutzt werden. - charging_power_left = self.data.get.power - config.bat_power_reserve + charging_power_left = self.data.get.power - config.power_reserve else: charging_power_left = ( - config.bat_power_reserve - self.data.get.power) * -1 + config.power_reserve - self.data.get.power) * -1 self.data.set.regulate_up = True else: # Speicher wird geladen charging_power_left = 0 self.data.set.regulate_up = True # Speicher zwischen min und max SoC - elif int(self.data.get.soc) >= config.min_bat_soc and int(self.data.get.soc) < config.max_bat_soc: + elif int(self.data.get.soc) >= config.min_soc and int(self.data.get.soc) < config.max_soc: # Speicher soll aktiv weder ge- noch entladen werden. # Mindest-SoC wird gehalten oder der Speicher mit weiterem vorhanden Überschuss geladen. if self.data.set.hysteresis_discharge is False: charging_power_left = self.data.get.power - # Speicher darf wegen Hysterese bis min_bat_soc entladen werden. + # Speicher darf wegen Hysterese bis min_soc entladen werden. else: if self.data.set.power_limit is None: # set allowed power @@ -411,10 +411,10 @@ def _get_charging_power_left(self): (self.data.config.power_limit_condition == BatPowerLimitCondition.PRICE_LIMIT.value and self.data.set.power_limit is None)) - if config.bat_power_discharge_active and power_discharge_allowed: + if config.power_discharge_active and power_discharge_allowed: # Wenn der Speicher mit mehr als der erlaubten Entladeleistung entladen wird, muss das # vom Überschuss subtrahiert werden. - charging_power_left = config.bat_power_discharge + base_power + charging_power_left = config.power_discharge + base_power log.debug(f"Erlaubte Entlade-Leistung nutzen {charging_power_left}W") else: # Speicher sollte weder ge- noch entladen werden. @@ -441,10 +441,10 @@ def _get_charging_power_left(self): (self.data.config.power_limit_condition == BatPowerLimitCondition.PRICE_LIMIT.value and self.data.set.power_limit is None)) - if config.bat_power_discharge_active and power_discharge_allowed: + if config.power_discharge_active and power_discharge_allowed: # Wenn der Speicher mit mehr als der erlaubten Entladeleistung entladen wird, muss das # vom Überschuss subtrahiert werden. - charging_power_left = config.bat_power_discharge + base_power + charging_power_left = config.power_discharge + base_power log.debug(f"Erlaubte Entlade-Leistung nutzen {charging_power_left}W") else: # Speicher sollte weder ge- noch entladen werden. @@ -518,8 +518,8 @@ def get_charge_mode_vehicle_charge(self): charge_mode = BatChargeMode.BAT_SELF_REGULATION # Debug Informationen - control_range_low = data.data.general_data.data.chargemode_config.pv_charging.control_range[0] - control_range_high = data.data.general_data.data.chargemode_config.pv_charging.control_range[1] + control_range_low = data.data.general_data.data.chargemode_config.surplus.control_range[0] + control_range_high = data.data.general_data.data.chargemode_config.surplus.control_range[1] control_range_center = control_range_high - (control_range_high - control_range_low) / 2 if len(chargepoint_by_chargemodes) == 0: log.debug("Speicher-Leistung nicht begrenzen, da keine Ladepunkte in einem aktiven Lademodus sind.") diff --git a/packages/control/bat_all_test.py b/packages/control/bat_all_test.py index 245a1f9917..46ae106946 100644 --- a/packages/control/bat_all_test.py +++ b/packages/control/bat_all_test.py @@ -10,7 +10,7 @@ from control import data from control.chargepoint.chargepoint import Chargepoint from control.chargepoint.chargepoint_all import AllChargepointData, AllChargepoints, AllGet -from control.general import General, PvCharging +from control.general import ChargemodeConfigBat, General from control.pv import Config, Get, Pv, PvData from modules.devices.generic.mqtt.bat import MqttBat from modules.devices.generic.mqtt.config import MqttBatSetup @@ -81,7 +81,7 @@ def test_limit_bat_power_discharge_no_hybrid_system(monkeypatch: pytest.MonkeyPa @dataclass class Params: name: str - config: PvCharging + config: ChargemodeConfigBat power: float soc: float expected_charging_power_left: float @@ -91,58 +91,60 @@ class Params: cases = [ - Params("Speicher, Speicher lädt", PvCharging(bat_mode="bat_mode"), 500, 90, -100, True), - Params("Speicher, Speicher entlädt", PvCharging(bat_mode="bat_mode"), -500, 90, -600, True), - Params("Speicher, Speicher ist voll", PvCharging(bat_mode="bat_mode"), 0, 100, 0, False), - Params("EV, Speicher lädt", PvCharging(bat_mode="ev_mode"), 500, 90, 500, False), - Params("EV, Speicher entlädt", PvCharging(bat_mode="ev_mode"), -500, 90, -500, False), - Params("EV, Speicher ist voll", PvCharging(bat_mode="ev_mode"), 0, 100, 0, False), + Params("Speicher, Speicher lädt", ChargemodeConfigBat(mode="bat_mode"), 500, 90, -100, True), + Params("Speicher, Speicher entlädt", ChargemodeConfigBat(mode="bat_mode"), -500, 90, -600, True), + Params("Speicher, Speicher ist voll", ChargemodeConfigBat(mode="bat_mode"), 0, 100, 0, False), + Params("EV, Speicher lädt", ChargemodeConfigBat(mode="ev_mode"), 500, 90, 500, False), + Params("EV, Speicher entlädt", ChargemodeConfigBat(mode="ev_mode"), -500, 90, -500, False), + Params("EV, Speicher ist voll", ChargemodeConfigBat(mode="ev_mode"), 0, 100, 0, False), Params("Mindest-SoC, SoC nicht erreicht, Speicher entlädt", - PvCharging(bat_mode="min_soc_bat_mode"), -500, 40, -600, True), + ChargemodeConfigBat(mode="min_soc_bat_mode"), -500, 40, -600, True), Params("Mindest-SoC, SoC nicht erreicht, Speicher lädt", - PvCharging(bat_mode="min_soc_bat_mode"), 500, 40, -100, True), + ChargemodeConfigBat(mode="min_soc_bat_mode"), 500, 40, -100, True), Params("Mindest-SoC, SoC nicht erreicht, Speicher-Reserve, Speicher entlädt", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_reserve=2000, bat_power_reserve_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_reserve=2000, power_reserve_active=True), -500, 40, -600, True), Params("Mindest-SoC, SoC nicht erreicht, Speicher-Reserve nicht ausgenutzt, Speicher lädt", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_reserve=2000, bat_power_reserve_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_reserve=2000, power_reserve_active=True), 1600, 40, -500, True), Params("Mindest-SoC, SoC nicht erreicht, Speicher-Reserve ausgenutzt, Speicher lädt", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_reserve=2000, bat_power_reserve_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_reserve=2000, power_reserve_active=True), 2200, 40, 200, False), - Params("Mindest-SoC, SoC erreicht, Speicher entlädt", PvCharging(bat_mode="min_soc_bat_mode"), -500, 90, -500, + Params("Mindest-SoC, SoC erreicht, Speicher entlädt", ChargemodeConfigBat(mode="min_soc_bat_mode"), -500, 90, -500, False), - Params("Mindest-SoC, SoC erreicht, Speicher lädt", PvCharging(bat_mode="min_soc_bat_mode"), 500, 90, 500, False), - Params("Mindest-SoC, SoC erreicht, Speicher ist voll", PvCharging(bat_mode="min_soc_bat_mode"), 0, 100, 0, False), + Params("Mindest-SoC, SoC erreicht, Speicher lädt", + ChargemodeConfigBat(mode="min_soc_bat_mode"), 500, 90, 500, False), + Params("Mindest-SoC, SoC erreicht, Speicher ist voll", + ChargemodeConfigBat(mode="min_soc_bat_mode"), 0, 100, 0, False), Params("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher entlädt, Entladeleistung nicht erreicht", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), -400, 90, 100, False), Params("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher entlädt, mehr als Entladeleistung", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), -600, 90, -100, False), Params("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher entlädt, Entladeleistung erreicht", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), -500, 90, 0, False), Params("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher lädt mit mehr als Entladeleistung", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), 650, 90, 1150, False), Params("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher lädt mit weniger als Entladeleistung", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), 400, 90, 900, False), Params("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher voll", - PvCharging(bat_mode="min_soc_bat_mode", bat_power_reserve=500, bat_power_reserve_active=True, - min_bat_soc=100), 0, 100, 0, False), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_reserve=500, power_reserve_active=True, + min_soc=100), 0, 100, 0, False), Params(("Mindest-SoC, SoC erreicht, Entladung in Auto, Speicher lädt mit weniger als Entladeleistung, " "Speicher-Sperre aktiv"), - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), 400, 90, 0, False, 600), Params(("Mindest-SoC, Hysterese, EV-Vorrang, keine Speichernutzung"), - PvCharging(bat_mode="min_soc_bat_mode"), 400, 60, 400, False, hysteresis_discharge=False), + ChargemodeConfigBat(mode="min_soc_bat_mode"), 400, 60, 400, False, hysteresis_discharge=False), Params(("Mindest-SoC, Hysterese, Speicherentladung, Speichernutzung erlaubt"), - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), 400, 60, 900, False, hysteresis_discharge=True), Params(("Mindest-SoC, Hysterese, Speicherentladung, Speichernutzung erlaubt, Speicher-Sperre aktiv"), - PvCharging(bat_mode="min_soc_bat_mode", bat_power_discharge=500, bat_power_discharge_active=True), + ChargemodeConfigBat(mode="min_soc_bat_mode", power_discharge=500, power_discharge_active=True), 400, 60, 0, False, 600, hysteresis_discharge=True), ] @@ -158,7 +160,7 @@ def test_get_charging_power_left(params: Params, caplog, data_, monkeypatch): b = Bat(0) b.data.get.power = params.power data.data.bat_data["bat0"] = b - data.data.general_data.data.chargemode_config.pv_charging = params.config + data.data.general_data.data.chargemode_config.bat = params.config mock_limit_bat_power_discharge = MagicMock(side_effect=lambda x: x) monkeypatch.setattr(BatAll, "_limit_bat_power_discharge", mock_limit_bat_power_discharge) diff --git a/packages/control/chargepoint/chargepoint.py b/packages/control/chargepoint/chargepoint.py index e435f7d9f6..e4122267c8 100644 --- a/packages/control/chargepoint/chargepoint.py +++ b/packages/control/chargepoint/chargepoint.py @@ -839,14 +839,14 @@ def hw_supports_phase_switch(self) -> bool: self.data.set.log.imported_since_plugged == 0)) def failed_phase_switches_reached(self) -> bool: - if (data.data.general_data.data.chargemode_config.pv_charging.retry_failed_phase_switches and + if (data.data.general_data.data.chargemode_config.surplus.vehicle.retry_failed_phase_switches and self.data.control_parameter.failed_phase_switches > self.MAX_FAILED_PHASE_SWITCHES): # bei deaktiverter Wiederholung der Umschaltung nur den gewünschten Umschaltvorgang durchführen, # keinen Korrekturversuch self.set_state_and_log( "Keine Phasenumschaltung, da die maximale Anzahl an Fehlversuchen erreicht wurde. ") return True - elif (data.data.general_data.data.chargemode_config.pv_charging.retry_failed_phase_switches is False and + elif (data.data.general_data.data.chargemode_config.surplus.vehicle.retry_failed_phase_switches is False and self.data.control_parameter.failed_phase_switches > 0): return True else: diff --git a/packages/control/chargepoint/chargepoint_test.py b/packages/control/chargepoint/chargepoint_test.py index 3ea9c9e622..57a746649b 100644 --- a/packages/control/chargepoint/chargepoint_test.py +++ b/packages/control/chargepoint/chargepoint_test.py @@ -147,7 +147,7 @@ def test_is_phase_switch_required(params: Params): cp.data.get.charge_state = params.charge_state cp.data.control_parameter.failed_phase_switches = params.failed_phase_switches data.data_init(Mock()) - data.data.general_data.data.chargemode_config.pv_charging.retry_failed_phase_switches = ( + data.data.general_data.data.chargemode_config.surplus.vehicle.retry_failed_phase_switches = ( params.retry_failed_phase_switches ) diff --git a/packages/control/chargepoint/get_phases_test.py b/packages/control/chargepoint/get_phases_test.py index b8bec247e0..e4bf1283f4 100644 --- a/packages/control/chargepoint/get_phases_test.py +++ b/packages/control/chargepoint/get_phases_test.py @@ -219,7 +219,7 @@ def test_failed_phase_switches_reached(cp: Chargepoint, failed_phase_switches: int, expected: bool): # setup - data.data.general_data.data.chargemode_config.pv_charging.retry_failed_phase_switches = ( + data.data.general_data.data.chargemode_config.surplus.vehicle.retry_failed_phase_switches = ( retry_failed_phase_switches ) cp.data.control_parameter.failed_phase_switches = failed_phase_switches diff --git a/packages/control/counter.py b/packages/control/counter.py index e7351b3cef..8a5a02a471 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -231,10 +231,11 @@ def calc_raw_surplus(self): ranged_surplus = surplus + self._control_range_offset() return ranged_surplus - def get_control_range_state(self, feed_in_yield: int) -> ControlRangeState: - control_range_low = data.data.general_data.data.chargemode_config.pv_charging.control_range[0] - control_range_high = data.data.general_data.data.chargemode_config.pv_charging.control_range[1] - surplus = data.data.counter_all_data.get_evu_counter().data.get.power + feed_in_yield + def get_control_range_state(self) -> ControlRangeState: + control_range_low = data.data.general_data.data.chargemode_config.surplus.control_range[0] + control_range_high = data.data.general_data.data.chargemode_config.surplus.control_range[1] + surplus = (data.data.counter_all_data.get_evu_counter().data.get.power + + data.data.general_data.get_feed_in_yield()) if control_range_low > surplus: return ControlRangeState.BELOW elif surplus > control_range_high: @@ -246,17 +247,17 @@ def _control_range_offset(self): if data.data.bat_all_data.data.set.regulate_up: # Regelmodus ignorieren, denn mit Regelmodus Bezug kann keine Einspeisung für den Speicher erzeugt werden. return 0 - control_range_low = data.data.general_data.data.chargemode_config.pv_charging.control_range[0] - control_range_high = data.data.general_data.data.chargemode_config.pv_charging.control_range[1] + control_range_low = data.data.general_data.data.chargemode_config.surplus.control_range[0] + control_range_high = data.data.general_data.data.chargemode_config.surplus.control_range[1] control_range_center = control_range_high - (control_range_high - control_range_low) / 2 range_offset = control_range_center log.debug(f"Anpassen des Regelbereichs {range_offset}W") return range_offset - def get_usable_surplus(self, feed_in_yield: float) -> float: + def get_usable_surplus(self) -> 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) + self.data.set.reserved_surplus - data.data.general_data.get_feed_in_yield()) SWITCH_ON_FALLEN_BELOW = "Einschaltschwelle während der Wartezeit unterschritten." SWITCH_ON_WAITING = "Die Ladung wird gestartet, sobald in {} die Wartezeit abgelaufen ist." @@ -268,25 +269,23 @@ def get_usable_surplus(self, feed_in_yield: float) -> float: def calc_switch_on_power(self, chargepoint: Chargepoint) -> Tuple[float, float]: surplus = self.calc_raw_surplus() - self.data.set.reserved_surplus control_parameter = chargepoint.data.control_parameter - pv_config = data.data.general_data.data.chargemode_config.pv_charging + surplus_config = data.data.general_data.data.chargemode_config.surplus - if chargepoint.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit: - threshold = pv_config.feed_in_yield + if surplus_config.feed_in_limit: + threshold = surplus_config.feed_in_yield else: - threshold = pv_config.switch_on_threshold*control_parameter.phases + threshold = surplus_config.vehicle.switch_on_threshold*control_parameter.phases return surplus, threshold def switch_on_threshold_reached(self, chargepoint: Chargepoint) -> None: try: message = None control_parameter = chargepoint.data.control_parameter - feed_in_limit = chargepoint.data.set.charge_template.data.chargemode.pv_charging.\ - feed_in_limit - pv_config = data.data.general_data.data.chargemode_config.pv_charging + surplus_config = data.data.general_data.data.chargemode_config.surplus timestamp_switch_on_off = control_parameter.timestamp_switch_on_off surplus, threshold = self.calc_switch_on_power(chargepoint) - power_to_reserve = pv_config.switch_on_threshold*control_parameter.phases + power_to_reserve = surplus_config.vehicle.switch_on_threshold*control_parameter.phases if control_parameter.state == ChargepointState.SWITCH_ON_DELAY: # Wurde die Einschaltschwelle erreicht? Reservierte Leistung aus all_surplus herausrechnen, # da diese Leistung ja schon reserviert wurde, als die Einschaltschwelle erreicht wurde. @@ -294,22 +293,22 @@ def switch_on_threshold_reached(self, chargepoint: Chargepoint) -> None: # Einschaltschwelle wurde unterschritten, Timer zurücksetzen timestamp_switch_on_off = None self.data.set.reserved_surplus -= power_to_reserve - message = self.SWITCH_ON_FALLEN_BELOW.format(pv_config.switch_on_threshold) + message = self.SWITCH_ON_FALLEN_BELOW.format(surplus_config.vehicle.switch_on_threshold) control_parameter.state = ChargepointState.NO_CHARGING_ALLOWED else: # Timer starten - if (surplus >= threshold) and ((feed_in_limit and self.data.set.reserved_surplus == 0) or - not feed_in_limit): + if (surplus >= threshold) and ((surplus_config.feed_in_limit and self.data.set.reserved_surplus == 0) or + not surplus_config.feed_in_limit): timestamp_switch_on_off = timecheck.create_timestamp() self.data.set.reserved_surplus += power_to_reserve message = self.SWITCH_ON_WAITING.format(timecheck.convert_timestamp_delta_to_time_string( - timestamp_switch_on_off, pv_config.switch_on_delay)) - if feed_in_limit: - message += "Die Einspeisegrenze wird berücksichtigt." + timestamp_switch_on_off, surplus_config.vehicle.switch_on_delay)) + if surplus_config.feed_in_limit: + message += " Die Einspeisegrenze wird berücksichtigt." control_parameter.state = ChargepointState.SWITCH_ON_DELAY else: # Einschaltschwelle nicht erreicht - message = self.SWITCH_ON_NOT_EXCEEDED.format(pv_config.switch_on_threshold) + message = self.SWITCH_ON_NOT_EXCEEDED.format(surplus_config.vehicle.switch_on_threshold) if timestamp_switch_on_off != control_parameter.timestamp_switch_on_off: control_parameter.timestamp_switch_on_off = timestamp_switch_on_off @@ -328,31 +327,29 @@ def switch_on_timer_expired(self, chargepoint: Chargepoint) -> None: """ try: msg = None - pv_config = data.data.general_data.data.chargemode_config.pv_charging + surplus_config = data.data.general_data.data.chargemode_config.surplus control_parameter = chargepoint.data.control_parameter charging_ev_data = chargepoint.data.set.charging_ev_data # Timer ist noch nicht abgelaufen if timecheck.check_timestamp(control_parameter.timestamp_switch_on_off, - pv_config.switch_on_delay): + surplus_config.vehicle.switch_on_delay): msg = self.SWITCH_ON_WAITING.format(timecheck.convert_timestamp_delta_to_time_string( - control_parameter.timestamp_switch_on_off, pv_config.switch_on_delay)) + control_parameter.timestamp_switch_on_off, surplus_config.vehicle.switch_on_delay)) # Timer abgelaufen else: control_parameter.timestamp_switch_on_off = 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) + self.data.set.reserved_surplus -= ( + surplus_config.vehicle.switch_on_threshold*control_parameter.phases + ) + msg = self.SWITCH_ON_EXPIRED.format(surplus_config.vehicle.switch_on_threshold) control_parameter.state = ChargepointState.WAIT_FOR_USING_PHASES - if chargepoint.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit: - feed_in_yield = pv_config.feed_in_yield - else: - feed_in_yield = 0 ev_template = charging_ev_data.ev_template 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.hw_supports_phase_switch() and - self.get_usable_surplus(feed_in_yield) > max_phases_power): + self.get_usable_surplus() > 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) @@ -370,35 +367,35 @@ def switch_on_timer_expired(self, chargepoint: Chargepoint) -> None: def switch_off_check_timer(self, chargepoint: Chargepoint) -> None: try: msg = None - pv_config = data.data.general_data.data.chargemode_config.pv_charging + surplus_config = data.data.general_data.data.chargemode_config.surplus control_parameter = chargepoint.data.control_parameter if control_parameter.timestamp_switch_on_off is not None: if not timecheck.check_timestamp( control_parameter.timestamp_switch_on_off, - pv_config.switch_off_delay): + surplus_config.vehicle.switch_off_delay): control_parameter.timestamp_switch_on_off = None self.data.set.released_surplus -= chargepoint.data.set.required_power msg = self.SWITCH_OFF_STOP control_parameter.state = ChargepointState.NO_CHARGING_ALLOWED else: msg = self.SWITCH_OFF_WAITING.format(timecheck.convert_timestamp_delta_to_time_string( - control_parameter.timestamp_switch_on_off, pv_config.switch_off_delay)) + control_parameter.timestamp_switch_on_off, surplus_config.switch_off_delay)) chargepoint.set_state_and_log(msg) except Exception: log.exception("Fehler im allgemeinen PV-Modul") def calc_switch_off_threshold(self, chargepoint: Chargepoint) -> float: - pv_config = data.data.general_data.data.chargemode_config.pv_charging + surplus_config = data.data.general_data.data.chargemode_config.surplus control_parameter = chargepoint.data.control_parameter - if chargepoint.data.set.charge_template.data.chargemode.pv_charging.feed_in_limit: + if surplus_config.feed_in_limit: # Der EVU-Überschuss muss ggf um die Einspeisegrenze bereinigt werden. # Wnn die Leistung nicht Einspeisegrenze + Einschaltschwelle erreicht, darf die Ladung nicht pulsieren. # Abschaltschwelle um Einschaltschwelle reduzieren. - threshold = (-data.data.general_data.data.chargemode_config.pv_charging.feed_in_yield - + pv_config.switch_on_threshold*control_parameter.phases) + threshold = (-surplus_config.feed_in_yield + + surplus_config.vehicle.switch_on_threshold*control_parameter.phases) else: - threshold = pv_config.switch_off_threshold + threshold = surplus_config.vehicle.switch_off_threshold return threshold def calc_switch_off(self, chargepoint: Chargepoint) -> Tuple[float, float]: @@ -464,7 +461,7 @@ def switch_off_check_threshold(self, chargepoint: Chargepoint) -> bool: self.data.set.released_surplus += chargepoint.data.set.required_power msg = self.SWITCH_OFF_WAITING.format(timecheck.convert_timestamp_delta_to_time_string( timestamp_switch_on_off, - data.data.general_data.data.chargemode_config.pv_charging.switch_off_delay)) + data.data.general_data.data.chargemode_config.surplus.vehicle.switch_off_delay)) control_parameter.state = ChargepointState.SWITCH_OFF_DELAY # Die Abschaltschwelle wird immer noch überschritten und es sollten weitere LP abgeschaltet # werden. @@ -483,12 +480,12 @@ def reset_switch_on_off(self, chargepoint: Chargepoint): # Wenn bereits geladen wird, lief die Abschaltverzögerung -> Leistung, die nach Abschalten frei # geworden wäre, nicht mehr zum zur Verfügung stehenden Überschuss zählen. # Wenn nicht geladen wird, reservierte Leistung freigeben. - pv_config = data.data.general_data.data.chargemode_config.pv_charging + surplus_config = data.data.general_data.data.chargemode_config.surplus if not chargepoint.data.get.charge_state: - evu_counter.data.set.reserved_surplus -= (pv_config.switch_on_threshold + evu_counter.data.set.reserved_surplus -= (surplus_config.vehicle.switch_on_threshold * chargepoint.data.set.phases_to_use) else: - evu_counter.data.set.released_surplus -= (pv_config.switch_on_threshold + evu_counter.data.set.released_surplus -= (surplus_config.vehicle.switch_on_threshold * chargepoint.data.control_parameter.phases) chargepoint.data.control_parameter.state = ChargepointState.NO_CHARGING_ALLOWED except Exception: diff --git a/packages/control/counter_test.py b/packages/control/counter_test.py index 4b3e59466a..06509b89a5 100644 --- a/packages/control/counter_test.py +++ b/packages/control/counter_test.py @@ -122,7 +122,8 @@ class Params: -681, 15000, 1652683250.0, ChargepointState.SWITCH_ON_DELAY, Counter.SWITCH_ON_FALLEN_BELOW.format(1500), None, 0), Params("Feed_in_limit, Timer starten", True, 0, 15001, 15000, None, ChargepointState.NO_CHARGING_ALLOWED, - Counter.SWITCH_ON_WAITING.format("30 Sek."), 1652683252.0, 1500), + Counter.SWITCH_ON_WAITING.format("30 Sek.") + " Die Einspeisegrenze wird berücksichtigt.", + 1652683252.0, 1500), Params("Feed_in_limit, Einschaltschwelle nicht erreicht", True, 0, 14999, 15000, None, ChargepointState.NO_CHARGING_ALLOWED, Counter.SWITCH_ON_NOT_EXCEEDED.format(1500), None, 0), Params("Feed_in_limit, Einschaltschwelle läuft", True, 1500, 15001, @@ -141,7 +142,7 @@ def test_switch_on_threshold_reached(params: Params, caplog, general_data_fixtur cp.data.control_parameter.state = params.state cp.data.control_parameter.timestamp_switch_on_off = params.timestamp_switch_on_off ev.data.charge_template = ChargeTemplate() - ev.data.charge_template.data.chargemode.pv_charging.feed_in_limit = params.feed_in_limit + data.data.general_data.data.chargemode_config.surplus.feed_in_limit = params.feed_in_limit cp.data.set.charging_ev_data = ev mock_calc_switch_on_power = Mock(return_value=[params.surplus, params.threshold]) monkeypatch.setattr(Counter, "calc_switch_on_power", mock_calc_switch_on_power) @@ -170,7 +171,7 @@ def test_control_range(control_range, evu_power, expected_range_offset, general_ get_evu_counter_mock = Mock(return_value=Mock(spec=Counter, data=Mock( spec=CounterData, get=Mock(spec=Get, power=evu_power)))) monkeypatch.setattr(data.data.counter_all_data, "get_evu_counter", get_evu_counter_mock) - data.data.general_data.data.chargemode_config.pv_charging.control_range = control_range + data.data.general_data.data.chargemode_config.surplus.control_range = control_range c = Counter(0) # execution diff --git a/packages/control/ev/charge_template.py b/packages/control/ev/charge_template.py index 20f7ba88bb..655b07a24f 100644 --- a/packages/control/ev/charge_template.py +++ b/packages/control/ev/charge_template.py @@ -64,7 +64,6 @@ class InstantCharging: class PvCharging: dc_min_current: float = 145 dc_min_soc_current: float = 145 - feed_in_limit: bool = False limit: Limit = field(default_factory=limit_factory) min_current: int = 0 min_soc_current: int = 10 diff --git a/packages/control/ev/ev.py b/packages/control/ev/ev.py index fab9167328..88ef507868 100644 --- a/packages/control/ev/ev.py +++ b/packages/control/ev/ev.py @@ -302,7 +302,6 @@ def _check_phase_switch_conditions(self, PHASE_SWITCH_DELAY_TEXT = '{} Phasen in {}.' def auto_phase_switch(self, - charge_template: ChargeTemplate, control_parameter: ControlParameter, cp_num: int, evse_current: float, @@ -315,12 +314,8 @@ def auto_phase_switch(self, current = control_parameter.required_current phases_to_use = control_parameter.phases phases_in_use = control_parameter.phases - pv_config = data.data.general_data.data.chargemode_config.pv_charging - if charge_template.data.chargemode.pv_charging.feed_in_limit: - feed_in_yield = pv_config.feed_in_yield - else: - feed_in_yield = 0 - delay = pv_config.phase_switch_delay * 60 + surplus_config = data.data.general_data.data.chargemode_config.surplus + delay = surplus_config.vehicle.phase_switch_delay * 60 if phases_in_use == 1: direction_str = f"Umschaltung von 1 auf {max_phases}" required_reserved_power = (control_parameter.min_current * max_phases * 230 - @@ -328,15 +323,15 @@ def auto_phase_switch(self, new_phase = max_phases new_current = control_parameter.min_current - waiting_time = pv_config.switch_on_delay + waiting_time = surplus_config.vehicle.switch_on_delay else: direction_str = f"Umschaltung von {max_phases} auf 1" # Es kann einphasig mit entsprechend niedriger Leistung gestartet werden. required_reserved_power = 0 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) + waiting_time = surplus_config.vehicle.switch_off_delay + all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus() 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. diff --git a/packages/control/general.py b/packages/control/general.py index 80941ead81..13924464a0 100644 --- a/packages/control/general.py +++ b/packages/control/general.py @@ -17,51 +17,60 @@ def control_range_factory() -> List: @dataclass -class PvCharging: - bat_power_reserve: int = field(default=2000, metadata={ - "topic": "chargemode_config/pv_charging/bat_power_reserve"}) - bat_power_reserve_active: bool = field(default=False, metadata={ - "topic": "chargemode_config/pv_charging/bat_power_reserve_active"}) - control_range: List = field(default_factory=control_range_factory, metadata={ - "topic": "chargemode_config/pv_charging/control_range"}) - feed_in_yield: int = field(default=15000, metadata={ - "topic": "chargemode_config/pv_charging/feed_in_yield"}) +class ChargemodeConfigBat: + power_reserve: int = field(default=2000, metadata={ + "topic": "chargemode_config/bat/power_reserve"}) + power_reserve_active: bool = field(default=False, metadata={ + "topic": "chargemode_config/bat/power_reserve_active"}) + power_discharge: int = field(default=1500, metadata={ + "topic": "chargemode_config/bat/power_discharge"}) + power_discharge_active: bool = field(default=False, metadata={ + "topic": "chargemode_config/bat/power_discharge_active"}) + min_soc: int = field(default=50, metadata={ + "topic": "chargemode_config/bat/min_soc"}) + max_soc: int = field(default=70, metadata={ + "topic": "chargemode_config/bat/max_soc"}) + mode: BatConsiderationMode = field(default=BatConsiderationMode.EV_MODE.value, metadata={ + "topic": "chargemode_config/bat/mode"}) + + +@dataclass +class ChargemodeConfigSurplusVehicle: phase_switch_delay: int = field(default=7, metadata={ - "topic": "chargemode_config/pv_charging/phase_switch_delay"}) - bat_power_discharge: int = field(default=1500, metadata={ - "topic": "chargemode_config/pv_charging/bat_power_discharge"}) - bat_power_discharge_active: bool = field(default=False, metadata={ - "topic": "chargemode_config/pv_charging/bat_power_discharge_active"}) - min_bat_soc: int = field(default=50, metadata={ - "topic": "chargemode_config/pv_charging/min_bat_soc"}) - max_bat_soc: int = field(default=70, metadata={ - "topic": "chargemode_config/pv_charging/max_bat_soc"}) - bat_mode: BatConsiderationMode = field(default=BatConsiderationMode.EV_MODE.value, metadata={ - "topic": "chargemode_config/pv_charging/bat_mode"}) + "topic": "chargemode_config/surplus/vehicle/phase_switch_delay"}) retry_failed_phase_switches: bool = field( default=False, - metadata={"topic": "chargemode_config/pv_charging/retry_failed_phase_switches"}) + metadata={"topic": "chargemode_config/surplus/vehicle/retry_failed_phase_switches"}) switch_off_delay: int = field(default=60, metadata={ - "topic": "chargemode_config/pv_charging/switch_off_delay"}) + "topic": "chargemode_config/surplus/vehicle/switch_off_delay"}) switch_off_threshold: int = field(default=0, metadata={ - "topic": "chargemode_config/pv_charging/switch_off_threshold"}) + "topic": "chargemode_config/surplus/vehicle/switch_off_threshold"}) switch_on_delay: int = field(default=30, metadata={ - "topic": "chargemode_config/pv_charging/switch_on_delay"}) + "topic": "chargemode_config/surplus/vehicle/switch_on_delay"}) switch_on_threshold: int = field(default=1500, metadata={ - "topic": "chargemode_config/pv_charging/switch_on_threshold"}) + "topic": "chargemode_config/surplus/vehicle/switch_on_threshold"}) -def pv_charging_factory() -> PvCharging: - return PvCharging() +@dataclass +class ChargemodeConfigSurplus: + control_range: List = field(default_factory=control_range_factory, metadata={ + "topic": "chargemode_config/surplus/control_range"}) + feed_in_limit: bool = field(default=False, metadata={ + "topic": "chargemode_config/surplus/feed_in_limit"}) + feed_in_yield: int = field(default=15000, metadata={ + "topic": "chargemode_config/surplus/feed_in_yield"}) + vehicle: ChargemodeConfigSurplusVehicle = field( + default_factory=lambda: ChargemodeConfigSurplusVehicle()) @dataclass class ChargemodeConfig: - pv_charging: PvCharging = field(default_factory=pv_charging_factory) unbalanced_load_limit: int = field( default=18, metadata={"topic": "chargemode_config/unbalanced_load_limit"}) unbalanced_load: bool = field(default=False, metadata={ "topic": "chargemode_config/unbalanced_load"}) + surplus: ChargemodeConfigSurplus = field(default_factory=lambda: ChargemodeConfigSurplus()) + bat: ChargemodeConfigBat = field(default_factory=lambda: ChargemodeConfigBat()) def chargemode_config_factory() -> ChargemodeConfig: @@ -146,3 +155,10 @@ def grid_protection(self): self.data.grid_protection_random_stop = 0 except Exception: log.exception("Fehler im General-Modul") + + def get_feed_in_yield(self) -> int: + """ Liefert den aktuellen Feed-In-Ertrag in Watt zurück. """ + if self.data.chargemode_config.surplus.feed_in_limit: + return self.data.chargemode_config.surplus.feed_in_yield + else: + return 0 diff --git a/packages/control/loadmanagement.py b/packages/control/loadmanagement.py index ae12e06f3c..5a0f383b8e 100644 --- a/packages/control/loadmanagement.py +++ b/packages/control/loadmanagement.py @@ -17,8 +17,7 @@ class Loadmanagement: def get_available_currents(self, missing_currents: List[float], counter: Counter, - cp: Chargepoint, - feed_in: int = 0) -> Tuple[List[float], LoadmanagementLimit]: + cp: Chargepoint) -> Tuple[List[float], LoadmanagementLimit]: raw_currents_left = counter.data.set.raw_currents_left try: available_currents, limit = self._limit_by_dimming_via_direct_control(missing_currents, cp) @@ -36,7 +35,7 @@ def get_available_currents(self, limit = new_limit if new_limit.limiting_value is not None else limit available_currents, new_limit = self._limit_by_power( - counter, available_currents, voltages_mean(cp.data.get.voltages), counter.data.set.raw_power_left, feed_in) + counter, available_currents, voltages_mean(cp.data.get.voltages), counter.data.set.raw_power_left) limit = new_limit if new_limit.limiting_value is not None else limit if f"counter{counter.num}" == data.data.counter_all_data.get_evu_counter_str(): @@ -50,8 +49,7 @@ def get_available_currents_surplus(self, missing_currents: List[float], cp_voltage: float, counter: Counter, - cp: Chargepoint, - feed_in: int = 0) -> Tuple[List[float], LoadmanagementLimit]: + cp: Chargepoint) -> Tuple[List[float], LoadmanagementLimit]: raw_currents_left = counter.data.set.raw_currents_left available_currents, limit = self._limit_by_dimming_via_direct_control(missing_currents, cp) @@ -62,7 +60,7 @@ def get_available_currents_surplus(self, limit = new_limit if new_limit.limiting_value is not None else limit available_currents, new_limit = self._limit_by_power( - counter, available_currents, cp_voltage, counter.data.set.surplus_power_left, feed_in) + counter, available_currents, cp_voltage, counter.data.set.surplus_power_left) limit = new_limit if new_limit.limiting_value is not None else limit if f"counter{counter.num}" == data.data.counter_all_data.get_evu_counter_str(): @@ -96,8 +94,7 @@ def _limit_by_power(self, counter: Counter, available_currents: List[float], cp_voltage: float, - raw_power_left: Optional[float], - feed_in: Optional[float]) -> Tuple[List[float], LoadmanagementLimit]: + raw_power_left: Optional[float]) -> Tuple[List[float], LoadmanagementLimit]: # Mittelwert der Spannungen verwenden, um Phasenverdrehung zu kompensieren # (Probleme bei einphasig angeschlossenen Wallboxen) currents = available_currents.copy() @@ -105,8 +102,9 @@ def _limit_by_power(self, if raw_power_left is None: return currents, limit elif raw_power_left > 0: - if feed_in is not None: - raw_power_left = max(raw_power_left - feed_in, 0) + surplus_config = data.data.general_data.data.chargemode_config.surplus + if surplus_config.feed_in_limit: + raw_power_left = max(raw_power_left - surplus_config.feed_in_yield, 0) log.debug(f"Verbleibende Leistung unter Berücksichtigung der Einspeisegrenze: {raw_power_left}W") if sum([c * cp_voltage for c in available_currents]) > raw_power_left: for i in range(0, 3): diff --git a/packages/control/loadmanagement_test.py b/packages/control/loadmanagement_test.py index 48de9d41e9..9c75fae169 100644 --- a/packages/control/loadmanagement_test.py +++ b/packages/control/loadmanagement_test.py @@ -33,7 +33,7 @@ def test_limit_by_power(available_currents: List[float], counter_name_mock = Mock(return_value=COUNTER_NAME) monkeypatch.setattr(loadmanagement, "get_component_name_by_id", counter_name_mock) # evaluation - ret = Loadmanagement()._limit_by_power(Counter(0), available_currents, 230, raw_power_left, None) + ret = Loadmanagement()._limit_by_power(Counter(0), available_currents, 230, raw_power_left) # assertion assert ret == expected_ret diff --git a/packages/helpermodules/create_debug.py b/packages/helpermodules/create_debug.py index cb032927a5..d835225a62 100644 --- a/packages/helpermodules/create_debug.py +++ b/packages/helpermodules/create_debug.py @@ -35,8 +35,8 @@ def get_common_data(): ip_address = None try: updateAvailable = subdata.SubData.system_data["system"].data["current_branch_commit"] and \ - subdata.SubData.system_data["system"].data["current_branch_commit"] != \ - subdata.SubData.system_data["system"].data["current_commit"] + subdata.SubData.system_data["system"].data["current_branch_commit"] != \ + subdata.SubData.system_data["system"].data["current_commit"] except Exception: updateAvailable = False @@ -113,20 +113,20 @@ def config_and_state(): chargemode_config = data.data.general_data.data.chargemode_config parsed_data += ( "\n## General Charge Config/ PV ##\n" - f"Phase_Switch_Delay: {chargemode_config.pv_charging.phase_switch_delay} min\n" - f"Retry_Failed_Phase_Switches: {chargemode_config.pv_charging.retry_failed_phase_switches}\n" - f"Control_Range: {chargemode_config.pv_charging.control_range}W\n" - f"Switch_On_Threshold: {chargemode_config.pv_charging.switch_on_threshold}W\n" - f"Switch_On_Delay: {chargemode_config.pv_charging.switch_on_delay}s\n" - f"Switch_Off_Threshold: {chargemode_config.pv_charging.switch_off_threshold}W\n" - f"Switch_Off_Delay: {chargemode_config.pv_charging.switch_off_delay}s\n" - f"Feed_In_Yield: {chargemode_config.pv_charging.feed_in_yield}W\n" - f"Bat_Mode: {chargemode_config.pv_charging.bat_mode}\n" - f"Min_Bat_SoC: {chargemode_config.pv_charging.min_bat_soc}%\n" - f"Bat_Power_Reserve_Active: {chargemode_config.pv_charging.bat_power_reserve_active}\n" - f"Bat_Power_Reserve: {chargemode_config.pv_charging.bat_power_reserve}W\n" - f"Bat_Power_Discharge_Active: {chargemode_config.pv_charging.bat_power_discharge_active}\n" - f"Bat_Power_Discharge: {chargemode_config.pv_charging.bat_power_discharge}W\n") + f"Phase_Switch_Delay: {chargemode_config.surplus.vehicle.phase_switch_delay} min\n" + f"Retry_Failed_Phase_Switches: {chargemode_config.surplus.vehicle.retry_failed_phase_switches}\n" + f"Control_Range: {chargemode_config.surplus.control_range}W\n" + f"Switch_On_Threshold: {chargemode_config.surplus.vehicle.switch_on_threshold}W\n" + f"Switch_On_Delay: {chargemode_config.surplus.vehicle.switch_on_delay}s\n" + f"Switch_Off_Threshold: {chargemode_config.surplus.vehicle.switch_off_threshold}W\n" + f"Switch_Off_Delay: {chargemode_config.surplus.vehicle.switch_off_delay}s\n" + f"Feed_In_Yield: {chargemode_config.surplus.feed_in_yield}W\n" + f"Bat_Mode: {chargemode_config.bat.mode}\n" + f"Min_Bat_SoC: {chargemode_config.bat.min_soc}%\n" + f"Bat_Power_Reserve_Active: {chargemode_config.bat.power_reserve_active}\n" + f"Bat_Power_Reserve: {chargemode_config.bat.power_reserve}W\n" + f"Bat_Power_Discharge_Active: {chargemode_config.bat.power_discharge_active}\n" + f"Bat_Power_Discharge: {chargemode_config.bat.power_discharge}W\n") if secondary is False: with ErrorHandlingContext(): parsed_data += f"\n## Hierarchy ##\n{get_hierarchy(data.data.counter_all_data.data.get.hierarchy)}\n" @@ -461,9 +461,9 @@ def write_to_file(file_handler, func, default: Optional[Any] = None): json_rsp = req.get_http_session().put("https://debughandler.wb-solution.de", data=data, params={ - 'debugemail': debug_email, - 'ticketnumber': ticketnumber, - 'subject': subject + 'debugemail': debug_email, + 'ticketnumber': ticketnumber, + 'subject': subject }, timeout=10).json() diff --git a/packages/helpermodules/setdata.py b/packages/helpermodules/setdata.py index 7973936181..bdb7ef2ee7 100644 --- a/packages/helpermodules/setdata.py +++ b/packages/helpermodules/setdata.py @@ -763,28 +763,29 @@ def process_general_topic(self, msg: mqtt.MQTTMessage): elif "openWB/set/general/chargemode_config/unbalanced_load_limit" in msg.topic: self._validate_value(msg, int, [(10, 32)]) elif ("openWB/set/general/chargemode_config/unbalanced_load" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/retry_failed_phase_switches" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/bat_power_discharge_active" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/bat_power_reserve_active" in msg.topic): + "openWB/set/general/chargemode_config/surplus/feed_in_limit" in msg.topic or + "openWB/set/general/chargemode_config/surplus/vehicle/retry_failed_phase_switches" in msg.topic or + "openWB/set/general/chargemode_config/bat/power_discharge_active" in msg.topic or + "openWB/set/general/chargemode_config/bat/power_reserve_active" in msg.topic): self._validate_value(msg, bool) - elif ("openWB/set/general/chargemode_config/pv_charging/feed_in_yield" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/switch_on_threshold" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/switch_on_delay" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/switch_off_delay" in msg.topic): + elif ("openWB/set/general/chargemode_config/surplus/feed_in_yield" in msg.topic or + "openWB/set/general/chargemode_config/surplus/vehicle/switch_on_threshold" in msg.topic or + "openWB/set/general/chargemode_config/surplus/vehicle/switch_on_delay" in msg.topic or + "openWB/set/general/chargemode_config/surplus/vehicle/switch_off_delay" in msg.topic): self._validate_value(msg, int, [(0, float("inf"))]) - elif "openWB/set/general/chargemode_config/pv_charging/switch_off_threshold" in msg.topic: + elif "openWB/set/general/chargemode_config/surplus/vehicle/switch_off_threshold" in msg.topic: self._validate_value(msg, float) - elif "openWB/set/general/chargemode_config/pv_charging/phase_switch_delay" in msg.topic: + elif "openWB/set/general/chargemode_config/surplus/vehicle/phase_switch_delay" in msg.topic: self._validate_value(msg, int, [(5, 180)]) - elif "openWB/set/general/chargemode_config/pv_charging/control_range" in msg.topic: + elif "openWB/set/general/chargemode_config/surplus/control_range" in msg.topic: self._validate_value(msg, int, collection=list) - elif ("openWB/set/general/chargemode_config/pv_charging/min_bat_soc" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/max_bat_soc" in msg.topic): + elif ("openWB/set/general/chargemode_config/bat/min_soc" in msg.topic or + "openWB/set/general/chargemode_config/bat/max_soc" in msg.topic): self._validate_value(msg, int, [(0, 100)]) - elif ("openWB/set/general/chargemode_config/pv_charging/bat_power_discharge" in msg.topic or - "openWB/set/general/chargemode_config/pv_charging/bat_power_reserve" in msg.topic): + elif ("openWB/set/general/chargemode_config/bat/power_discharge" in msg.topic or + "openWB/set/general/chargemode_config/bat/power_reserve" in msg.topic): self._validate_value(msg, float, [(0, float("inf"))]) - elif "openWB/set/general/chargemode_config/pv_charging/bat_mode" in msg.topic: + elif "openWB/set/general/chargemode_config/bat/mode" in msg.topic: self._validate_value(msg, str) elif "openWB/set/general/chargemode_config/" in msg.topic and "/phases_to_use" in msg.topic: self._validate_value(msg, int, [(1, 1), (3, 3)]) diff --git a/packages/helpermodules/update_config.py b/packages/helpermodules/update_config.py index 48d2f72b1e..337e9681a0 100644 --- a/packages/helpermodules/update_config.py +++ b/packages/helpermodules/update_config.py @@ -41,7 +41,7 @@ from control.ev.charge_template import EcoCharging, get_charge_template_default from control.ev import ev from control.ev.ev_template import EvTemplateData -from control.general import Prices, PvCharging +from control.general import ChargemodeConfigSurplusVehicle, Prices from control.optional_data import OcppConfig from modules.common.abstract_vehicle import GeneralVehicleConfig from modules.common.component_type import ComponentType @@ -229,21 +229,22 @@ class UpdateConfig: "^openWB/general/temporary_charge_templates_active$", "^openWB/general/chargemode_config/unbalanced_load_limit$", "^openWB/general/chargemode_config/unbalanced_load$", - "^openWB/general/chargemode_config/pv_charging/bat_mode$", - "^openWB/general/chargemode_config/pv_charging/feed_in_yield$", - "^openWB/general/chargemode_config/pv_charging/switch_on_threshold$", - "^openWB/general/chargemode_config/pv_charging/switch_on_delay$", - "^openWB/general/chargemode_config/pv_charging/switch_off_threshold$", - "^openWB/general/chargemode_config/pv_charging/switch_off_delay$", - "^openWB/general/chargemode_config/pv_charging/phase_switch_delay$", - "^openWB/general/chargemode_config/pv_charging/control_range$", - "^openWB/general/chargemode_config/pv_charging/min_bat_soc$", - "^openWB/general/chargemode_config/pv_charging/max_bat_soc$", - "^openWB/general/chargemode_config/pv_charging/bat_power_discharge$", - "^openWB/general/chargemode_config/pv_charging/bat_power_discharge_active$", - "^openWB/general/chargemode_config/pv_charging/bat_power_reserve$", - "^openWB/general/chargemode_config/pv_charging/bat_power_reserve_active$", - "^openWB/general/chargemode_config/pv_charging/retry_failed_phase_switches$", + "^openWB/general/chargemode_config/surplus/feed_in_limit$", + "^openWB/general/chargemode_config/bat/mode$", + "^openWB/general/chargemode_config/surplus/feed_in_yield$", + "^openWB/general/chargemode_config/surplus/vehicle/switch_on_threshold$", + "^openWB/general/chargemode_config/surplus/vehicle/switch_on_delay$", + "^openWB/general/chargemode_config/surplus/vehicle/switch_off_threshold$", + "^openWB/general/chargemode_config/surplus/vehicle/switch_off_delay$", + "^openWB/general/chargemode_config/surplus/vehicle/phase_switch_delay$", + "^openWB/general/chargemode_config/surplus/control_range$", + "^openWB/general/chargemode_config/bat/min_soc$", + "^openWB/general/chargemode_config/bat/max_soc$", + "^openWB/general/chargemode_config/bat/power_discharge$", + "^openWB/general/chargemode_config/bat/power_discharge_active$", + "^openWB/general/chargemode_config/bat/power_reserve$", + "^openWB/general/chargemode_config/bat/power_reserve_active$", + "^openWB/general/chargemode_config/surplus/vehicle/retry_failed_phase_switches$", # obsolet, Daten hieraus müssen nach prices/ überführt werden "^openWB/general/price_kwh$", "^openWB/general/prices/bat$", @@ -603,22 +604,23 @@ class UpdateConfig: ("openWB/vehicle/template/charge_template/0", get_charge_template_default()), ("openWB/general/allow_unencrypted_access", True), ("openWB/general/charge_log_data_config", get_default_charge_log_columns()), - ("openWB/general/chargemode_config/pv_charging/bat_mode", BatConsiderationMode.EV_MODE.value), - ("openWB/general/chargemode_config/pv_charging/bat_power_discharge", 1000), - ("openWB/general/chargemode_config/pv_charging/bat_power_discharge_active", True), - ("openWB/general/chargemode_config/pv_charging/min_bat_soc", 50), - ("openWB/general/chargemode_config/pv_charging/max_bat_soc", 70), - ("openWB/general/chargemode_config/pv_charging/bat_power_reserve", 200), - ("openWB/general/chargemode_config/pv_charging/bat_power_reserve_active", True), - ("openWB/general/chargemode_config/pv_charging/control_range", [0, 230]), - ("openWB/general/chargemode_config/pv_charging/switch_off_threshold", 0), - ("openWB/general/chargemode_config/pv_charging/switch_off_delay", 60), - ("openWB/general/chargemode_config/pv_charging/switch_on_delay", 30), - ("openWB/general/chargemode_config/pv_charging/switch_on_threshold", 1500), - ("openWB/general/chargemode_config/pv_charging/feed_in_yield", 0), - ("openWB/general/chargemode_config/pv_charging/phase_switch_delay", 7), - ("openWB/general/chargemode_config/pv_charging/retry_failed_phase_switches", - PvCharging().retry_failed_phase_switches), + ("openWB/general/chargemode_config/bat/mode", BatConsiderationMode.EV_MODE.value), + ("openWB/general/chargemode_config/bat/power_discharge", 1000), + ("openWB/general/chargemode_config/bat/power_discharge_active", True), + ("openWB/general/chargemode_config/bat/min_soc", 50), + ("openWB/general/chargemode_config/bat/max_soc", 70), + ("openWB/general/chargemode_config/bat/power_reserve", 200), + ("openWB/general/chargemode_config/bat/power_reserve_active", True), + ("openWB/general/chargemode_config/surplus/control_range", [0, 230]), + ("openWB/general/chargemode_config/surplus/feed_in_limit", False), + ("openWB/general/chargemode_config/surplus/vehicle/switch_off_threshold", 0), + ("openWB/general/chargemode_config/surplus/vehicle/switch_off_delay", 60), + ("openWB/general/chargemode_config/surplus/vehicle/switch_on_delay", 30), + ("openWB/general/chargemode_config/surplus/vehicle/switch_on_threshold", 1500), + ("openWB/general/chargemode_config/surplus/feed_in_yield", 0), + ("openWB/general/chargemode_config/surplus/vehicle/phase_switch_delay", 7), + ("openWB/general/chargemode_config/surplus/vehicle/retry_failed_phase_switches", + ChargemodeConfigSurplusVehicle().retry_failed_phase_switches), ("openWB/general/chargemode_config/unbalanced_load", False), ("openWB/general/chargemode_config/unbalanced_load_limit", 18), ("openWB/general/control_interval", 10), diff --git a/packages/modules/display_themes/cards/source/src/App.vue b/packages/modules/display_themes/cards/source/src/App.vue index 6058e5320e..4c315126f4 100644 --- a/packages/modules/display_themes/cards/source/src/App.vue +++ b/packages/modules/display_themes/cards/source/src/App.vue @@ -63,7 +63,7 @@ export default { "openWB/counter/+/get/power", "openWB/counter/get/hierarchy", "openWB/counter/set/home_consumption", - "openWB/general/chargemode_config/pv_charging/bat_mode", + "openWB/general/chargemode_config/bat/mode", "openWB/optional/ep/configured", "openWB/optional/ep/get/prices", "openWB/optional/int_display/only_local_charge_points", diff --git a/packages/modules/display_themes/cards/source/src/components/Battery/BatteryModeModal.vue b/packages/modules/display_themes/cards/source/src/components/Battery/BatteryModeModal.vue index ac813fe499..5c99374478 100644 --- a/packages/modules/display_themes/cards/source/src/components/Battery/BatteryModeModal.vue +++ b/packages/modules/display_themes/cards/source/src/components/Battery/BatteryModeModal.vue @@ -99,8 +99,8 @@ export default { methods: { setBatteryMode(mode) { if(mode !== this.mqttStore.getBatteryMode) { - this.mqttStore.updateState("openWB/general/chargemode_config/pv_charging/bat_mode", mode); - this.$root.sendTopicToBroker("openWB/general/chargemode_config/pv_charging/bat_mode", mode); + this.mqttStore.updateState("openWB/general/chargemode_config/bat/mode", mode); + this.$root.sendTopicToBroker("openWB/general/chargemode_config/bat/mode", mode); } }, }, diff --git a/packages/modules/display_themes/cards/source/src/stores/mqtt.js b/packages/modules/display_themes/cards/source/src/stores/mqtt.js index aa4c0218ba..8bbc97166c 100644 --- a/packages/modules/display_themes/cards/source/src/stores/mqtt.js +++ b/packages/modules/display_themes/cards/source/src/stores/mqtt.js @@ -397,7 +397,7 @@ export const useMqttStore = defineStore("mqtt", { return state.getChartData("openWB/bat/get/soc"); }, getBatteryMode(state) { - return state.topics["openWB/general/chargemode_config/pv_charging/bat_mode"]; + return state.topics["openWB/general/chargemode_config/bat/mode"]; }, getPvConfigured(state) { return state.getValueBool("openWB/pv/config/configured"); @@ -776,16 +776,6 @@ export const useMqttStore = defineStore("mqtt", { return undefined; }; }, - getChargePointConnectedVehiclePvChargingFeedInLimit(state) { - return (chargePointId) => { - if (state.getChargePointConnectedVehicleChargeTemplate(chargePointId)) { - return state.getChargePointConnectedVehicleChargeTemplate( - chargePointId, - ).chargemode.pv_charging.feed_in_limit; - } - return undefined; - }; - }, getChargePointConnectedVehiclePvChargingMinCurrent(state) { return (chargePointId) => { if (state.getChargePointConnectedVehicleChargeTemplate(chargePointId)) { diff --git a/packages/modules/display_themes/cards/source/src/views/ChargePointsView.vue b/packages/modules/display_themes/cards/source/src/views/ChargePointsView.vue index dffaf783bd..2ba286e972 100644 --- a/packages/modules/display_themes/cards/source/src/views/ChargePointsView.vue +++ b/packages/modules/display_themes/cards/source/src/views/ChargePointsView.vue @@ -217,14 +217,6 @@ export default { this.updateChargePointChargeTemplate(id, event, "chargemode.instant_charging.limit.amount"); } }, - setChargePointConnectedVehiclePvChargingFeedInLimit(id, event) { - if ( - event != - this.mqttStore.getChargePointConnectedVehiclePvChargingFeedInLimit(id) - ) { - this.updateChargePointChargeTemplate(id, event, "chargemode.pv_charging.feed_in_limit"); - } - }, setChargePointConnectedVehiclePvChargingMinCurrent(id, event) { let previous_value = this.mqttStore.getChargePointConnectedVehiclePvChargingMinCurrent(id); @@ -1026,45 +1018,6 @@ export default { - - Einspeisegrenze beachten - - - Nein - - - Ja - - - - - - diff --git a/packages/modules/display_themes/colors/source/src/components/chargePointList/model.ts b/packages/modules/display_themes/colors/source/src/components/chargePointList/model.ts index 710d180a37..8eea21a9c2 100755 --- a/packages/modules/display_themes/colors/source/src/components/chargePointList/model.ts +++ b/packages/modules/display_themes/colors/source/src/components/chargePointList/model.ts @@ -156,15 +156,6 @@ export class ChargePoint { updateChargeTemplate(this.id) } } - get pvFeedInLimit() { - return this.chargeTemplate?.chargemode.pv_charging.feed_in_limit ?? false - } - set pvFeedInLimit(setting: boolean) { - if (this.chargeTemplate) { - this.chargeTemplate.chargemode.pv_charging.feed_in_limit = setting - updateChargeTemplate(this.id) - } - } get pvMinCurrent() { return this.chargeTemplate?.chargemode.pv_charging.min_current ?? 0 } @@ -448,7 +439,6 @@ export interface ChargeTemplate { pv_charging: { dc_min_current: number dc_min_soc_current: number - feed_in_limit: boolean limit: { selected: string amount: number diff --git a/packages/modules/web_themes/colors/source/src/components/chargePointList/cpConfig/ConfigPv.vue b/packages/modules/web_themes/colors/source/src/components/chargePointList/cpConfig/ConfigPv.vue index dfdbb43f8d..d820678972 100755 --- a/packages/modules/web_themes/colors/source/src/components/chargePointList/cpConfig/ConfigPv.vue +++ b/packages/modules/web_themes/colors/source/src/components/chargePointList/cpConfig/ConfigPv.vue @@ -130,15 +130,6 @@ unit="kWh" /> - - - diff --git a/packages/modules/web_themes/colors/source/src/components/chargePointList/model.ts b/packages/modules/web_themes/colors/source/src/components/chargePointList/model.ts index e3291f7b61..0ee9fc4a54 100755 --- a/packages/modules/web_themes/colors/source/src/components/chargePointList/model.ts +++ b/packages/modules/web_themes/colors/source/src/components/chargePointList/model.ts @@ -71,7 +71,6 @@ export class ChargePoint implements PowerItem { private _instantTargetSoc = 0 private _instantMaxEnergy = 0 private _instantTargetPhases = 0 - private _pvFeedInLimit = false private _pvMinCurrent = 0 private _pvMaxSoc = 0 private _pvMinSoc = 0 @@ -206,15 +205,6 @@ export class ChargePoint implements PowerItem { updateChargeTemplate(this.id) } } - get pvFeedInLimit() { - return this.chargeTemplate?.chargemode.pv_charging.feed_in_limit ?? false - } - set pvFeedInLimit(setting: boolean) { - if (this.chargeTemplate) { - this.chargeTemplate.chargemode.pv_charging.feed_in_limit = setting - updateChargeTemplate(this.id) - } - } get pvMinCurrent() { return this.chargeTemplate?.chargemode.pv_charging.min_current ?? 0 } @@ -504,7 +494,6 @@ export interface ChargeTemplate { pv_charging: { dc_min_current: number dc_min_soc_current: number - feed_in_limit: boolean limit: ChargeLimit min_current: number min_soc_current: number diff --git a/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue b/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue index fb1bcb4464..fea8e97903 100644 --- a/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue +++ b/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue @@ -169,7 +169,5 @@ const pvMinSocCurrent = computed(() => ), ); -const feedInLimit = computed(() => - mqttStore.chargePointConnectedVehiclePvChargeFeedInLimit(props.chargePointId), -); + diff --git a/packages/modules/web_themes/koala/source/src/stores/mqtt-store-model.ts b/packages/modules/web_themes/koala/source/src/stores/mqtt-store-model.ts index 3810f16ccb..4c4df71bdb 100644 --- a/packages/modules/web_themes/koala/source/src/stores/mqtt-store-model.ts +++ b/packages/modules/web_themes/koala/source/src/stores/mqtt-store-model.ts @@ -84,7 +84,6 @@ export interface ChargeTemplateConfiguration { pv_charging: { dc_min_current: number; dc_min_soc_current: number; - feed_in_limit: boolean; limit: { selected: string; amount: number; diff --git a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts index 6d1bd0cfb3..f1b3d20f30 100644 --- a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts +++ b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts @@ -1799,30 +1799,6 @@ export const useMqttStore = defineStore('mqtt', () => { }); }; - /** - * Get or set the charge point connected vehicle pv feed in limit active identified by the charge point id - * @param chargePointId charge point id - * @returns object | undefined - */ - const chargePointConnectedVehiclePvChargeFeedInLimit = ( - chargePointId: number, - ) => { - return computed({ - get() { - return chargePointConnectedVehicleChargeTemplate(chargePointId).value - ?.chargemode?.pv_charging?.feed_in_limit; - }, - set(newValue: boolean) { - console.debug('set pv feed in limit active', newValue, chargePointId); - return updateTopic( - `openWB/chargepoint/${chargePointId}/set/charge_template`, - newValue, - 'chargemode.pv_charging.feed_in_limit', - true, - ); - }, - }); - }; /** * Get or set the charge point connected vehicle eco charging current identified by the charge point id @@ -1961,10 +1937,10 @@ export const useMqttStore = defineStore('mqtt', () => { const batteryChargePriorityRange = computed({ get() { const minSoc = getValue.value( - 'openWB/general/chargemode_config/pv_charging/min_bat_soc', + 'openWB/general/chargemode_config/bat/min_soc', ) as number | undefined; const maxSoc = getValue.value( - 'openWB/general/chargemode_config/pv_charging/max_bat_soc', + 'openWB/general/chargemode_config/bat/max_soc', ) as number | undefined; return { min: minSoc ?? 0, @@ -1973,13 +1949,13 @@ export const useMqttStore = defineStore('mqtt', () => { }, set(newRange: RangeValue) { updateTopic( - 'openWB/general/chargemode_config/pv_charging/min_bat_soc', + 'openWB/general/chargemode_config/bat/min_soc newRange.min, undefined, true, ); updateTopic( - 'openWB/general/chargemode_config/pv_charging/max_bat_soc', + 'openWB/general/chargemode_config/bat/max_soc', newRange.max, undefined, true, @@ -2891,13 +2867,13 @@ export const useMqttStore = defineStore('mqtt', () => { get() { return ( (getValue.value( - 'openWB/general/chargemode_config/pv_charging/bat_mode', + 'openWB/general/chargemode_config/bat/mode', ) as string) || undefined ); }, set(newValue: string) { return updateTopic( - 'openWB/general/chargemode_config/pv_charging/bat_mode', + 'openWB/general/chargemode_config/bat/mode', newValue, undefined, true, @@ -4200,7 +4176,6 @@ export const useMqttStore = defineStore('mqtt', () => { chargePointConnectedVehiclePvDcChargePower, chargePointConnectedVehiclePvDcMinSocPower, chargePointConnectedVehiclePvChargePhasesMinSoc, - chargePointConnectedVehiclePvChargeFeedInLimit, chargePointConnectedVehicleEcoChargeCurrent, chargePointConnectedVehicleEcoChargeDcPower, chargePointConnectedVehicleEcoChargePhases, diff --git a/packages/modules/web_themes/standard_legacy/web/index.html b/packages/modules/web_themes/standard_legacy/web/index.html index 1cd5f60f8b..1e55b30ab7 100644 --- a/packages/modules/web_themes/standard_legacy/web/index.html +++ b/packages/modules/web_themes/standard_legacy/web/index.html @@ -161,7 +161,7 @@
+ data-topic="openWB/set/general/chargemode_config/bat/mode"> @@ -957,20 +957,6 @@

Einstellungen für "PV"

-
-
- Einspeisegrenze beachten -
-
- -
-
diff --git a/packages/modules/web_themes/standard_legacy/web/processAllMqttMsg.js b/packages/modules/web_themes/standard_legacy/web/processAllMqttMsg.js index d356efa16e..971ba03a0d 100644 --- a/packages/modules/web_themes/standard_legacy/web/processAllMqttMsg.js +++ b/packages/modules/web_themes/standard_legacy/web/processAllMqttMsg.js @@ -218,15 +218,6 @@ function refreshChargeTemplate(chargePointIndex) { // chargemode.pv_charging.limit.amount element = chargePoint.find('.charge-point-pv-charge-limit-amount'); setInputValue(element.attr('id'), chargeTemplate[chargePointIndex].chargemode.pv_charging.limit.amount); - // chargemode.pv_charging.feed_in_limit - var element = chargePoint.find('.charge-point-pv-charge-feed-in-limit'); // now get parents respective child element - if (chargeTemplate[chargePointIndex].chargemode.pv_charging.feed_in_limit == true) { - // element.prop('checked', true); - element.bootstrapToggle('on', true); // do not fire a changed-event to prevent a loop! - } else { - // element.prop('checked', false); - element.bootstrapToggle('off', true); // do not fire a changed-event to prevent a loop! - } // ***** eco_charging ***** // chargemode.eco_charging.X @@ -793,7 +784,7 @@ function processPvMessages(mqttTopic, mqttPayload) { } function processPvConfigMessages(mqttTopic, mqttPayload) { - if (mqttTopic == 'openWB/general/chargemode_config/pv_charging/bat_mode') { + if (mqttTopic == 'openWB/general/chargemode_config/bat/mode') { data = JSON.parse(mqttPayload); var element = $('.bat-consideration-mode input[type=radio][data-option="' + data + '"]'); element.prop('checked', true); // check selected battery mode radio button diff --git a/packages/modules/web_themes/standard_legacy/web/setupMqttServices.js b/packages/modules/web_themes/standard_legacy/web/setupMqttServices.js index 637c6783b8..b29c14da94 100644 --- a/packages/modules/web_themes/standard_legacy/web/setupMqttServices.js +++ b/packages/modules/web_themes/standard_legacy/web/setupMqttServices.js @@ -73,7 +73,7 @@ var topicsToSubscribe = [ // charge mode config - ["openWB/general/chargemode_config/pv_charging/bat_mode", 0], + ["openWB/general/chargemode_config/bat/mode", 0], // electricity tariff ["openWB/optional/ep/configured", 1], // ep provider information diff --git a/simpleAPI/simpleAPI_mqtt.py b/simpleAPI/simpleAPI_mqtt.py index ce394f75fd..fab4c55b6f 100755 --- a/simpleAPI/simpleAPI_mqtt.py +++ b/simpleAPI/simpleAPI_mqtt.py @@ -826,7 +826,7 @@ def _handle_bat_mode_operation(self, payload: str) -> bool: log.error(f"Invalid bat_mode: {payload}. Valid values: {valid_modes}") return False - target_topic = "openWB/set/general/chargemode_config/pv_charging/bat_mode" + target_topic = "openWB/set/general/chargemode_config/bat/mode" self.client.publish(target_topic, payload, qos=0, retain=True) log.info(f"Set bat_mode to {payload}") return True diff --git a/simpleAPI/src/ParameterHandler.php b/simpleAPI/src/ParameterHandler.php index 1967fb8340..d564aa76b9 100644 --- a/simpleAPI/src/ParameterHandler.php +++ b/simpleAPI/src/ParameterHandler.php @@ -1590,7 +1590,7 @@ private function setBatMode($value) } try { - $topic = "openWB/set/general/chargemode_config/pv_charging/bat_mode"; + $topic = "openWB/set/general/chargemode_config/bat/mode"; if ($this->mqttClient->setValue($topic, $value)) { return ['success' => true, 'message' => "Bat mode set to {$value}"]; From 91f9e68718eb682d4b9b664125a8fe467870d8f5 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 5 Aug 2026 09:55:14 +0200 Subject: [PATCH 2/6] fix --- .../modules/web_themes/koala/source/src/stores/mqtt-store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts index f1b3d20f30..8f98b33da0 100644 --- a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts +++ b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts @@ -1949,7 +1949,7 @@ export const useMqttStore = defineStore('mqtt', () => { }, set(newRange: RangeValue) { updateTopic( - 'openWB/general/chargemode_config/bat/min_soc + 'openWB/general/chargemode_config/bat/min_soc', newRange.min, undefined, true, From 563cb251ed88e2f688b04a693b4d565625eba939 Mon Sep 17 00:00:00 2001 From: LKuemmel Date: Wed, 5 Aug 2026 09:58:28 +0200 Subject: [PATCH 3/6] fix --- .../source/src/components/ChargePointPvSettings.vue | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue b/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue index fea8e97903..bb48bb4b3e 100644 --- a/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue +++ b/packages/modules/web_themes/koala/source/src/components/ChargePointPvSettings.vue @@ -91,21 +91,11 @@
- -
-
Einspeisegrenze beachten
-
- -
-