-
Notifications
You must be signed in to change notification settings - Fork 115
Time charging: min bat soc #3304
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
base: master
Are you sure you want to change the base?
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 |
|---|---|---|
|
|
@@ -367,3 +367,107 @@ def test_control_price_limit(params: BatControlParams, data_, monkeypatch): | |
| data.data.bat_all_data._set_bat_power_active_control(data.data.bat_all_data.data.set.power_limit) | ||
|
|
||
| assert data.data.bat_data["bat2"].data.set.power_limit == params.expected_power_limit_bat | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "control_permitted, control_activated, condition, limit, expected_result", | ||
| [ | ||
| pytest.param(False, True, | ||
| BatPowerLimitCondition.MANUAL.value, BatPowerLimitMode.MODE_NO_DISCHARGE.value, True, | ||
| id="Speichersteuerung nicht erlaubt, aber aktiviert -> laden"), | ||
| pytest.param(True, False, | ||
| BatPowerLimitCondition.MANUAL.value, BatPowerLimitMode.MODE_NO_DISCHARGE.value, True, | ||
| id="Speichersteuerung erlaubt, aber nicht aktiviert -> laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.MANUAL.value, BatPowerLimitMode.MODE_NO_DISCHARGE.value, False, | ||
| id="Manuell, volle Entladesperre -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.MANUAL.value, | ||
| BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value, False, | ||
| id="Manuell, Entladung in Fahrzeuge sperren -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.MANUAL.value, BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value, False, | ||
| id="Manuell, PV-Ertrag speichern -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.VEHICLE_CHARGING.value, BatPowerLimitMode.MODE_NO_DISCHARGE.value, False, | ||
| id="Fahrzeuge laden, volle Entladesperre -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.VEHICLE_CHARGING.value, | ||
| BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value, False, | ||
| id="Fahrzeuge laden, Entladung in Fahrzeuge sperren -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.VEHICLE_CHARGING.value, | ||
| BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value, False, | ||
| id="Fahrzeuge laden, PV-Ertrag speichern -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.PRICE_LIMIT.value, BatPowerLimitMode.MODE_NO_DISCHARGE.value, False, | ||
| id="Preislimit, volle Entladesperre -> nicht laden"), | ||
| pytest.param(True, True, | ||
| BatPowerLimitCondition.PRICE_LIMIT.value, | ||
| BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value, False, | ||
| id="Preislimit, Entladung in Fahrzeuge sperren -> nicht laden"), | ||
|
|
||
| ] | ||
| ) | ||
| def test_time_charging_min_bat_soc_allowed(control_permitted: bool, | ||
| control_activated: bool, | ||
| condition: BatPowerLimitCondition, | ||
| limit: BatPowerLimitMode, | ||
| expected_result: bool): | ||
| # setup | ||
| b = BatAll() | ||
| b.data.config.configured = True | ||
| b.data.config.power_limit_condition = condition | ||
| b.data.config.power_limit_mode = limit | ||
| b.data.config.bat_control_permitted = control_permitted | ||
| b.data.config.bat_control_activated = control_activated | ||
|
|
||
|
Comment on lines
+418
to
+424
|
||
| # execution | ||
| result = b.time_charging_min_bat_soc_allowed() | ||
|
|
||
| # evaluation | ||
| assert result == expected_result | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "ep_configured, price_limit_activated, price_charge_activated, price_threshold_mock, expected_result", | ||
| [ | ||
| pytest.param(False, True, True, [True, True], True, | ||
| id="Preislimit aktiviert, aber kein Preis konfiguriert -> Eigenregelung -> laden"), | ||
| pytest.param(True, True, False, [True], True, | ||
| id="Strompreis für Regelmodus, Preis unter Limit -> laden"), | ||
| pytest.param(True, True, False, [False], False, | ||
| id="Strompreis für Regelmodus, Preis über Limit -> nicht laden"), | ||
| pytest.param(True, False, True, [True], True, | ||
| id="Strompreis für aktives Laden, Preis unter Limit -> laden"), | ||
| pytest.param(True, False, True, [False], False, | ||
| id="Strompreis für aktives Laden, Preis unter Limit -> nicht laden"), | ||
| pytest.param(True, False, False, [], False, | ||
| id="beide Strompreise deaktiviert -> nicht laden"), | ||
| ] | ||
| ) | ||
| def test_time_charging_min_bat_soc_allowed_pricing(ep_configured: bool, | ||
| price_limit_activated: bool, | ||
| price_charge_activated: bool, | ||
| price_threshold_mock: List[bool], | ||
| expected_result: bool, | ||
| monkeypatch): | ||
| # setup | ||
| b = BatAll() | ||
| b.data.config.configured = True | ||
| b.data.config.power_limit_condition = BatPowerLimitCondition.PRICE_LIMIT.value | ||
| b.data.config.power_limit_mode = BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value | ||
| b.data.config.price_limit_activated = price_limit_activated | ||
| b.data.config.price_charge_activated = price_charge_activated | ||
| data.data.optional_data.data.electricity_pricing.configured = ep_configured | ||
| b.data.config.bat_control_permitted = True | ||
| b.data.config.bat_control_activated = True | ||
|
|
||
| monkeypatch.setattr(data.data.optional_data, "ep_is_charging_allowed_price_threshold", | ||
| Mock(side_effect=price_threshold_mock)) | ||
|
|
||
| # execution | ||
| result = b.time_charging_min_bat_soc_allowed() | ||
|
|
||
| # evaluation | ||
| assert result == expected_result | ||
|
Comment on lines
+372
to
+473
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -143,6 +143,10 @@ class ChargeTemplate: | |||||||||||||
| TIME_CHARGING_NO_PLAN_ACTIVE = "Kein Zeitfenster für Zeitladen aktiv." | ||||||||||||||
| TIME_CHARGING_SOC_REACHED = "Das Ladeziel für das Zeitladen wurde erreicht." | ||||||||||||||
| TIME_CHARGING_AMOUNT_REACHED = "Die gewünschte Energiemenge für das Zeitladen wurde geladen." | ||||||||||||||
| TIME_CHARGING_CONFLICT_ACTIVE_BAT_CONTROL = ("Laden mit Zeitladen nach Speicher-SoC nicht möglich, da dies im " | ||||||||||||||
| "Konflikt mit der aktiven Speichersteuerung steht.") | ||||||||||||||
| TIME_CHARGING_MIN_BAT_SOC_REACHED = ("Laden mit Zeitladen nach Speicher-SoC nicht möglich, da der SoC des" | ||||||||||||||
| " Speichers unter dem minimalen SoC liegt.") | ||||||||||||||
|
|
||||||||||||||
| def time_charging(self, | ||||||||||||||
| soc: Optional[float], | ||||||||||||||
|
|
@@ -151,34 +155,40 @@ def time_charging(self, | |||||||||||||
| """ prüft, ob ein Zeitfenster aktiv ist und setzt entsprechend den Ladestrom | ||||||||||||||
| """ | ||||||||||||||
| message = None | ||||||||||||||
| sub_mode = "time_charging" | ||||||||||||||
| sub_mode = "stop" | ||||||||||||||
| current = 0 | ||||||||||||||
| id = None | ||||||||||||||
| phases = None | ||||||||||||||
| try: | ||||||||||||||
| if self.data.time_charging.plans: | ||||||||||||||
| plan = timecheck.check_plans_timeframe(self.data.time_charging.plans) | ||||||||||||||
| if plan is not None: | ||||||||||||||
| current = plan.current if charging_type == ChargingType.AC.value else plan.dc_current | ||||||||||||||
| phases = plan.phases_to_use | ||||||||||||||
| id = plan.id | ||||||||||||||
| phases = plan.phases_to_use | ||||||||||||||
| if plan.limit.selected == "soc" and soc and soc >= plan.limit.soc: | ||||||||||||||
| # SoC-Limit erreicht | ||||||||||||||
| current = 0 | ||||||||||||||
| sub_mode = "stop" | ||||||||||||||
| message = self.TIME_CHARGING_SOC_REACHED | ||||||||||||||
| elif plan.limit.selected == "amount" and used_amount_time_charging >= plan.limit.amount: | ||||||||||||||
| # Energie-Limit erreicht | ||||||||||||||
| current = 0 | ||||||||||||||
| sub_mode = "stop" | ||||||||||||||
| message = self.TIME_CHARGING_AMOUNT_REACHED | ||||||||||||||
| elif plan.min_bat_soc is not None and data.data.bat_all_data.data.config.configured: | ||||||||||||||
| if data.data.bat_all_data.time_charging_min_bat_soc_allowed(): | ||||||||||||||
|
||||||||||||||
| if data.data.bat_all_data.time_charging_min_bat_soc_allowed(): | |
| if not data.data.bat_all_data.data.config.configured: | |
| log.debug("Zeitladen: kein Speicher konfiguriert, minimaler Speicher-SoC wird ignoriert.") | |
| current = plan.current if charging_type == ChargingType.AC.value else plan.dc_current | |
| sub_mode = "time_charging" | |
| elif data.data.bat_all_data.time_charging_min_bat_soc_allowed(): |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -57,7 +57,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| class UpdateConfig: | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| DATASTORE_VERSION = 121 | ||||||||||||||||||||||||||||||||||||||||||||||||
| DATASTORE_VERSION = 122 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| valid_topic = [ | ||||||||||||||||||||||||||||||||||||||||||||||||
| "^openWB/bat/config/bat_control_permitted$", | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -3068,3 +3068,14 @@ def upgrade(topic: str, payload) -> Optional[dict]: | |||||||||||||||||||||||||||||||||||||||||||||||
| return {topic: payload} | ||||||||||||||||||||||||||||||||||||||||||||||||
| self._loop_all_received_topics(upgrade) | ||||||||||||||||||||||||||||||||||||||||||||||||
| self._append_datastore_version(121) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| def upgrade_datastore_122(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||
| def upgrade(topic: str, payload) -> Optional[dict]: | ||||||||||||||||||||||||||||||||||||||||||||||||
| if re.search("openWB/vehicle/template/charge_template/[0-9]+$", topic) is not None: | ||||||||||||||||||||||||||||||||||||||||||||||||
| payload = decode_payload(payload) | ||||||||||||||||||||||||||||||||||||||||||||||||
| for plan in payload["time_charging"]["plans"]: | ||||||||||||||||||||||||||||||||||||||||||||||||
| if plan.get("min_bat_soc") is None: | ||||||||||||||||||||||||||||||||||||||||||||||||
| plan.update({"min_bat_soc": None}) | ||||||||||||||||||||||||||||||||||||||||||||||||
| return {topic: payload} | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+3076
to
+3079
|
||||||||||||||||||||||||||||||||||||||||||||||||
| for plan in payload["time_charging"]["plans"]: | |
| if plan.get("min_bat_soc") is None: | |
| plan.update({"min_bat_soc": None}) | |
| return {topic: payload} | |
| if not isinstance(payload, dict): | |
| return None | |
| time_charging = payload.get("time_charging") | |
| if not isinstance(time_charging, dict): | |
| return None | |
| plans = time_charging.get("plans", []) | |
| if not isinstance(plans, list): | |
| return None | |
| changed = False | |
| for plan in plans: | |
| if isinstance(plan, dict) and "min_bat_soc" not in plan: | |
| plan["min_bat_soc"] = None | |
| changed = True | |
| if changed: | |
| return {topic: payload} |
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.
In
test_time_charging_min_bat_soc_allowed, the parametersconditionandlimitare annotated asBatPowerLimitCondition/BatPowerLimitMode, but the parametrized values passed in are the.valuestrings. This makes the type hints incorrect and can confuse readers/tools; either annotate them asstror pass the enum instances instead of.value.