Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions packages/control/algorithm/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from control import data
from control.algorithm.filter_chargepoints import get_chargepoints_by_mode
from control.algorithm.utils import get_medium_charging_current
from control.chargepoint.chargepoint import Chargepoint
from control.counter import Counter
from helpermodules.timecheck import check_timestamp
Expand Down Expand Up @@ -73,9 +74,9 @@ def set_current_counterdiff(diff_curent: float,
counters = data.data.counter_all_data.get_counters_to_check(chargepoint.num)
for counter in counters:
if surplus:
data.data.counter_data[counter].update_surplus_values_left(diffs)
data.data.counter_data[counter].update_surplus_values_left(diffs, chargepoint.data.get.voltages)
else:
data.data.counter_data[counter].update_values_left(diffs)
data.data.counter_data[counter].update_values_left(diffs, chargepoint.data.get.voltages)
data.data.io_actions.dimming_set_import_power_left({"type": "cp", "id": chargepoint.num}, sum(diffs)*230)

chargepoint.data.set.current = current
Expand Down Expand Up @@ -145,21 +146,22 @@ def update_raw_data(preferenced_chargepoints: List[Chargepoint],
counters = data.data.counter_all_data.get_counters_to_check(chargepoint.num)
for counter in counters:
if surplus:
data.data.counter_data[counter].update_surplus_values_left(diffs)
data.data.counter_data[counter].update_surplus_values_left(diffs, chargepoint.data.get.voltages)
else:
data.data.counter_data[counter].update_values_left(diffs)
data.data.counter_data[counter].update_values_left(diffs, chargepoint.data.get.voltages)
data.data.io_actions.dimming_set_import_power_left({"type": "cp", "id": chargepoint.num}, sum(diffs)*230)


def consider_less_charging_chargepoint_in_loadmanagement(cp: Chargepoint, set_current: float) -> bool:
if (data.data.counter_all_data.data.config.consider_less_charging is False and
((set_current -
cp.data.set.charging_ev_data.ev_template.data.nominal_difference) > max(cp.data.get.currents) and
cp.data.set.charging_ev_data.ev_template.data.nominal_difference) > get_medium_charging_current(
cp.data.get.currents) and
cp.data.control_parameter.timestamp_charge_start is not None and
check_timestamp(cp.data.control_parameter.timestamp_charge_start, LESS_CHARGING_TIMEOUT) is False)):
log.debug(
f"LP {cp.num} lädt deutlich unter dem Sollstrom und wird nur mit {cp.data.get.currents}A berücksichtigt.")
return max(cp.data.get.currents)
return get_medium_charging_current(cp.data.get.currents)
else:
return set_current
# tested
Expand Down
15 changes: 9 additions & 6 deletions packages/control/algorithm/surplus_controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from control.algorithm.filter_chargepoints import (get_chargepoints_by_chargemodes,
get_chargepoints_by_mode_and_counter,
get_preferenced_chargepoint_charging)
from control.algorithm.utils import get_medium_charging_current
from control.chargepoint.charging_type import ChargingType
from control.chargepoint.chargepoint import Chargepoint
from control.chargepoint.chargepoint_state import ChargepointState, CHARGING_STATES
Expand Down Expand Up @@ -52,6 +53,7 @@ def _set(self,
cp = chargepoints[0]
missing_currents, counts = common.get_missing_currents_left(chargepoints)
available_currents, limit = Loadmanagement().get_available_currents_surplus(missing_currents,
cp.data.get.voltages,
counter,
cp,
feed_in=feed_in_yield)
Expand All @@ -63,7 +65,8 @@ def _set(self,
# Wenn die Differenz zwischen altem und neuem Soll-Strom größer als der Regelbereich ist, trotzdem
# nachregeln, auch wenn der Regelbereich eingehalten wird. Sonst würde zB nicht berücksichtigt werden,
# wenn noch ein Fahrzeug dazu kommmt.
if (pv_charging.control_range[1] - pv_charging.control_range[0]) / 230 < abs(dif_to_old_current):
if ((pv_charging.control_range[1] - pv_charging.control_range[0]) /
(sum(counter.data.get.voltages) / len(counter.data.get.voltages)) < abs(dif_to_old_current)):
current = available_for_cp
else:
# Nicht mehr freigeben, wie das Lastmanagement vorgibt
Expand Down Expand Up @@ -115,16 +118,16 @@ def _limit_adjust_current(self, chargepoint: Chargepoint, new_current: float) ->
else:
# Um max. +/- 5A pro Zyklus regeln
if (-MAX_CURRENT-nominal_difference
< new_current - max(chargepoint.data.get.currents)
< new_current - get_medium_charging_current(chargepoint.data.get.currents)
< MAX_CURRENT+nominal_difference):
current = new_current
else:
if new_current < max(chargepoint.data.get.currents):
current = max(chargepoint.data.get.currents) - MAX_CURRENT
if new_current < get_medium_charging_current(chargepoint.data.get.currents):
current = get_medium_charging_current(chargepoint.data.get.currents) - MAX_CURRENT
msg = f"Es darf um max {MAX_CURRENT}A unter den aktuell genutzten Strom geregelt werden."

else:
current = max(chargepoint.data.get.currents) + MAX_CURRENT
current = get_medium_charging_current(chargepoint.data.get.currents) + MAX_CURRENT
msg = f"Es darf um max {MAX_CURRENT}A über den aktuell genutzten Strom geregelt werden."
chargepoint.set_state_and_log(msg)
return max(current,
Expand All @@ -139,7 +142,7 @@ def _fix_deviating_evse_current(self, chargepoint: Chargepoint) -> float:
Wenn die Soll-Stromstärke nicht angepasst worden ist, nicht den ungenutzten EVSE-Strom aufschlagen."""
evse_current = chargepoint.data.get.evse_current
if evse_current and chargepoint.data.set.current != chargepoint.data.set.current_prev:
offset = evse_current - max(chargepoint.data.get.currents)
offset = evse_current - get_medium_charging_current(chargepoint.data.get.currents)
current_with_offset = chargepoint.data.set.current + offset
current = min(current_with_offset, chargepoint.data.control_parameter.required_current)
if current != chargepoint.data.set.current:
Expand Down
10 changes: 10 additions & 0 deletions packages/control/algorithm/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from typing import List


def get_medium_charging_current(currents: List[float]) -> float:
"""Ermittelt den mittleren Ladestrom der Phasen, auf denen geladen wird.
"""
if any(x >= 0.5 for x in currents):
return sum(x for x in currents if x >= 0.5) / len([x for x in currents if x >= 0.5])
else:
return 0.0
6 changes: 4 additions & 2 deletions packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import traceback
from typing import Dict, Optional, Tuple

from control.algorithm.utils import get_medium_charging_current
from control.chargelog import chargelog
from control import data
from control.chargemode import Chargemode
Expand Down Expand Up @@ -598,7 +599,8 @@ def set_required_currents(self, required_current: float) -> None:
self.set_state_and_log("Bitte in den Ladepunkt-Einstellungen die Einstellung 'Phase 1 des Ladekabels'" +
" angeben. Andernfalls wird der benötigte Strom auf allen 3 Phasen vorgehalten, " +
"was ggf eine unnötige Reduktion der Ladeleistung zur Folge hat.")
self.data.set.required_power = sum(control_parameter.required_currents) * 230
self.data.set.required_power = sum(
[c * v for c, v in zip(control_parameter.required_currents, self.data.get.voltages)])

def set_timestamp_charge_start(self):
# Beim Ladestart Timer laufen lassen, manche Fahrzeuge brauchen sehr lange.
Expand Down Expand Up @@ -696,7 +698,7 @@ def update(self, ev_list: Dict[str, Ev]) -> None:
f"{self.data.control_parameter.submode}, Phasen: "
f"{self.data.control_parameter.phases}"
f", Priorität: {charging_ev.charge_template.data.prio}"
f", max. Ist-Strom: {max(self.data.get.currents)}")
f", mittlerer Ist-Strom: {get_medium_charging_current(self.data.get.currents)}")
except Exception:
log.exception("Fehler im Prepare-Modul für Ladepunkt "+str(self.num))
self.data.control_parameter.submode = "stop"
Expand Down
13 changes: 7 additions & 6 deletions packages/control/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from typing import List, Optional, Tuple

from control import data
from control.algorithm.utils import get_medium_charging_current
from control.chargemode import Chargemode
from control.ev.ev import Ev
from control.chargepoint.chargepoint import Chargepoint
Expand Down Expand Up @@ -150,7 +151,7 @@ def _set_current_left(self, loadmanagement_available: bool) -> None:
chargepoint.data.config.phase_1,
chargepoint.data.get.currents)
except KeyError:
element_current = [max(chargepoint.data.get.currents)]*3
element_current = [get_medium_charging_current(chargepoint.data.get.currents)]*3
currents_raw = list(map(operator.sub, currents_raw, element_current))
currents_raw = list(map(operator.sub, self.data.config.max_currents, currents_raw))
if min(currents_raw) < 0:
Expand Down Expand Up @@ -191,17 +192,17 @@ def _set_power_left(self, loadmanagement_available: bool) -> None:
else:
self.data.set.raw_power_left = None

def update_values_left(self, diffs) -> None:
def update_values_left(self, diffs, cp_voltages: List[float]) -> 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
self.data.set.raw_power_left -= sum([c * v for c, v in zip(diffs, cp_voltages)])
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:
def update_surplus_values_left(self, diffs, cp_voltages: List[float]) -> 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
self.data.set.surplus_power_left -= sum([c * v for c, v in zip(diffs, cp_voltages)])
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')

Expand Down Expand Up @@ -441,7 +442,7 @@ def switch_off_check_threshold(self, chargepoint: Chargepoint) -> bool:
# Einen nach dem anderen abschalten, bis Ladeleistung des Speichers erreicht ist
# und wieder eingespeist wird.
self.data.set.reserved_surplus == 0))
if switch_off_condition and max(chargepoint.data.get.currents) <= min_current:
if switch_off_condition and get_medium_charging_current(chargepoint.data.get.currents) <= min_current:
if not charging_ev_data.ev_template.data.prevent_charge_stop:
# EV, die ohnehin nicht laden, wird direkt die Ladefreigabe entzogen.
# Würde man required_power vom released_evu_surplus subtrahieren, würden keine anderen EVs
Expand Down
10 changes: 6 additions & 4 deletions packages/control/ev/ev.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from typing import List, Optional, Tuple

from control import data
from control.algorithm.utils import get_medium_charging_current
from control.chargepoint.chargepoint_state import ChargepointState, PHASE_SWITCH_STATES
from control.chargepoint.charging_type import ChargingType
from control.chargepoint.control_parameter import ControlParameter
Expand Down Expand Up @@ -309,10 +310,11 @@ def _check_phase_switch_conditions(self,
all_surplus = data.data.counter_all_data.get_evu_counter().get_usable_surplus(feed_in_yield)
required_surplus = control_parameter.min_current * max_phases_ev * 230 - get_power
unblanced_load_limit_reached = limit.limiting_value == LimitingValue.UNBALANCED_LOAD
condition_1_to_3 = (((max(get_currents) > max_current and
condition_1_to_3 = (((get_medium_charging_current(get_currents) > max_current and
all_surplus > required_surplus) or unblanced_load_limit_reached) and
phases_in_use == 1)
condition_3_to_1 = max(get_currents) < min_current and all_surplus <= 0 and phases_in_use > 1
condition_3_to_1 = get_medium_charging_current(
get_currents) < min_current and all_surplus <= 0 and phases_in_use > 1
if condition_1_to_3 or condition_3_to_1:
return True, None
else:
Expand Down Expand Up @@ -361,8 +363,8 @@ def auto_phase_switch(self,
new_current = self.ev_template.data.max_current_single_phase

log.debug(
f'Genutzter Strom: {max(get_currents)}A, Überschuss: {all_surplus}W, benötigte neue Leistung: '
f'{required_reserved_power}W')
f'Genutzter Strom: {get_medium_charging_current(get_currents)}A, Überschuss: {all_surplus}W, benötigte '
f'neue Leistung: {required_reserved_power}W')
# Wenn gerade umgeschaltet wird, darf kein Timer gestartet werden.
if not self.ev_template.data.prevent_phase_switch:
condition, condition_msg = self._check_phase_switch_conditions(control_parameter,
Expand Down
10 changes: 6 additions & 4 deletions packages/control/loadmanagement.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def get_available_currents(self,
limit = new_limit if new_limit.limiting_value is not None else limit

available_currents, new_limit = self._limit_by_power(
counter, available_currents, counter.data.set.raw_power_left, feed_in)
counter, available_currents, cp.data.get.voltages, counter.data.set.raw_power_left, feed_in)
limit = new_limit if new_limit.limiting_value is not None else limit

if f"counter{counter.num}" == data.data.counter_all_data.get_evu_counter_str():
Expand All @@ -47,6 +47,7 @@ def get_available_currents(self,

def get_available_currents_surplus(self,
missing_currents: List[float],
cp_voltages: List[float],
counter: Counter,
cp: Chargepoint,
feed_in: int = 0) -> Tuple[List[float], LoadmanagementLimit]:
Expand All @@ -60,7 +61,7 @@ def get_available_currents_surplus(self,
limit = new_limit if new_limit.limiting_value is not None else limit

available_currents, new_limit = self._limit_by_power(
counter, available_currents, counter.data.set.surplus_power_left, feed_in)
counter, available_currents, cp_voltages, counter.data.set.surplus_power_left, feed_in)
limit = new_limit if new_limit.limiting_value is not None else limit

if f"counter{counter.num}" == data.data.counter_all_data.get_evu_counter_str():
Expand Down Expand Up @@ -93,6 +94,7 @@ def _limit_by_unbalanced_load(self,
def _limit_by_power(self,
counter: Counter,
available_currents: List[float],
cp_voltages: List[float],
raw_power_left: Optional[float],
feed_in: Optional[float]) -> Tuple[List[float], LoadmanagementLimit]:
currents = available_currents.copy()
Expand All @@ -101,10 +103,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([c * v for c, v in zip(available_currents, cp_voltages)]) > 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 / cp_voltages[i]
log.debug(f"Leistungsüberschreitung auf {raw_power_left}W korrigieren: {available_currents}")
limit = LoadmanagementLimit(LimitingValue.POWER.value.format(get_component_name_by_id(counter.num)),
LimitingValue.POWER)
Expand Down
2 changes: 1 addition & 1 deletion packages/control/loadmanagement_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def test_limit_by_power(available_currents: List[float],
counter_name_mock = Mock(return_value=COUNTER_NAME)
monkeypatch.setattr(loadmanagement, "get_component_name_by_id", counter_name_mock)
# evaluation
currents = Loadmanagement()._limit_by_power(Counter(0), available_currents, raw_power_left, None)
currents = Loadmanagement()._limit_by_power(Counter(0), available_currents, [230]*3, raw_power_left, None)

# assertion
assert currents == expected_currents
Expand Down