From 36fc0223f51b6e0d81c857d78e13b6847e18bf90 Mon Sep 17 00:00:00 2001 From: vuffiraa72 Date: Fri, 2 Feb 2024 11:19:00 +0100 Subject: [PATCH 1/5] test calculation of current --- packages/control/algorithm/algorithm_test.py | 80 ++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 packages/control/algorithm/algorithm_test.py diff --git a/packages/control/algorithm/algorithm_test.py b/packages/control/algorithm/algorithm_test.py new file mode 100644 index 0000000000..516563d408 --- /dev/null +++ b/packages/control/algorithm/algorithm_test.py @@ -0,0 +1,80 @@ +from unittest.mock import Mock +import pytest + +from control import data +from control.algorithm.algorithm import Algorithm +from control.chargemode import Chargemode +from control.chargepoint.chargepoint import Chargepoint +from control.chargepoint.chargepoint_state import ChargepointState +from control.counter import Counter +from control.general import General + + +@pytest.fixture(autouse=True) +def data_fixture() -> None: + data.data_init(Mock()) + data.data.general_data = General() + data.data.cp_data = {"cp2": Chargepoint(2, None)} + data.data.counter_data = {"counter0": Counter(0)} + data.data.counter_all_data.data.get.hierarchy = [ + {"id": 0, + "type": "counter", + "children": [ + {"id": 1, + "type": "inverter", + "children": []}, + {"id": 2, + "type": "cp", + "children": []}]}] + + +@pytest.mark.parametrize("control_range, evu_power, evu_currents, evu_voltages, cp_power, cp_currents", + [pytest.param([-230, 0], -84.08, [-2.42, 4.69, -2.66], [239, 237.8, 237.6], 1823.86, [7.81, -0.06, 0.06], id="Einspeisung, im Regelbereich"), + pytest.param([-230, 0], 41.96, [-2.4, 5.22, -2.64], [238.7, 237.7, 237.7], 1939.72, [8.31, -0.06, 0.06], id="Einspeisung, über Regelbereich"), + pytest.param([-230, 0], -690, [-1, -1, -1], [230, 230, 230], 1610, [7, 0, 0], id="Einspeisung bei 230V Spannung, unter Regelbereich"), + pytest.param([-230, 0], -115, [0, -0.5, 0], [230, 230, 230], 2185, [9.5, 0, 0], id="Einspeisung bei 230V Spannung, im Regelbereich"), + pytest.param([-230, 0], -115, [0, -0.49, 0], [235, 235, 235], 2185, [9.3, 0, 0], id="Einspeisung bei 235V Spannung, im Regelbereich"), + pytest.param([-230, 0], 235, [0, 1, 0], [235, 235, 235], 2535, [10.87, 0, 0], id="Einspeisung bei 235V Spannung, über Regelbereich"), + pytest.param([0, 230], -230, [0, -1, 0], [230, 230, 230], 2070, [9, 0, 0], id="Bezug bei 230V Spannung, unter Regelbereich"), + pytest.param([0, 230], 115, [0, 0.5, 0], [230, 230, 230], 2415, [10.5, 0, 0], id="Bezug bei 230V Spannung, im Regelbereich"), + pytest.param([0, 230], 115, [0, 0.49, 0], [235, 235, 235], 2415, [10.3, 0, 0], id="Bezug bei 235V Spannung, im Regelbereich"), + pytest.param([0, 230], 705, [1, 1, 1], [235, 235, 235], 3005, [12.8, 0, 0], id="Bezug bei 235V Spannung, über Regelbereich"), + pytest.param([-115, 115], -230, [0, -1, 0], [230, 230, 230], 2070, [9, 0, 0], id="Ausgeglichen bei 230V Spannung, unter Regelbereich"), + pytest.param([-115, 115], 0, [0, 0, 0], [230, 230, 230], 2300, [10, 0, 0], id="Ausgeglichen bei 230V Spannung, im Regelbereich"), + pytest.param([-115, 115], 0, [0, 0, 0], [235, 235, 235], 2300, [9.8, 0, 0], id="Ausgeglichen bei 235V Spannung, im Regelbereich"), + pytest.param([-115, 115], 235, [0, 1, 0], [235, 235, 235], 2535, [10.8, 0, 0], id="Ausgeglichen bei 235V Spannung, über Regelbereich") + ] + ) +def test_calc_current(control_range, evu_power, evu_currents, evu_voltages, cp_power, cp_currents, monkeypatch): + # setup + data.data.general_data.data.chargemode_config.pv_charging.control_range = control_range + cp = data.data.cp_data["cp2"] + cp.data.config.phase_1 = 2 + cp.data.control_parameter.state = ChargepointState.CHARGING_ALLOWED + cp.data.control_parameter.chargemode = Chargemode.PV_CHARGING + cp.data.control_parameter.submode = Chargemode.PV_CHARGING + cp.data.control_parameter.phases = 1 + cp.data.control_parameter.required_current = 6 + cp.data.control_parameter.required_currents = [0, 6, 0] + cp.data.set.charging_ev = 0 + cp.data.get.currents = cp_currents + cp.data.get.power = cp_power + counter = data.data.counter_data["counter0"] + counter.data.config.max_currents = [35, 35, 35] + counter.data.config.max_total_power = 24000 + counter.data.get.currents = evu_currents + counter.data.get.voltages = evu_voltages + counter.data.get.power = evu_power + counter._set_power_left() + counter._set_current_left() + a = Algorithm() + + # execution + a.calc_current() + + # evaluation + average_voltage = sum(cp.data.get.voltages)/len(cp.data.get.voltages) + initial_power_left = cp.data.get.power - counter.data.get.power + new_power = cp.data.set.current * average_voltage + # calculated surplus is in control range + assert control_range[0] < int(new_power - initial_power_left) < control_range[1] From 7262fe415366389056ce1f8bb95b6a09ef3ae7b5 Mon Sep 17 00:00:00 2001 From: vuffiraa72 Date: Fri, 2 Feb 2024 11:24:38 +0100 Subject: [PATCH 2/5] respect actual voltages while calulating surplus --- packages/control/counter.py | 6 ++++-- packages/control/loadmanagement.py | 11 +++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/control/counter.py b/packages/control/counter.py index 1888291418..6d6df59730 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -172,14 +172,16 @@ def _set_power_left(self) -> None: def update_values_left(self, diffs) -> None: self.data.set.raw_currents_left = list(map(operator.sub, self.data.set.raw_currents_left, diffs)) if self.data.set.raw_power_left: - self.data.set.raw_power_left -= sum(diffs) * 230 + average_voltage = sum(self.data.get.voltages)/len(self.data.get.voltages) + self.data.set.raw_power_left -= sum(diffs) * average_voltage log.debug(f'Zähler {self.num}: {self.data.set.raw_currents_left}A verbleibende Ströme, ' f'{self.data.set.raw_power_left}W verbleibende Leistung') def update_surplus_values_left(self, diffs) -> None: self.data.set.raw_currents_left = list(map(operator.sub, self.data.set.raw_currents_left, diffs)) if self.data.set.surplus_power_left: - self.data.set.surplus_power_left -= sum(diffs) * 230 + average_voltage = sum(self.data.get.voltages)/len(self.data.get.voltages) + self.data.set.surplus_power_left -= sum(diffs) * average_voltage log.debug(f'Zähler {self.num}: {self.data.set.raw_currents_left}A verbleibende Ströme, ' f'{self.data.set.surplus_power_left}W verbleibender Überschuss') diff --git a/packages/control/loadmanagement.py b/packages/control/loadmanagement.py index efc59ce58e..1b595ebf50 100644 --- a/packages/control/loadmanagement.py +++ b/packages/control/loadmanagement.py @@ -16,9 +16,10 @@ def get_available_currents(self, counter: Counter, feed_in: int = 0) -> Tuple[List[float], Optional[LimitingValue]]: raw_currents_left = counter.data.set.raw_currents_left + average_voltage = sum(counter.data.get.voltages)/len(counter.data.get.voltages) available_currents, limit = self._limit_by_current(missing_currents, raw_currents_left) available_currents, limit_power = self._limit_by_power( - available_currents, counter.data.set.raw_power_left, feed_in) + available_currents, average_voltage, counter.data.set.raw_power_left, feed_in) if limit_power is not None: limit = limit_power if f"counter{counter.num}" == data.data.counter_all_data.get_evu_counter_str(): @@ -33,9 +34,10 @@ def get_available_currents_surplus(self, counter: Counter, feed_in: int = 0) -> Tuple[List[float], Optional[LimitingValue]]: raw_currents_left = counter.data.set.raw_currents_left + average_voltage = sum(counter.data.get.voltages)/len(counter.data.get.voltages) available_currents, limit = self._limit_by_current(missing_currents, raw_currents_left) available_currents, limit_power = self._limit_by_power( - available_currents, counter.data.set.surplus_power_left, feed_in) + available_currents, average_voltage, counter.data.set.surplus_power_left, feed_in) if limit_power is not None: limit = limit_power if f"counter{counter.num}" == data.data.counter_all_data.get_evu_counter_str(): @@ -61,6 +63,7 @@ def _limit_by_unbalanced_load(self, # tested def _limit_by_power(self, available_currents: List[float], + average_voltage: float, raw_power_left: Optional[float], feed_in: Optional[float]) -> Tuple[List[float], Optional[LimitingValue]]: currents = available_currents.copy() @@ -69,10 +72,10 @@ def _limit_by_power(self, if feed_in: raw_power_left = raw_power_left - feed_in log.debug(f"Verbleibende Leistung unter Berücksichtigung der Einspeisegrenze: {raw_power_left}W") - if sum(available_currents)*230 > raw_power_left: + if sum(available_currents)*average_voltage > raw_power_left: for i in range(0, 3): # Am meisten belastete Phase trägt am meisten zur Leistungsreduktion bei. - currents[i] = available_currents[i] / sum(available_currents) * raw_power_left / 230 + currents[i] = available_currents[i] / sum(available_currents) * raw_power_left / average_voltage log.debug(f"Leistungsüberschreitung auf {raw_power_left}W korrigieren: {available_currents}") limit = LimitingValue.POWER return currents, limit From 177712126135824485aa8ab0d05e0a4e7c098951 Mon Sep 17 00:00:00 2001 From: vuffiraa72 Date: Fri, 2 Feb 2024 11:27:41 +0100 Subject: [PATCH 3/5] rage offset is independent from state of control range --- packages/control/counter.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/packages/control/counter.py b/packages/control/counter.py index 6d6df59730..1ef4dca930 100644 --- a/packages/control/counter.py +++ b/packages/control/counter.py @@ -241,15 +241,8 @@ def _control_range_offset(self): 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_center = control_range_high - (control_range_high - control_range_low) / 2 - control_range_state = self.get_control_range_state(0) - if control_range_state == ControlRangeState.BELOW: - range_offset = abs(control_range_center) - elif control_range_state == ControlRangeState.ABOVE: - range_offset = - abs(control_range_center) - else: - range_offset = 0 - log.debug(f"Anpassen des Regelbereichs {range_offset}W") - return range_offset + log.debug(f"Anpassen des Regelbereichs {control_range_center}W") + return control_range_center SWITCH_ON_FALLEN_BELOW = "Einschaltschwelle während der Einschaltverzögerung unterschritten." SWITCH_ON_WAITING = "Die Ladung wird gestartet, sobald nach {}s die Einschaltverzögerung abgelaufen ist." From a53c72ede459173316b23beab69c93402af5bec7 Mon Sep 17 00:00:00 2001 From: vuffiraa72 Date: Sat, 3 Feb 2024 16:53:52 +0100 Subject: [PATCH 4/5] fix flake8 problems --- packages/control/algorithm/algorithm_test.py | 56 +++++++++++++++----- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/packages/control/algorithm/algorithm_test.py b/packages/control/algorithm/algorithm_test.py index 516563d408..9aeaba1dbc 100644 --- a/packages/control/algorithm/algorithm_test.py +++ b/packages/control/algorithm/algorithm_test.py @@ -29,20 +29,48 @@ def data_fixture() -> None: @pytest.mark.parametrize("control_range, evu_power, evu_currents, evu_voltages, cp_power, cp_currents", - [pytest.param([-230, 0], -84.08, [-2.42, 4.69, -2.66], [239, 237.8, 237.6], 1823.86, [7.81, -0.06, 0.06], id="Einspeisung, im Regelbereich"), - pytest.param([-230, 0], 41.96, [-2.4, 5.22, -2.64], [238.7, 237.7, 237.7], 1939.72, [8.31, -0.06, 0.06], id="Einspeisung, über Regelbereich"), - pytest.param([-230, 0], -690, [-1, -1, -1], [230, 230, 230], 1610, [7, 0, 0], id="Einspeisung bei 230V Spannung, unter Regelbereich"), - pytest.param([-230, 0], -115, [0, -0.5, 0], [230, 230, 230], 2185, [9.5, 0, 0], id="Einspeisung bei 230V Spannung, im Regelbereich"), - pytest.param([-230, 0], -115, [0, -0.49, 0], [235, 235, 235], 2185, [9.3, 0, 0], id="Einspeisung bei 235V Spannung, im Regelbereich"), - pytest.param([-230, 0], 235, [0, 1, 0], [235, 235, 235], 2535, [10.87, 0, 0], id="Einspeisung bei 235V Spannung, über Regelbereich"), - pytest.param([0, 230], -230, [0, -1, 0], [230, 230, 230], 2070, [9, 0, 0], id="Bezug bei 230V Spannung, unter Regelbereich"), - pytest.param([0, 230], 115, [0, 0.5, 0], [230, 230, 230], 2415, [10.5, 0, 0], id="Bezug bei 230V Spannung, im Regelbereich"), - pytest.param([0, 230], 115, [0, 0.49, 0], [235, 235, 235], 2415, [10.3, 0, 0], id="Bezug bei 235V Spannung, im Regelbereich"), - pytest.param([0, 230], 705, [1, 1, 1], [235, 235, 235], 3005, [12.8, 0, 0], id="Bezug bei 235V Spannung, über Regelbereich"), - pytest.param([-115, 115], -230, [0, -1, 0], [230, 230, 230], 2070, [9, 0, 0], id="Ausgeglichen bei 230V Spannung, unter Regelbereich"), - pytest.param([-115, 115], 0, [0, 0, 0], [230, 230, 230], 2300, [10, 0, 0], id="Ausgeglichen bei 230V Spannung, im Regelbereich"), - pytest.param([-115, 115], 0, [0, 0, 0], [235, 235, 235], 2300, [9.8, 0, 0], id="Ausgeglichen bei 235V Spannung, im Regelbereich"), - pytest.param([-115, 115], 235, [0, 1, 0], [235, 235, 235], 2535, [10.8, 0, 0], id="Ausgeglichen bei 235V Spannung, über Regelbereich") + [pytest.param( + [-230, 0], -84.08, [-2.42, 4.69, -2.66], [239, 237.8, 237.6], 1823.86, [7.81, -0.06, 0.06], + id="Einspeisung, im Regelbereich"), + pytest.param( + [-230, 0], 41.96, [-2.4, 5.22, -2.64], [238.7, 237.7, 237.7], 1939.72, [8.31, -0.06, 0.06], + id="Einspeisung, über Regelbereich"), + pytest.param( + [-230, 0], -690, [-1, -1, -1], [230, 230, 230], 1610, [7, 0, 0], + id="Einspeisung bei 230V Spannung, unter Regelbereich"), + pytest.param( + [-230, 0], -115, [0, -0.5, 0], [230, 230, 230], 2185, [9.5, 0, 0], + id="Einspeisung bei 230V Spannung, im Regelbereich"), + pytest.param( + [-230, 0], -115, [0, -0.49, 0], [235, 235, 235], 2185, [9.3, 0, 0], + id="Einspeisung bei 235V Spannung, im Regelbereich"), + pytest.param( + [-230, 0], 235, [0, 1, 0], [235, 235, 235], 2535, [10.87, 0, 0], + id="Einspeisung bei 235V Spannung, über Regelbereich"), + pytest.param( + [0, 230], -230, [0, -1, 0], [230, 230, 230], 2070, [9, 0, 0], + id="Bezug bei 230V Spannung, unter Regelbereich"), + pytest.param( + [0, 230], 115, [0, 0.5, 0], [230, 230, 230], 2415, [10.5, 0, 0], + id="Bezug bei 230V Spannung, im Regelbereich"), + pytest.param( + [0, 230], 115, [0, 0.49, 0], [235, 235, 235], 2415, [10.3, 0, 0], + id="Bezug bei 235V Spannung, im Regelbereich"), + pytest.param( + [0, 230], 705, [1, 1, 1], [235, 235, 235], 3005, [12.8, 0, 0], + id="Bezug bei 235V Spannung, über Regelbereich"), + pytest.param( + [-115, 115], -230, [0, -1, 0], [230, 230, 230], 2070, [9, 0, 0], + id="Ausgeglichen bei 230V Spannung, unter Regelbereich"), + pytest.param( + [-115, 115], 0, [0, 0, 0], [230, 230, 230], 2300, [10, 0, 0], + id="Ausgeglichen bei 230V Spannung, im Regelbereich"), + pytest.param( + [-115, 115], 0, [0, 0, 0], [235, 235, 235], 2300, [9.8, 0, 0], + id="Ausgeglichen bei 235V Spannung, im Regelbereich"), + pytest.param( + [-115, 115], 235, [0, 1, 0], [235, 235, 235], 2535, [10.8, 0, 0], + id="Ausgeglichen bei 235V Spannung, über Regelbereich") ] ) def test_calc_current(control_range, evu_power, evu_currents, evu_voltages, cp_power, cp_currents, monkeypatch): From b89ca9a8637c3b61df3c4f6a3275d7d9a45ee4a1 Mon Sep 17 00:00:00 2001 From: vuffiraa72 Date: Fri, 16 Feb 2024 19:25:51 +0100 Subject: [PATCH 5/5] fix tests to match pv charging --- .../algorithm/integration_test/pv_charging_test.py | 8 ++++---- packages/control/counter_test.py | 8 ++++---- packages/control/loadmanagement_test.py | 13 +++++++------ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/control/algorithm/integration_test/pv_charging_test.py b/packages/control/algorithm/integration_test/pv_charging_test.py index 25fed2f500..70272a3e20 100644 --- a/packages/control/algorithm/integration_test/pv_charging_test.py +++ b/packages/control/algorithm/integration_test/pv_charging_test.py @@ -133,7 +133,7 @@ def test_start_pv_delay(all_cp_pv_charging_3p, all_cp_not_charging, monkeypatch) assert data.data.cp_data[ "cp5"].data.control_parameter.timestamp_switch_on_off is None assert data.data.counter_data["counter0"].data.set.raw_power_left == 31775 - assert data.data.counter_data["counter0"].data.set.surplus_power_left == 9660 + assert data.data.counter_data["counter0"].data.set.surplus_power_left == 9890 assert data.data.counter_data["counter0"].data.set.reserved_surplus == 9000 @@ -172,7 +172,7 @@ def test_pv_delay_expired(all_cp_pv_charging_3p, all_cp_not_charging, monkeypatc assert data.data.cp_data[ "cp5"].data.control_parameter.timestamp_switch_on_off is None assert data.data.counter_data["counter0"].data.set.raw_power_left == 24300 - assert data.data.counter_data["counter0"].data.set.surplus_power_left == 2185 + assert data.data.counter_data["counter0"].data.set.surplus_power_left == 2415 assert data.data.counter_data["counter0"].data.set.reserved_surplus == 0 @@ -210,7 +210,7 @@ def test_pv_delay_expired(all_cp_pv_charging_3p, all_cp_not_charging, monkeypatc expected_current_cp4=6, expected_current_cp5=6, expected_raw_power_left=5635, - expected_surplus_power_left=-16480.0, + expected_surplus_power_left=-16250.0, expected_reserved_surplus=0, expected_released_surplus=11040), ] @@ -246,7 +246,7 @@ def test_surplus(params: ParamsSurplus, all_cp_pv_charging_3p, all_cp_charging_3 expected_current_cp4=6, expected_current_cp5=6, expected_raw_power_left=17400, - expected_surplus_power_left=-4715, + expected_surplus_power_left=-4485, expected_reserved_surplus=0, expected_released_surplus=0), ParamsPhaseSwitch(name="phase switch 1p->3p", diff --git a/packages/control/counter_test.py b/packages/control/counter_test.py index 6e9a05810f..5e253f47c8 100644 --- a/packages/control/counter_test.py +++ b/packages/control/counter_test.py @@ -149,12 +149,12 @@ def test_switch_on_threshold_reached(params: Params, caplog, general_data_fixtur @pytest.mark.parametrize("control_range, evu_power, expected_range_offset", - [pytest.param([0, 230], 200, 0, id="Bezug, im Regelbereich"), - pytest.param([0, 230], 290, -115, id="Bezug, über Regelbereich"), + [pytest.param([0, 230], 200, 115, id="Bezug, im Regelbereich"), + pytest.param([0, 230], 290, 115, id="Bezug, über Regelbereich"), pytest.param([0, 230], -100, 115, id="Bezug, unter Regelbereich"), - pytest.param([-230, 0], -104, 0, id="Einspeisung, im Regelbereich"), + pytest.param([-230, 0], -104, -115, id="Einspeisung, im Regelbereich"), pytest.param([-230, 0], 80, -115, id="Einspeisung, über Regelbereich"), - pytest.param([-230, 0], -300, 115, id="Einspeisung, unter Regelbereich"), + pytest.param([-230, 0], -300, -115, id="Einspeisung, unter Regelbereich"), ], ) def test_control_range(control_range, evu_power, expected_range_offset, general_data_fixture, monkeypatch): diff --git a/packages/control/loadmanagement_test.py b/packages/control/loadmanagement_test.py index 0d143dcda5..deda6d17bc 100644 --- a/packages/control/loadmanagement_test.py +++ b/packages/control/loadmanagement_test.py @@ -6,17 +6,18 @@ @pytest.mark.parametrize( - "available_currents, raw_power_left, expected_currents", + "available_currents, voltage, raw_power_left, expected_currents", [ - pytest.param([5, 10, 15], 6900, ([5, 10, 15], None)), - pytest.param([5, 10, 25], 1000, ([0.5434782608695652, 1.0869565217391304, + pytest.param([5, 10, 15], 230, 6900, ([5, 10, 15], None)), + pytest.param([5, 10, 25], 230, 1000, ([0.5434782608695652, 1.0869565217391304, 2.717391304347826], LimitingValue.POWER)), - pytest.param([5, 10, 25], 5000, ([2.717391304347826, 5.434782608695652, + pytest.param([5, 10, 25], 230, 5000, ([2.717391304347826, 5.434782608695652, 13.58695652173913], LimitingValue.POWER)), ]) -def test_limit_by_power(available_currents: List[float], raw_power_left: float, expected_currents: List[float]): +def test_limit_by_power(available_currents: List[float], voltage: float, raw_power_left: float, + expected_currents: List[float]): # setup & evaluation - currents = Loadmanagement()._limit_by_power(available_currents, raw_power_left, None) + currents = Loadmanagement()._limit_by_power(available_currents, voltage, raw_power_left, None) # assertion assert currents == expected_currents