-
Notifications
You must be signed in to change notification settings - Fork 115
hybrid system: fix consideration of max out power #3247
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -179,9 +179,9 @@ def calc_power_for_all_components(self): | |
| except Exception: | ||
| log.exception("Fehler im Bat-Modul") | ||
|
|
||
| def _inverter_limited_power(self, inverter: Pv) -> float: | ||
| """gibt die maximale Entladeleistung des Speichers zurück, bis die maximale Ausgangsleistung des WR erreicht | ||
| ist.""" | ||
| def _get_pv_power_beyond_max_ac_out(self, inverter: Pv) -> float: | ||
| """gibt die PV-Leistung zurück, die über der maximalen Ausgangsleistung des Wechselrichters liegt und somit | ||
| nicht für die Entladung des Speichers genutzt werden kann.""" | ||
| # tested | ||
|
Comment on lines
+182
to
185
|
||
| # Wenn vom PV-Ertrag der Speicher geladen wird, kann diese Leistung bis zur max Ausgangsleistung des WR | ||
| # genutzt werden. | ||
|
|
@@ -193,18 +193,32 @@ def _inverter_limited_power(self, inverter: Pv) -> float: | |
| def _limit_bat_power_discharge(self, required_power): | ||
| """begrenzt die für den Algorithmus benötigte Entladeleistung des Speichers, wenn die maximale Ausgangsleistung | ||
| des WR erreicht ist.""" | ||
| inverter_limited_power = 0 | ||
| pv_power_beyond_max_ac_out = 0 | ||
| if required_power > 0: | ||
| # Nur wenn der Speicher entladen werden soll, fließt Leistung durch den WR. | ||
| for inverter in data.data.pv_data.values(): | ||
| try: | ||
| inverter_limited_power += self._inverter_limited_power(inverter) | ||
| pv_power_beyond_max_ac_out += self._get_pv_power_beyond_max_ac_out(inverter) | ||
| except Exception: | ||
| log.exception(f"Fehler im Bat-Modul {inverter.num}") | ||
| if inverter_limited_power > 0: | ||
| required_power = max(required_power-inverter_limited_power, 0) | ||
| log.debug(f"Verbleibende Speicher-Leistung durch maximale Ausgangsleistung auf {required_power}W" | ||
| " begrenzt.") | ||
| # Wenn max_inverter_power_for_bat nur deshalb negativ ist, weil der Speicher aktuell bereits entlädt | ||
| # (self.data.get.power < 0) und keine PV-Leistung über der maximalen WR-Ausgangsleistung anliegt | ||
| # (pv_power_beyond_max_ac_out == 0), dann würde eine Begrenzung auf 0W die noch verfügbare | ||
| # Entladeleistung fälschlicherweise unterdrücken. In diesem Fall wenden wir keine zusätzliche | ||
| # Begrenzung durch die WR-Ausgangsleistung an. | ||
| if pv_power_beyond_max_ac_out > 0: | ||
| max_inverter_power_for_bat = self.data.get.power - pv_power_beyond_max_ac_out | ||
| # Negative Werte bedeuten, dass bereits mehr Leistung über den WR fließt, als für den Speicher | ||
| # zusätzlich verfügbar ist; in diesem Fall ist keine weitere Entladung möglich. | ||
| max_inverter_power_for_bat = max(max_inverter_power_for_bat, 0) | ||
| required_power = min(required_power, max_inverter_power_for_bat) | ||
| log.debug( | ||
| f"Verbleibende Speicher-Leistung durch maximale Ausgangsleistung auf {required_power}W begrenzt." | ||
| ) | ||
| else: | ||
| log.debug( | ||
| "Speicher-Entladeleistung nicht durch maximale WR-Ausgangsleistung begrenzt, da keine PV-Leistung " | ||
| "über der maximalen WR-Ausgangsleistung anliegt.") | ||
| return required_power | ||
|
|
||
| def _set_bat_power_active_control(self, power): | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -16,9 +16,8 @@ | |||||||
| from modules.devices.generic.mqtt.config import MqttBatSetup | ||||||||
|
|
||||||||
|
|
||||||||
| @pytest.fixture | ||||||||
| @pytest.fixture(autouse=True) | ||||||||
| def data_fixture() -> None: | ||||||||
| data.data_init(Mock()) | ||||||||
| data.data.general_data = General() | ||||||||
|
Comment on lines
+19
to
21
|
||||||||
| data.data.cp_all_data = Mock(spec=AllChargepoints, data=Mock( | ||||||||
| spec=AllChargepointData, get=Mock(spec=AllGet, power=0))) | ||||||||
|
|
@@ -35,34 +34,45 @@ def data_fixture() -> None: | |||||||
| pytest.param(0, -6000, 0, id="max_ac_out ist 0"), | ||||||||
| ], | ||||||||
| ) | ||||||||
| def test_inverter_limited_power(max_ac_out, power, expected_result): | ||||||||
| def test_pv_power_beyond_max_ac_out(max_ac_out: int, power: int, expected_result: int): | ||||||||
| # Mock für die Pv-Klasse | ||||||||
| inverter = Pv(1) | ||||||||
| inverter.data.config.max_ac_out = max_ac_out | ||||||||
| inverter.data.get.power = power | ||||||||
| bat_all = BatAll() | ||||||||
|
|
||||||||
| # Aufruf der zu testenden Funktion | ||||||||
| result = bat_all._inverter_limited_power(inverter) | ||||||||
| result = bat_all._get_pv_power_beyond_max_ac_out(inverter) | ||||||||
|
|
||||||||
| # Überprüfung des Ergebnisses | ||||||||
| assert result == expected_result | ||||||||
|
|
||||||||
|
|
||||||||
| @pytest.mark.parametrize( | ||||||||
| "required_power, return_inverter_limited_power, expected_power", | ||||||||
| "bat_power, required_power, return_pv_power_beyond_max_ac_out, expected_power", | ||||||||
| [ | ||||||||
| pytest.param(1000, 0, 1000, id="maximale Entladeleistung nicht erreicht"), | ||||||||
| pytest.param(1000, 100, 900, id="maximale Entladeleistung erreicht"), | ||||||||
| pytest.param(-1000, 10, -1000, id="Speicher soll nicht mehr entladen werden"), | ||||||||
| pytest.param(1000, 1000, 0, 1000, id="exakt max Leistung des WR"), | ||||||||
| pytest.param(1000, 1000, 100, 900, id="max Leistung des WR um 100W überschritten"), | ||||||||
| pytest.param(1000, 1000, 1100, 0, id="maximale Entladeleistung erreicht"), | ||||||||
| pytest.param(3000, 3000, 2000, 1000, id="max Leistung des WR um 2000W überschritten"), | ||||||||
| pytest.param(3000, 5000, 2000, 1000, id="max Leistung des WR um 2000W überschritten, " + | ||||||||
| "erlaubte Entladeleistung höher als aktuelle Leistung"), | ||||||||
|
||||||||
| "erlaubte Entladeleistung höher als aktuelle Leistung"), | |
| "erlaubte Entladeleistung höher als aktuelle Leistung"), | |
| pytest.param(-1000, 1000, 2000, 0, id="Speicher lädt, Entladung angefordert, PV bereits über max_ac_out"), |
Copilot
AI
Mar 27, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
data.data.pv_data = {"pv2": Pv(2)} assumes the global control.data.data has been initialized via data.data_init(...), but this test doesn’t request the local data_fixture (and doesn’t take the shared data_ fixture either). That makes the test order-dependent and it can fail in isolation. Include a fixture that calls data.data_init(...) in this test’s signature (or make the module’s data_fixture autouse).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im Docstring ist ein Tippfehler: „Entadung“ sollte „Entladung“ heißen.