-
Notifications
You must be signed in to change notification settings - Fork 120
Feature negative dc charging #3795
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 7 commits
6b25cc2
02820e3
bddd3c7
04c0a5f
5d5463d
c77c482
6e52bad
5fe579b
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 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,9 +1,18 @@ | ||||||||||
| import logging | ||||||||||
| from control import data | ||||||||||
| from control.chargemode import Chargemode | ||||||||||
| from control.algorithm.chargemodes import CONSIDERED_CHARGE_MODES_BIDI_DISCHARGE | ||||||||||
| from control.algorithm.filter_chargepoints import get_chargepoints_with_required_current_by_chargemode | ||||||||||
| from helpermodules.phase_handling import voltages_mean | ||||||||||
|
|
||||||||||
| from control.limiting_value import LoadmanagementLimit | ||||||||||
| from control.loadmanagement import Loadmanagement | ||||||||||
|
|
||||||||||
| from control.chargepoint.chargepoint import Chargepoint | ||||||||||
| import control.algorithm.common as common | ||||||||||
| from typing import List | ||||||||||
|
|
||||||||||
|
|
||||||||||
| log = logging.getLogger(__name__) | ||||||||||
|
|
||||||||||
|
|
||||||||||
|
|
@@ -14,33 +23,115 @@ def __init__(self): | |||||||||
| def set_bidi(self): | ||||||||||
| grid_counter = data.data.counter_all_data.get_evu_counter() | ||||||||||
| log.debug(f"Nullpunktanpassung {grid_counter.data.set.surplus_power_left}W") | ||||||||||
| zero_point_adjustment = grid_counter | ||||||||||
| for mode_tuple in CONSIDERED_CHARGE_MODES_BIDI_DISCHARGE: | ||||||||||
| preferenced_cps = get_chargepoints_with_required_current_by_chargemode(mode_tuple) | ||||||||||
| if preferenced_cps: | ||||||||||
| log.info( | ||||||||||
| f"Mode-Tuple {mode_tuple[0]} - {mode_tuple[1]} - {mode_tuple[2]}, Zähler {grid_counter.num}") | ||||||||||
|
|
||||||||||
| while len(preferenced_cps): | ||||||||||
| cp = preferenced_cps[0] | ||||||||||
| zero_point_adjustment = grid_counter.data.set.surplus_power_left / len(preferenced_cps) | ||||||||||
| log.debug(f"Nullpunktanpassung für LP{cp.num}: verbleibende Leistung {zero_point_adjustment}W") | ||||||||||
| missing_currents = [zero_point_adjustment / cp.data.get.phases_in_use / | ||||||||||
| 230 for i in range(0, cp.data.get.phases_in_use)] | ||||||||||
| missing_currents += [0] * (3 - len(missing_currents)) | ||||||||||
| if zero_point_adjustment > 0: | ||||||||||
| if cp.data.set.charging_ev_data.charge_template.bidi_charging_allowed( | ||||||||||
| cp.data.control_parameter.current_plan, cp.data.set.charging_ev_data.data.get.soc): | ||||||||||
| for index in range(0, 3): | ||||||||||
| missing_currents[index] = min(cp.data.control_parameter.required_current, | ||||||||||
| missing_currents[index]) | ||||||||||
| else: | ||||||||||
| log.info(f"LP{cp.num}: Nur bidirektional entladen erlaubt, da SoC-Limit erreicht.") | ||||||||||
| missing_currents = [0, 0, 0] | ||||||||||
| else: | ||||||||||
| for index in range(0, 3): | ||||||||||
| missing_currents[index] = cp.check_min_max_current(missing_currents[index], | ||||||||||
| cp.data.get.phases_in_use) | ||||||||||
| grid_counter.update_surplus_values_left(missing_currents, voltages_mean(cp.data.get.voltages)) | ||||||||||
| cp.data.set.current = missing_currents[0] | ||||||||||
| log.info(f"LP{cp.num}: Stromstärke {missing_currents}A") | ||||||||||
| counts = self.get_counts(cp) | ||||||||||
|
|
||||||||||
| cp.data.set.target_current = 0 | ||||||||||
|
|
||||||||||
| missing_currents = self.get_missing_currents(preferenced_cps, grid_counter) | ||||||||||
| log.debug(f"Bidi-LP{cp.num}: missing currents {missing_currents}A") | ||||||||||
|
|
||||||||||
| counters = data.data.counter_all_data.get_counters_to_check(cp.num) | ||||||||||
| for counter in counters: | ||||||||||
| available_currents, limit = Loadmanagement().get_available_currents_bidi( | ||||||||||
| missing_currents, voltages_mean(cp.data.get.voltages), data.data.counter_data[counter]) | ||||||||||
|
|
||||||||||
| if limit.limiting_value is not None: | ||||||||||
| cp.data.control_parameter.limit = limit | ||||||||||
|
|
||||||||||
| available_for_cp = common.available_current_for_cp( | ||||||||||
| cp, counts, available_currents, missing_currents, bidi_mode=True) | ||||||||||
|
|
||||||||||
| # Der neue Strom darf nicht höher als der bisher gesetzte Strom sein | ||||||||||
| current = common.get_current_to_set( | ||||||||||
| cp.data.set.current, available_for_cp, cp.data.set.target_current) | ||||||||||
|
|
||||||||||
| cp.data.set.current = current | ||||||||||
| log.info(f"LP{cp.num}: Stromstärke {current}A") | ||||||||||
|
|
||||||||||
| # Ausgabe LIMIT-MSG | ||||||||||
| self._set_loadmangement_message(current, limit, cp) | ||||||||||
|
|
||||||||||
| common.set_current_counterdiff(cp.data.set.target_current, current, cp, surplus=True) | ||||||||||
|
|
||||||||||
| preferenced_cps.pop(0) | ||||||||||
|
|
||||||||||
| def _set_loadmangement_message(self, | ||||||||||
| current: float, | ||||||||||
| limit: LoadmanagementLimit, | ||||||||||
| chargepoint: Chargepoint) -> None: | ||||||||||
| # Strom muss an diesem Zähler geändert werden | ||||||||||
| log.debug( | ||||||||||
| f"current {current} target {chargepoint.data.set.target_current} set current {chargepoint.data.set.current}" | ||||||||||
| f" required currents {chargepoint.data.control_parameter.required_currents}") | ||||||||||
| required_currents = chargepoint.data.control_parameter.required_currents | ||||||||||
| required_current = min(required_currents) if current < 0 else max(required_currents) | ||||||||||
| if (limit.message and | ||||||||||
| # Strom erreicht nicht die vorgegebene Stromstärke | ||||||||||
| round(current, 2) != round(required_current, 2)): | ||||||||||
| if current == 0: | ||||||||||
| chargepoint.set_state_and_log(f"Es kann nicht mit der vorgegebenen Stromstärke geladen/entladen werden" | ||||||||||
| f"{limit.message}") | ||||||||||
| elif current < 0: | ||||||||||
| chargepoint.set_state_and_log(f"Es kann nicht mit der vorgegebenen Stromstärke entladen werden" | ||||||||||
| f"{limit.message}") | ||||||||||
| else: | ||||||||||
| chargepoint.set_state_and_log(f"Es kann nicht mit der vorgegebenen Stromstärke geladen werden" | ||||||||||
| f"{limit.message}") | ||||||||||
|
|
||||||||||
| def get_counts(self, chargepoint: Chargepoint) -> List[int]: | ||||||||||
|
|
||||||||||
| counts = [0]*3 | ||||||||||
| required_currents = chargepoint.data.control_parameter.required_currents | ||||||||||
| for i in range(3): | ||||||||||
| if required_currents[i] != 0: | ||||||||||
| counts[i] += 1 | ||||||||||
| return counts | ||||||||||
|
|
||||||||||
| def get_missing_currents(self, preferenced_cps: List[Chargepoint], grid_counter) -> List[float]: | ||||||||||
| cp = preferenced_cps[0] | ||||||||||
| missing_currents = [0, 0, 0] | ||||||||||
| if cp.data.control_parameter.chargemode == Chargemode.INSTANT_CHARGING: | ||||||||||
| # Entladen im Instant-Charging-Modus | ||||||||||
| if cp.data.set.charging_ev_data.data.get.soc > 0: | ||||||||||
| # Auto-bat ist nicht leer | ||||||||||
|
Comment on lines
+103
to
+106
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Ob das Auto leer ist oder aus anderen Gründen die Entladung verweigert (fast leer, Temperatur, etc.) wird ja dadurch abgefangen, dass nur die tatsächlich entladenen Leistung zum Laden von anderen Fahrzeugen verwendet wird. Dann kann diese Restriktion entfallen. |
||||||||||
|
|
||||||||||
| dc_current = cp.data.set.charging_ev_data.charge_template.data.chargemode.instant_charging.dc_current | ||||||||||
| if dc_current < 0: | ||||||||||
| # Phasen in use berücksichtigen | ||||||||||
| missing_currents = [dc_current for i in range(0, cp.data.get.phases_in_use)] | ||||||||||
| missing_currents += [0] * (3 - len(missing_currents)) | ||||||||||
|
|
||||||||||
| for index in range(0, 3): | ||||||||||
| missing_currents[index] = cp.check_min_max_current( | ||||||||||
| missing_currents[index], cp.data.get.phases_in_use) | ||||||||||
|
Comment on lines
+108
to
+116
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Müsste das nicht control_parameter.required_currents entsprechen?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ja das ist genau der Punkt, denn wir schonmal besprochen haben: |
||||||||||
|
|
||||||||||
| else: | ||||||||||
| # Default Nullpunktanpassung | ||||||||||
| zero_point_adjustment = grid_counter.data.set.surplus_power_left / len(preferenced_cps) | ||||||||||
| log.debug(f"Nullpunktanpassung für LP{cp.num}: verbleibende Leistung {zero_point_adjustment}W") | ||||||||||
| missing_currents = [zero_point_adjustment / cp.data.get.phases_in_use / | ||||||||||
| 230 for i in range(0, cp.data.get.phases_in_use)] | ||||||||||
| missing_currents += [0] * (3 - len(missing_currents)) | ||||||||||
| if zero_point_adjustment > 0: | ||||||||||
| if cp.data.set.charging_ev_data.charge_template.bidi_charging_allowed( | ||||||||||
| cp.data.control_parameter.current_plan, cp.data.set.charging_ev_data.data.get.soc): | ||||||||||
| for index in range(0, 3): | ||||||||||
| missing_currents[index] = min(cp.data.control_parameter.required_current, | ||||||||||
| missing_currents[index]) | ||||||||||
| else: | ||||||||||
| log.info(f"LP{cp.num}: Nur bidirektional entladen erlaubt, da SoC-Limit erreicht.") | ||||||||||
| missing_currents = [0, 0, 0] | ||||||||||
| else: | ||||||||||
| for index in range(0, 3): | ||||||||||
| missing_currents[index] = cp.check_min_max_current(missing_currents[index], | ||||||||||
| cp.data.get.phases_in_use) | ||||||||||
|
|
||||||||||
| return missing_currents | ||||||||||
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.
Gibt es einen Grund, dass Du nicht die Methode mode_and_counter_generator verwendest, Die auch min_current,.. verwenden, um über die Zähler zu iterieren?
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.
Wenn ich
mode_and_counter_generatorverwende, schlägt der Testtest_cp3_cp4_bidi_dischargefehl.In dem Test wird geprüft, ob bei mehreren Bidi-CPs (im Zielladen) alle gleichmäßig entladen werden und nicht nur einer und die anderen nicht.
-> Deswegen habe ich das so gelöst. Ich brauche eine Liste mit allen CPs, die sich in diesem Mode befinden, um das Entladen entsprechend aufteilen zu können.