Skip to content

Commit 718b2d6

Browse files
committed
Merge remote-tracking branch 'upstream/master' into fixed-hours-per-weekday
2 parents 76c8b09 + 6b65b8b commit 718b2d6

392 files changed

Lines changed: 2668 additions & 1166 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

data/config/mosquitto/public/default-dynamic-security.json

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
"anonymousGroup": "anonymous",
7171
"roles": [
7272
{
73-
"rolename": "openwb-version:4",
73+
"rolename": "openwb-version:5",
7474
"textname": "openWB Versionsnummer",
7575
"textdescription": "Diese Rolle ist ein Platzhalter für die openWB Versionsnummer und wird automatisch aktualisiert. Sie hat keine direkten Berechtigungen.",
7676
"acls": []
@@ -1158,12 +1158,6 @@
11581158
"priority": 0,
11591159
"allow": true
11601160
},
1161-
{
1162-
"acltype": "publishClientSend",
1163-
"topic": "openWB/set/bat/config/bat_control_permitted",
1164-
"priority": 0,
1165-
"allow": true
1166-
},
11671161
{
11681162
"acltype": "publishClientSend",
11691163
"topic": "openWB/set/bat/config/charge_limit",
@@ -1290,12 +1284,6 @@
12901284
"priority": 0,
12911285
"allow": true
12921286
},
1293-
{
1294-
"acltype": "publishClientReceive",
1295-
"topic": "openWB/bat/config/bat_control_permitted",
1296-
"priority": 0,
1297-
"allow": true
1298-
},
12991287
{
13001288
"acltype": "publishClientReceive",
13011289
"topic": "openWB/bat/config/charge_limit",
@@ -2764,6 +2752,19 @@
27642752
"allow": true
27652753
}
27662754
]
2755+
},
2756+
{
2757+
"rolename": "tenant-energy-configuration-access",
2758+
"textname": "Leserechte für Mieterstromdaten",
2759+
"textdescription": "Erlaubt das Empfangen von Mieterstrom Daten.",
2760+
"acls": [
2761+
{
2762+
"acltype": "publishClientReceive",
2763+
"topic": "openWB/system/security/access/TenantEnergyConfiguration",
2764+
"priority": 0,
2765+
"allow": true
2766+
}
2767+
]
27672768
}
27682769
]
27692770
}

packages/control/algorithm/surplus_controlled.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,9 @@ def limit_adjust_current(chargepoint: Chargepoint, new_current: float) -> float:
210210
else:
211211
if new_current < get_medium_charging_current(chargepoint.data.get.currents):
212212
current = get_medium_charging_current(chargepoint.data.get.currents) - MAX_CURRENT
213-
msg = "Fahrzeug lädt (noch) nicht mit dem vorgegebenen Ladestrom."
214213

