-
Notifications
You must be signed in to change notification settings - Fork 117
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
646b95a
1798268
81b6339
603c5bd
f5b04b7
0565cf8
68983bf
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 |
|---|---|---|
|
|
@@ -344,3 +344,117 @@ 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_activated, condition, limit, manual_mode, expected_result", | ||
| [ | ||
| pytest.param(False, | ||
| BatPowerLimitCondition.MANUAL.value, | ||
| BatPowerLimitMode.MODE_NO_DISCHARGE.value, | ||
| ManualMode.MANUAL_DISABLE.value, True, | ||
| id="Speichersteuerung nicht aktiviert, aber aktiviert -> laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.MANUAL.value, | ||
| BatPowerLimitMode.MODE_NO_DISCHARGE.value, | ||
| ManualMode.MANUAL_DISABLE.value, True, | ||
| id="Manuell, Eigenregelung, volle Entladesperre -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.MANUAL.value, | ||
| BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value, | ||
| ManualMode.MANUAL_LIMIT.value, False, | ||
| id="Manuell, Entladung in Fahrzeuge sperren -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.MANUAL.value, | ||
| BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value, | ||
| ManualMode.MANUAL_CHARGE.value, False, | ||
| id="Manuell, PV-Ertrag speichern -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.VEHICLE_CHARGING.value, | ||
| BatPowerLimitMode.MODE_NO_DISCHARGE.value, | ||
| ManualMode.MANUAL_DISABLE.value, False, | ||
| id="Fahrzeuge laden, volle Entladesperre -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.VEHICLE_CHARGING.value, | ||
| BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value, | ||
| ManualMode.MANUAL_DISABLE.value, False, | ||
| id="Fahrzeuge laden, Entladung in Fahrzeuge sperren -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.VEHICLE_CHARGING.value, | ||
| BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value, | ||
| ManualMode.MANUAL_DISABLE.value, False, | ||
| id="Fahrzeuge laden, PV-Ertrag speichern -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.PRICE_LIMIT.value, | ||
| BatPowerLimitMode.MODE_NO_DISCHARGE.value, | ||
| ManualMode.MANUAL_DISABLE.value, False, | ||
| id="Preislimit, volle Entladesperre -> nicht laden"), | ||
| pytest.param(True, | ||
| BatPowerLimitCondition.PRICE_LIMIT.value, | ||
| BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value, | ||
| ManualMode.MANUAL_DISABLE.value, False, | ||
| id="Preislimit, Entladung in Fahrzeuge sperren -> nicht laden"), | ||
|
|
||
| ] | ||
| ) | ||
| def test_time_charging_min_bat_soc_allowed(control_activated: bool, | ||
| condition: str, | ||
| limit: str, | ||
| manual_mode: str, | ||
| 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_activated = control_activated | ||
| b.data.config.manual_mode = manual_mode | ||
|
|
||
| # 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: pytest.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_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
+349
to
+460
|
||
| 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 = 128 | ||||||||||||||||||||||||||||||||||||||||||||||||
| DATASTORE_VERSION = 129 | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| valid_topic = [ | ||||||||||||||||||||||||||||||||||||||||||||||||
| "^openWB/bat/config/bat_control_activated$", | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -3265,4 +3265,13 @@ def upgrade_component(topic: str, payload) -> Optional[dict]: | |||||||||||||||||||||||||||||||||||||||||||||||
| MessageType.INFO | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| self._append_datastore_version(128) | ||||||||||||||||||||||||||||||||||||||||||||||||
| def upgrade_datastore_129(self) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||
| def upgrade(topic: str, payload) -> None: | ||||||||||||||||||||||||||||||||||||||||||||||||
| 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
+3272
to
+3275
|
||||||||||||||||||||||||||||||||||||||||||||||||
| 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.
Test setup does not set
b.data.config.configured = True, butBatAll.time_charging_min_bat_soc_allowed()gates its logic onself.data.config.configured. With the defaultconfigured=False, this test will always getTrueand cannot validate the intended branches.