Skip to content

Commit

Permalink
Phasenumschaltung unter Beachtung der Schieflast (#1121)
Browse files Browse the repository at this point in the history
* move control parameter to Chargepoint class

* draft

* fix test

* fix
  • Loading branch information
LKuemmel authored Oct 17, 2023
1 parent 70475f3 commit cf73077
Show file tree
Hide file tree
Showing 12 changed files with 46 additions and 27 deletions.
1 change: 1 addition & 0 deletions packages/control/algorithm/additional_current.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def set_additional_current(self, mode_range: List[int]) -> None:
cp = preferenced_chargepoints[0]
missing_currents, counts = common.get_missing_currents_left(preferenced_chargepoints)
available_currents, limit = Loadmanagement().get_available_currents(missing_currents, counter)
cp.data.control_parameter.limit = limit
available_for_cp = common.available_current_for_cp(cp, counts, available_currents, missing_currents)
current = common.get_current_to_set(
cp.data.set.current, available_for_cp, cp.data.set.target_current)
Expand Down
3 changes: 2 additions & 1 deletion packages/control/algorithm/algorithm.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ def _check_auto_phase_switch_delay(self) -> None:
cp.data.get.currents,
cp.data.get.power,
cp.template.data.max_current_single_phase,
cp.get_max_phase_hw())
cp.get_max_phase_hw(),
cp.data.control_parameter.limit)
if message is not None:
cp.data.get.state_str = message
# Nachdem im Automatikmodus die Anzahl Phasen bekannt ist, Einhaltung des Maximalstroms
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from control.chargemode import Chargemode
from control import data
from control.algorithm.algorithm import Algorithm
from control.loadmanagement import LimitingValue
from control.limiting_value import LimitingValue
from dataclass_utils.factories import currents_list_factory


Expand Down Expand Up @@ -88,7 +88,8 @@ class ParamsLimit(ParamsExpectedSetCurrent, ParamsExpectedCounterSet):
raw_power_left=21310,
raw_currents_left_counter0=[14, 30, 31],
raw_currents_left_counter6=[16, 12, 14],
expected_state_str=LimitingValue.CURRENT,
expected_state_str=(f"Es kann nicht mit der vorgegebenen Stromstärke geladen werden"
f"{LimitingValue.CURRENT.value.format('Garage')}"),
expected_current_cp3=14,
expected_current_cp4=12,
expected_current_cp5=14,
Expand All @@ -97,15 +98,16 @@ class ParamsLimit(ParamsExpectedSetCurrent, ParamsExpectedCounterSet):
expected_raw_currents_left_counter6=[16, 0, 0]),
ParamsLimit(name="limit by power",
raw_power_left=5520,
raw_currents_left_counter0=[14, 30, 31],
raw_currents_left_counter6=[16, 12, 14],
expected_state_str=LimitingValue.POWER,
expected_current_cp3=10.333333333333334,
expected_current_cp4=6.833333333333333,
expected_current_cp5=6.833333333333333,
raw_currents_left_counter0=[32]*3,
raw_currents_left_counter6=[16]*3,
expected_state_str=(f"Es kann nicht mit der vorgegebenen Stromstärke geladen werden"
f"{LimitingValue.POWER.value.format('Garage')}"),
expected_current_cp3=10.461538461538462,
expected_current_cp4=6.769230769230769,
expected_current_cp5=6.769230769230769,
expected_raw_power_left=0,
expected_raw_currents_left_counter0=[3.666666666666666, 23.166666666666668, 24.166666666666668],
expected_raw_currents_left_counter6=[16, 5.166666666666667, 7.166666666666667]),
expected_raw_currents_left_counter0=[21.53846153846154, 25.23076923076923, 25.23076923076923],
expected_raw_currents_left_counter6=[16, 9.23076923076923, 9.23076923076923]),
# limit by unbalanced load
]

Expand All @@ -125,8 +127,7 @@ def test_instant_charging_limit(params: ParamsLimit, all_cp_instant_charging_1p,
assert_expected_current(params)
for i in range(3, 6):
assert data.data.cp_data[
f"cp{i}"].data.get.state_str == (f"Es kann nicht mit der vorgegebenen Stromstärke geladen werden"
f"{params.expected_state_str.value.format('Garage')}")
f"cp{i}"].data.get.state_str.replace("\n", "") == params.expected_state_str.replace("\n", "")
assert_counter_set(params)


Expand Down
1 change: 1 addition & 0 deletions packages/control/algorithm/min_current.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def set_min_current(self) -> None:
missing_currents, counts = common.get_min_current(cp)
if max(missing_currents) > 0:
available_currents, limit = Loadmanagement().get_available_currents(missing_currents, counter)
cp.data.control_parameter.limit = limit
available_for_cp = common.available_current_for_cp(
cp, counts, available_currents, missing_currents)
current = common.get_current_to_set(
Expand Down
1 change: 1 addition & 0 deletions packages/control/algorithm/surplus_controlled.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def _set(self,
available_currents, limit = Loadmanagement().get_available_currents_surplus(missing_currents,
counter,
feed_in_yield)
cp.data.control_parameter.limit = limit
available_for_cp = common.available_current_for_cp(cp, counts, available_currents, missing_currents)
current = common.get_current_to_set(cp.data.set.current, available_for_cp, cp.data.set.target_current)
self._set_loadmangement_message(current, limit, cp, counter)
Expand Down
3 changes: 2 additions & 1 deletion packages/control/auto_phase_switch_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ def test_auto_phase_switch(monkeypatch, vehicle: Ev, params: Params):
params.get_currents,
params.get_power,
32,
3)
3,
None)