215214
else:
216215
current = get_medium_charging_current(chargepoint.data.get.currents) + MAX_CURRENT
217-
msg = "Fahrzeug lädt (noch) nicht mit dem vorgegebenen Ladestrom."
218216
chargepoint.set_state_and_log(msg)
219217
return max(current,
220218
chargepoint.data.control_parameter.min_current,

packages/control/bat_all.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,6 @@ class CurrentState(Enum):
7575
@dataclass
7676
class Config:
7777
configured: bool = field(default=False, metadata={"topic": "config/configured"})
78-
bat_control_permitted: bool = field(default=False, metadata={"topic": "config/bat_control_permitted"})
7978
bat_control_activated: bool = field(default=False, metadata={"topic": "config/bat_control_activated"})
8079
power_limit_mode: str = field(default=BatPowerLimitMode.MODE_NO_DISCHARGE.value,
8180
metadata={"topic": "config/power_limit_mode"})
@@ -278,7 +277,7 @@ def _set_bat_power_active_control(self, power):
278277
f"SoC. Eigenregelung des Speichers (ID: {bat_component.component_config.id})"))
279278
else:
280279
# unterhalb des minimal SoC greift die Eigenregelung
281-
# das verhindert Tiefenentladung
280+
# das verhindert Tiefentladung
282281
if bat_component_data.get.soc <= self.data.config.bat_control_min_soc:
283282
power_limit = None
284283
bat_component_data.get.state_str = ("Keine Steuerung - dieser Speicher "
@@ -544,18 +543,14 @@ def get_charge_mode_scheduled(self):
544543
return BatChargeMode.BAT_SELF_REGULATION
545544

546545
def get_power_limit(self):
547-
# Falls kein steuerbarer Speicher installiert ist, der Disclaimer nicht akzeptiert wurde
548-
# oder die aktive Speichersteuerung deaktiviert wurde
546+
# Falls kein steuerbarer Speicher installiert oder die aktive Speichersteuerung deaktiviert ist
549547
if (self.data.get.power_limit_controllable is False or
550-
self.data.config.bat_control_permitted is False or
551548
self.data.config.bat_control_activated is False):
552549
charge_mode = BatChargeMode.BAT_SELF_REGULATION
553550
if self.data.get.power_limit_controllable is False:
554551
log.debug("Speicher-Leistung nicht begrenzen, da keine regelbaren Speicher vorhanden sind.")
555-
elif self.data.config.bat_control_permitted is False:
556-
log.debug("Speicher-Leistung nicht begrenzen, da der aktiven Speichersteuerung nicht zugestimmt wurde.")
557552
elif self.data.config.bat_control_activated is False:
558-
log.debug("Speicher-Leistung nicht begrenzen, da aktive Speichersteuerung deaktiviert wurde.")
553+
log.debug("Speicher-Leistung nicht begrenzen, da aktive Speichersteuerung deaktiviert ist.")
559554
else:
560555
charge_mode = BatChargeMode.BAT_SELF_REGULATION
561556
if self.data.config.power_limit_condition == BatPowerLimitCondition.MANUAL.value:
@@ -584,8 +579,18 @@ def get_power_limit(self):
584579
self.data.set.power_limit = data.data.counter_all_data.data.set.home_consumption * -1
585580
log.debug(f"Speicher-Leistung begrenzen auf {self.data.set.power_limit/1000}kW")
586581
elif self.data.config.power_limit_mode == BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value:
587-
self.data.set.power_limit = data.data.pv_all_data.data.get.power * -1
588-
log.debug(f"Speicher in Höhe des PV-Ertrags laden: {self.data.set.power_limit/1000}kW")
582+
# PV-Überschuss abzüglich Hausverbrauch als Ladeleistung des Speichers nutzen.
583+
# Bei geringem Überschuss wird Hausverbrauch durch Speicher ausgeglichen
584+
pv_power = min(data.data.pv_all_data.data.get.power, 0)
585+
left_pv_power = (pv_power +
586+
data.data.counter_all_data.data.set.home_consumption) * -1
587+
self.data.set.power_limit = left_pv_power
588+
if self.data.set.power_limit > 0:
589+
log.debug("Speicher in Höhe des verbliebenen PV-Überschusses "
590+
f"laden: {self.data.set.power_limit/1000}kW")
591+
else:
592+
log.debug("Speicher Entladen um Hausverbrauch zu decken: "
593+
f"{self.data.set.power_limit/1000}kW")
589594
elif charge_mode == BatChargeMode.BAT_FORCE_CHARGE:
590595
# maximal konfigurierte Ladeleistung des Speichers setzen
591596
max_charge_power_total = 0
@@ -597,8 +602,7 @@ def get_power_limit(self):
597602
self.data.set.power_limit = None
598603
log.debug("Speicher-Leistung nicht begrenzen")
599604

600-
if ((self.data.config.bat_control_permitted is False or
601-
self.data.config.bat_control_activated is False)
605+
if (self.data.config.bat_control_activated is False
602606
and self.data.set.current_state == CurrentState.STARTUP.value):
603607
self.data.set.set_limit = False
604608
elif (self.data.set.current_state == CurrentState.IDLE.value and

packages/control/bat_all_test.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ class BatControlParams:
192192
bat_power: float = -10
193193
bat_soc: float = 50.0
194194
evu_power: float = 200
195+
pv_power: float = -654
195196
bat_control_permitted: bool = True
196197
bat_control_activated: bool = True
197198
max_charge_power: float = 5000
@@ -207,8 +208,6 @@ class BatControlParams:
207208
cases = [
208209
BatControlParams("Speicher nicht regelbar", None, power_limit_controllable=False,
209210
power_limit_mode=BatPowerLimitMode.MODE_NO_DISCHARGE.value),
210-
BatControlParams("Disclaimer nicht akzeptiert", None, bat_control_permitted=False,
211-
power_limit_mode=BatPowerLimitMode.MODE_NO_DISCHARGE.value),
212211
BatControlParams("Speichersteuerung deaktiviert", None, bat_control_activated=False,
213212
power_limit_mode=BatPowerLimitMode.MODE_NO_DISCHARGE.value),
214213
# Manuelle Steuerung
@@ -222,7 +221,7 @@ class BatControlParams:
222221
power_limit_condition=BatPowerLimitCondition.MANUAL.value,
223222
bat_manual_mode=ManualMode.MANUAL_LIMIT.value,
224223
power_limit_mode=BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value),
225-
BatControlParams("Manuelle Steuerung, Ladung PV Überschuss", 654,
224+
BatControlParams("Manuelle Steuerung, Ladung PV Überschuss", 198,
226225
power_limit_condition=BatPowerLimitCondition.MANUAL.value,
227226
bat_manual_mode=ManualMode.MANUAL_LIMIT.value,
228227
power_limit_mode=BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value),
@@ -240,15 +239,17 @@ class BatControlParams:
240239
power_limit_mode=BatPowerLimitMode.MODE_NO_DISCHARGE.value),
241240
BatControlParams("Fahrzeuge laden, Begrenzung Hausverbrauch", -456,
242241
power_limit_mode=BatPowerLimitMode.MODE_DISCHARGE_HOME_CONSUMPTION.value),
243-
BatControlParams("Fahrzeuge laden, Ladung PV Überschuss", 654,
242+
BatControlParams("Fahrzeuge laden, Ladung PV Überschuss", 198,
244243
power_limit_mode=BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value),
244+
BatControlParams("Fahrzeuge laden, Ladung PV Überschuss, Eigenverbrauch PV-Anlage", -456,
245+
power_limit_mode=BatPowerLimitMode.MODE_CHARGE_PV_PRODUCTION.value,
246+
pv_power=100),
245247
]
246248

247249

248250
@pytest.mark.parametrize("params", cases, ids=[c.name for c in cases])
249251
def test_active_bat_control(params: BatControlParams, data_, monkeypatch):
250252
b_all = BatAll()
251-
b_all.data.config.bat_control_permitted = params.bat_control_permitted
252253
b_all.data.config.bat_control_activated = params.bat_control_activated
253254
b_all.data.config.power_limit_mode = params.power_limit_mode
254255
b_all.data.config.power_limit_condition = params.power_limit_condition
@@ -265,7 +266,7 @@ def test_active_bat_control(params: BatControlParams, data_, monkeypatch):
265266
# b_all.data.get.soc = 50.0
266267
data.data.counter_all_data = hierarchy_standard()
267268
data.data.counter_all_data.data.set.home_consumption = 456
268-
data.data.pv_all_data.data.get.power = -654
269+
data.data.pv_all_data.data.get.power = params.pv_power
269270
data.data.cp_all_data.data.get.power = 1400
270271
data.data.counter_data["counter0"].data.get.power = params.evu_power
271272
data.data.bat_all_data = b_all
@@ -300,7 +301,7 @@ def test_active_bat_control(params: BatControlParams, data_, monkeypatch):
300301
price_limit_activated=True,
301302
price_limit=0.30,
302303
power_limit_mode=BatPowerLimitMode.MODE_NO_DISCHARGE.value),
303-
BatControlParams("Preisgrenze, Überschuss Laden, Grenze unterschritten", 654,
304+
BatControlParams("Preisgrenze, Überschuss Laden, Grenze unterschritten", 198,
304305
power_limit_condition=BatPowerLimitCondition.PRICE_LIMIT.value,
305306
price_limit_activated=True,
306307
price_limit=0.30,
@@ -330,7 +331,6 @@ def test_active_bat_control(params: BatControlParams, data_, monkeypatch):
330331
def test_control_price_limit(params: BatControlParams, data_, monkeypatch):
331332
monkeypatch.setattr(data.data.optional_data, "ep_get_current_price", Mock(return_value=0.2))
332333
b_all = BatAll()
333-
b_all.data.config.bat_control_permitted = params.bat_control_permitted
334334
b_all.data.config.bat_control_activated = params.bat_control_activated
335335
b_all.data.config.power_limit_mode = params.power_limit_mode
336336
b_all.data.config.power_limit_condition = params.power_limit_condition

packages/control/chargepoint/chargepoint.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@ def _process_charge_stop(self) -> None:
184184
self.data.set.ocpp_transaction_id,
185185
self.data.set.rfid)
186186
self.data.set.ocpp_transaction_id = None
187+
# muss vor dem Zurücksetzen der control parameter aufgerufen werden
188+
self.data.set.charging_ev_data.reset_phase_switch(self.data.control_parameter)
189+
self.data.set.charging_ev_data.reset_phase_switch_delay(self.data.control_parameter, self.get_max_phase_hw())
187190
self.reset_control_parameter_at_charge_stop()
188191
data.data.counter_all_data.get_evu_counter().reset_switch_on_off(self)
189192
if self.data.get.plug_state is False and self.data.set.plug_state_prev is True:
@@ -666,7 +669,7 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
666669

667670
if self.chargemode_changed or self.submode_changed:
668671
data.data.counter_all_data.get_evu_counter().reset_switch_on_off(self)
669-
charging_ev.reset_phase_switch(self.data.control_parameter)
672+
charging_ev.reset_phase_switch_delay(self.data.control_parameter, self.get_max_phase_hw())
670673
if self.chargemode_changed:
671674
self.data.control_parameter.failed_phase_switches = 0
672675
message = message_ev if message_ev else message

packages/control/ev/charge_template.py

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -417,41 +417,44 @@ def _calc_remaining_time(self,
417417
charging_type: str,
418418
control_parameter_phases: int,
419419
soc_request_interval_offset: int,
420-
bidi_state: BidiState) -> SelectedPlan:
420+
bidi_state: BidiState) -> Tuple[float, float, int, float]:
421421
bidi = bidi_state == BidiState.BIDI_CAPABLE and plan.bidi_charging_enabled
422+
battery_capacity = ev_template.data.battery_capacity
423+
efficiency = ev_template.data.efficiency
424+
425+
def calc_for_phases(phases_to_use: int) -> Tuple[float, float]:
426+
return self._calculate_duration(
427+
plan,
428+
soc,
429+
battery_capacity,
430+
efficiency,
431+
used_amount,
432+
phases_to_use,
433+
charging_type,
434+
ev_template,
435+
bidi)
436+
422437
if bidi:
423-
duration, missing_amount = self._calculate_duration(
424-
plan, soc, ev_template.data.battery_capacity,
425-
used_amount, control_parameter_phases, charging_type, ev_template, bidi)
438+
duration, missing_amount = calc_for_phases(control_parameter_phases)
426439
remaining_time = plan_end_time - duration
427440
phases = control_parameter_phases
428441
elif plan.phases_to_use == 0:
429442
if max_hw_phases == 1:
430-
duration, missing_amount = self._calculate_duration(
431-
plan, soc, ev_template.data.battery_capacity,
432-
used_amount, 1, charging_type, ev_template, bidi)
443+
duration, missing_amount = calc_for_phases(1)
433444
remaining_time = plan_end_time - duration
434445
phases = 1
435446
elif phase_switch_supported is False:
436-
duration, missing_amount = self._calculate_duration(
437-
plan, soc, ev_template.data.battery_capacity, used_amount, control_parameter_phases,
438-
charging_type, ev_template, bidi)
447+
duration, missing_amount = calc_for_phases(control_parameter_phases)
439448
phases = control_parameter_phases
440449
remaining_time = plan_end_time - duration
441450
elif plan.et_active:
442-
duration, missing_amount = self._calculate_duration(
443-
plan, soc, ev_template.data.battery_capacity, used_amount, max_hw_phases,
444-
charging_type, ev_template, bidi)
451+
duration, missing_amount = calc_for_phases(max_hw_phases)
445452
phases = max_hw_phases
446453
remaining_time = plan_end_time - duration
447454
else:
448-
duration_3p, missing_amount = self._calculate_duration(
449-
plan, soc, ev_template.data.battery_capacity, used_amount, max_hw_phases,
450-
charging_type, ev_template, bidi)
455+
duration_3p, missing_amount = calc_for_phases(max_hw_phases)
451456
remaining_time_3p = plan_end_time - duration_3p
452-
duration_1p, missing_amount = self._calculate_duration(
453-
plan, soc, ev_template.data.battery_capacity, used_amount, 1,
454-
charging_type, ev_template, bidi)
457+
duration_1p, missing_amount = calc_for_phases(1)
455458
remaining_time_1p = plan_end_time - duration_1p
456459
# Kurz vor dem nächsten Abfragen des SoC, wenn noch der alte SoC da ist, kann es sein, dass die Zeit
457460
# für 1p nicht mehr reicht, weil die Regelung den neuen SoC noch nicht kennt.
@@ -466,11 +469,9 @@ def _calc_remaining_time(self,
466469
phases = 1
467470
log.debug(f"Dauer 1p: {duration_1p}, Dauer 3p: {duration_3p}")
468471
elif plan.phases_to_use == 3 or plan.phases_to_use == 1:
469-
duration, missing_amount = self._calculate_duration(
470-
plan, soc, ev_template.data.battery_capacity,
471-
used_amount, min(plan.phases_to_use, max_hw_phases), charging_type, ev_template, bidi)
472+
phases = min(plan.phases_to_use, max_hw_phases)
473+
duration, missing_amount = calc_for_phases(phases)
472474
remaining_time = plan_end_time - duration
473-
phases = plan.phases_to_use
474475

475476
log.debug(f"Verbleibende Zeit bis zum Ladestart [s]:{remaining_time}, Dauer [h]: {duration/3600}")
476477
return remaining_time, missing_amount, phases, duration
@@ -479,6 +480,7 @@ def _calculate_duration(self,
479480
plan: ScheduledChargingPlan,
480481
soc: Optional[float],
481482
battery_capacity: float,
483+
efficiency: float,
482484
used_amount: float,
483485
phases: int,
484486
charging_type: str,
@@ -487,7 +489,7 @@ def _calculate_duration(self,
487489

488490
if plan.limit.selected == "soc":
489491
if soc is not None:
490-
missing_amount = ((plan.limit.soc_scheduled - soc) / 100) * battery_capacity
492+
missing_amount = ((plan.limit.soc_scheduled - soc) / 100) * battery_capacity / (efficiency / 100)
491493
else:
492494
raise ValueError("Um Zielladen mit SoC-Ziel nutzen zu können, bitte ein SoC-Modul konfigurieren.")
493495
else:

packages/control/ev/charge_template_test.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ def test_calc_remaining_time(phases_to_use,
169169
@pytest.mark.parametrize(
170170
"selected, phases, bidi_charging_enabled, expected_duration, expected_missing_amount",
171171
[
172-
pytest.param("soc", 1, False, 10062.111801242236, 9000, id="soc, one phase"),
172+
pytest.param("soc", 1, False, 11180.124223602485, 10000, id="soc, one phase"),
173173
pytest.param("amount", 2, False, 447.2049689440994, 800, id="amount, two phases"),
174-
pytest.param("soc", 2, True, 3240.0, 9000, id="bidi"),
174+
pytest.param("soc", 2, True, 3600.0, 10000, id="bidi"),
175175
])
176176
def test_calculate_duration(selected: str,
177177
phases: int,
@@ -184,7 +184,7 @@ def test_calculate_duration(selected: str,
184184
plan.limit.selected = selected
185185
# execution
186186
duration, missing_amount = ct._calculate_duration(
187-
plan, 60, 45000, 200, phases, ChargingType.AC.value, EvTemplate(), bidi_charging_enabled)
187+
plan, 60, 45000, 90, 200, phases, ChargingType.AC.value, EvTemplate(), bidi_charging_enabled)
188188

189189
# evaluation
190190
assert duration == expected_duration

0 commit comments

Comments
 (0)