# evaluation
assert phases_to_use == params.expected_phases_to_use
Expand Down
5 changes: 4 additions & 1 deletion packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,10 @@ def __init__(self, index: int, event: Optional[threading.Event]):
def set_state_and_log(self, message: str) -> None:
if message:
log.info(f"LP {self.num}: {message}")
self.data.get.state_str = message
if self.data.get.state_str is None:
self.data.get.state_str = message
elif message not in self.data.get.state_str:
self.data.get.state_str += f" {message}"

def _is_grid_protection_inactive(self) -> Tuple[bool, Optional[str]]:
""" prüft, ob der Netzschutz inaktiv ist oder ob alle Ladepunkt gestoppt werden müssen.
Expand Down
4 changes: 4 additions & 0 deletions packages/control/chargepoint/control_parameter.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from control.chargepoint.chargepoint_state import ChargepointState
from control.chargemode import Chargemode as Chargemode_enum
from control.limiting_value import LimitingValue
from dataclass_utils.factories import currents_list_factory


Expand All @@ -20,6 +21,9 @@ class ControlParameter:
imported_instant_charging: Optional[float] = field(
default=None,
metadata={"topic": "control_parameter/imported_instant_charging", "mutable_by_algorithm": True})
limit: Optional[LimitingValue] = field(
default=None,
metadata={"topic": "control_parameter/limit", "mutable_by_algorithm": True})
phases: int = field(
default=0,
metadata={"topic": "control_parameter/phases", "mutable_by_algorithm": True})
Expand Down
14 changes: 9 additions & 5 deletions packages/control/ev.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from control.bat_all import SwitchOnBatState
from control.chargepoint.chargepoint_state import ChargepointState, PHASE_SWITCH_STATES
from control.chargepoint.control_parameter import ControlParameter
from control.limiting_value import LimitingValue
from dataclass_utils.factories import empty_dict_factory, empty_list_factory
from helpermodules.abstract_plans import Limit, limit_factory, ScheduledChargingPlan, TimeChargingPlan
from helpermodules import timecheck
Expand Down Expand Up @@ -365,7 +366,8 @@ def _check_phase_switch_conditions(self,
control_parameter: ControlParameter,
get_currents: List[float],
get_power: float,
max_current_cp: int) -> Tuple[bool, Optional[str]]:
max_current_cp: int,
limit: LimitingValue) -> Tuple[bool, Optional[str]]:
# Manche EV laden mit 6.1A bei 6A Sollstrom
min_current = self.ev_template.data.min_current + self.ev_template.data.nominal_difference
max_current = (min(self.ev_template.data.max_current_single_phase, max_current_cp)
Expand All @@ -381,9 +383,9 @@ def _check_phase_switch_conditions(self,
# verbleibender EVU-Überschuss unter Berücksichtigung der Einspeisegrenze und Speicherleistung
all_surplus = (-evu_counter.calc_surplus() - evu_counter.data.set.released_surplus +
evu_counter.data.set.reserved_surplus - feed_in_yield)
condition_1_to_3 = (max(get_currents) > max_current and
condition_1_to_3 = (((max(get_currents) > max_current and
all_surplus > self.ev_template.data.min_current * max_phases_ev * 230
- get_power and
- get_power) or limit == LimitingValue.UNBALANCED_LOAD.value) and
phases_in_use == 1)
condition_3_to_1 = max(get_currents) < min_current and all_surplus <= 0 and phases_in_use > 1
if condition_1_to_3 or condition_3_to_1:
Expand All @@ -404,7 +406,8 @@ def auto_phase_switch(self,
get_currents: List[float],
get_power: float,
max_current_cp: int,
max_phases: int) -> Tuple[int, float, Optional[str]]:
max_phases: int,
limit: LimitingValue) -> Tuple[int, float, Optional[str]]:
message = None
current = control_parameter.required_current
timestamp_auto_phase_switch = control_parameter.timestamp_auto_phase_switch
Expand Down Expand Up @@ -442,7 +445,8 @@ def auto_phase_switch(self,
condition, condition_msg = self._check_phase_switch_conditions(control_parameter,
get_currents,
get_power,
max_current_cp)
max_current_cp,
limit)
if control_parameter.state not in PHASE_SWITCH_STATES:
if condition:
# Umschaltverzögerung starten
Expand Down
7 changes: 7 additions & 0 deletions packages/control/limiting_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from enum import Enum


class LimitingValue(Enum):
CURRENT = ", da der Maximal-Strom an Zähler {} erreicht ist."
POWER = ", da die maximale Leistung an Zähler {} erreicht ist."
UNBALANCED_LOAD = ", da die maximale Schieflast an Zähler {} erreicht ist."
8 changes: 1 addition & 7 deletions packages/control/loadmanagement.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
from enum import Enum
import logging
import operator
from typing import List, Optional, Tuple

from control import data
from control.counter import Counter
from control.limiting_value import LimitingValue


log = logging.getLogger(__name__)


class LimitingValue(Enum):
CURRENT = ", da der Maximal-Strom an Zähler {} erreicht ist."
POWER = ", da die maximale Leistung an Zähler {} erreicht ist."
UNBALANCED_LOAD = ", da die maximale Schieflast an Zähler {} erreicht ist."


class Loadmanagement:
def get_available_currents(self,
missing_currents: List[float],
Expand Down
1 change: 1 addition & 0 deletions packages/helpermodules/setdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,7 @@ def process_chargepoint_topic(self, msg: mqtt.MQTTMessage):
elif "/control_parameter/phases" in msg.topic:
self._validate_value(msg, int, [(0, 3)])
elif ("/control_parameter/submode" in msg.topic or
"/control_parameter/limit" in msg.topic or
"/control_parameter/chargemode" in msg.topic):
self._validate_value(msg, str)
elif "/control_parameter/prio" in msg.topic:
Expand Down

0 comments on commit cf73077

Please sign in to comment.