Repository navigation
Conversation
…schalten Wenn der Speicher im Modus "Mindest-SoC des Speichers" oberhalb des Maximal-SoC seine freigegebene Entladeleistung als Ueberschuss anbietet, soll er eine laufende Ueberschuss-Ladung ueber Wolken hinweg stuetzen. Die Regelung arbeitet aber dagegen: - Die Entladeleistung deckt bei mehrphasigem Laden nur einen Teil des Bedarfs, der Ueberschuss ist also <= 0 und damit die Bedingung fuer die Rueckschaltung 3 -> 1 erfuellt. Einphasig ist die Ladeleistung ein Drittel und der Puffer damit wirkungslos. - Ein- und festphasige Ladepunkte haben keine Umschaltung, die greifen koennte; bei ihnen laeuft stattdessen die Abschaltverzoegerung an. BatAll.is_buffering() macht diesen Zustand abfragbar - exakt die Bedingung, unter der get_charging_power_left_diff() die Entladeleistung freigibt. Solange sie wahr ist: - sperrt Ev._check_phase_switch_conditions() die Rueckschaltung 3 -> 1 (die Hochschaltung 1 -> 3 bleibt unberuehrt), - haelt Counter.switch_off_check_threshold() eine tatsaechlich fliessende Ladung gegen die Abschaltschwelle und bricht eine bereits laufende Abschaltverzoegerung ab. Der Mindeststrom selbst ist bereits strukturell gesichert: limit_adjust_current() gibt nie weniger als min_current zurueck. Verbraucher sind nicht betroffen, fuer sie gilt weiterhin die Verbraucher-Abschaltschwelle. Eine Ladung, die noch gar nicht laeuft, startet der Puffer nicht. Co-Authored-By: Claude Opus 5 <[email protected]>
Die Rueckschaltung hat Vorrang vor der Abschaltung: surplus_controlled.py ueberspringt switch_off_check_threshold(), solange phase_switch_necessary() gilt. Diese Bedingung ist rein statisch (HW kann umschalten, aktuell nicht einphasig, Automatikmodus), ein dreiphasiger Automatik-LP erreicht die Abschaltschwelle also nie. Wenn der Puffer leer laeuft, stapeln sich dadurch die Verzoegerungen: fuer 3 -> 1 gilt switch_off_delay, dazu der Puffer phase_switch_delay seit der letzten Umschaltung, und danach wartet die Abschaltschwelle noch einmal switch_off_delay ab. Die Ladung laeuft die ganze Zeit aus dem Netz, waehrend der Speicher sich eigentlich wieder aufladen soll. Unterhalb des Mindest-SoC ist die Rueckschaltung auch nicht die richtige Reaktion: einphasig weiterzuladen konkurriert weiter mit dem Speicher, der dort Vorrang hat. BatAll.is_buffer_depleted() macht diesen Zustand abfragbar; solange er gilt, - unterdrueckt Ev._check_phase_switch_conditions() die Rueckschaltung 3 -> 1, - laesst phase_switch_necessary() die Abschaltschwelle durch. Damit bleibt genau eine switch_off_delay stehen. Erholt sich der Puffer, entscheidet die Einschaltlogik neu, ob ein- oder dreiphasig gestartet wird. Co-Authored-By: Claude Opus 5 <[email protected]>
|
Ich häng mal eine Frage dran, bevor ich in den Code im Detail einsteige: Mit diesem PR haben wir jetzt drei noch offene, sich gegenseitig beeinflussende Änderungen an Das hattest du im Issue ja selbst schon offen gelassen ("Was ich so aus dem FF nicht beurteilen kann ist ob die Änderungen #3986 + #3985 das Auto bei höchstens 6A halten und die 3p->1p Umschaltung unterdrücken solange die Hausbatterie puffert. Das wäre noch zu prüfen.") - und genau da hänge ich mich ein: Ich würde vorschlagen, das erst zu prüfen (#3985/#3986 landen lassen, dann schauen, ob eine sinnvoll abgestimmte Unabhängig vom Timing steht für mich noch eine grundsätzlichere Frage im Raum: Soll dieses Pufferverhalten Teil von Nichts davon ist eine inhaltliche Kritik am Ansatz - dein 4-Schritte-Modell aus dem Issue hat sich bei dir im Betrieb ja klar bewährt. Mir geht's nur um Reihenfolge und darum, dass wir uns nicht in drei überlappenden PRs zum selben Modus verheddern, bevor überhaupt geklärt ist, was der Modus eigentlich leisten soll. |
|
Huch, das ging ja schnell. Kurzum, der Modus soll den Hausakku als Kurzzeitpuffer verwenden. Anstatt der Wartezeiten. Bisher:
Neu:
|
|
Nochmal, diese Funktion ist aber nirgens so dokumentiert/beschrieben das es das tut. Das ist ein Wunsch von dir und daher ist es hier doch erstmal wichtig zu klären ob das der bestehende Modus überhaupt tun soll oder dafür nicht lieber ein neuer Modus implementiert wird. |
|
#3980 ist imho der richtige Ort dafür |
Problem
Im Modus „Mindest-SoC des Speichers" gibt
get_charging_power_left_diff()oberhalb des Maximal-SoC die konfigurierte Entladeleistung als Überschuss frei:Der Zweck ist, eine laufende Überschuss-Ladung über Wolkenlücken hinweg zu stützen, bis der Mindest-SoC wieder erreicht ist. Die Regelung arbeitet in genau diesem Zustand aber gegen den Puffer:
Mehrphasige LP mit automatischer Umschaltung. Die freigegebene Entladeleistung ist typischerweise kleiner als der Bedarf eines dreiphasig ladenden Fahrzeugs. Der Überschuss ist damit ≤ 0 — und das ist die Rückschaltbedingung:
Nach der Rückschaltung lädt das Fahrzeug mit einem Drittel der Leistung. Der Puffer hat dann zwar leichtes Spiel, aber die Ladung, die er halten sollte, ist bereits eingebrochen. Kommt die Sonne zurück, kostet die Hochschaltung erneut
switch_on_delayplusphase_switch_delay.Ein- und festphasige LP. Hier gibt es keine Umschaltung, die greifen könnte. Stattdessen läuft direkt die Abschaltverzögerung an, weil
switch_off_check_threshold()die Schwelle überschritten sieht. Bei mehrphasigen LP verdecktphase_switch_necessary()das bisher, bei diesen nicht.In beiden Fällen ist das Ergebnis dasselbe: Der Speicher gibt Leistung frei, die die Regelung nicht in die Ladung umsetzt.
Und wenn der Puffer leer läuft, stapeln sich die Verzögerungen. Die Rückschaltung hat Vorrang vor der Abschaltung:
phase_switch_necessary()ist rein statisch — Hardware kann umschalten, aktuell nicht einphasig, Automatikmodus. Ein dreiphasiger Automatik-LP erreicht die Abschaltschwelle also überhaupt nie, solange er dreiphasig lädt. Unterschreitet der Speicher den Mindest-SoC, läuft deshalb ab:switch_off_delayfür die Rückschaltung 3 → 1 (ev.py:334), dazu der Pufferphase_switch_delayseit der letzten Umschaltungswitch_off_delayDie ganze Zeit lädt das Fahrzeug aus dem Netz, während der Speicher sich eigentlich wieder aufladen soll.
Änderung
BatAll.is_buffering()undBatAll.is_buffer_depleted()_buffer_configured()prüft, ob der Speicher überhaupt als Puffer wirken kann — konfiguriert, kein Fehlerfall, Modusmin_soc_bat_mode,power_discharge_activeund die Freigabe der aktiven Speichersteuerung. Dieselbe Bedingung, unter derget_charging_power_left_diff()die Entladeleistung zuschlägt. Darauf setzen zwei Zustände auf:is_buffering()— zusätzlichhysteresis_discharge(Maximal-SoC erreicht, Mindest-SoC noch nicht wieder unterschritten) und keine vorgegebene Entladeleistung. Der Puffer stützt die Ladung.is_buffer_depleted()— zusätzlichsoc < min_soc. Der Puffer ist aufgebraucht, der Speicher hat Vorrang und lädt sich wieder auf.Die Modus-Prüfung ist wichtig:
hysteresis_dischargewird nur im Mindest-SoC-Modus gepflegt und ist inbat_mode/ev_modeein Altwert.Rein additiv,
get_charging_power_left_diff()bleibt unangetastet. Die Bedingung ist dort zweimal ausgeschrieben (Band und oberhalb Maximal-SoC); sie gegen den neuen Helper zu deduplizieren wäre naheliegend, kollidiert aber mit #3985 und #3986, die genau diese Zweige anfassen. Das gehört in einen Folge-PR, wenn die beiden durch sind.Sperre der Rückschaltung 3 → 1
Früher Ausstieg in
_check_phase_switch_conditions(), bevor die Bedingungen gerechnet werden:Auf
phases_in_use > 1begrenzt, die Hochschaltung 1 → 3 bleibt also unberührt: wenn genug Überschuss für drei Phasen da ist, soll auch hochgeschaltet werden, unabhängig vom Speicher. Auf den PV-Submodus begrenzt, damit Sofort- und Zielladen nicht betroffen sind.Über den bestehenden Rückgabepfad bricht das auch eine bereits laufende
PHASE_SWITCH_DELAYab und gibtreserved_surpluszurück — das ist der gewünschte Effekt, wenn der Puffer mitten in der Verzögerung einsetzt oder leer läuft.Leerer Puffer: abschalten statt zurückschalten
phase_switch_necessary()gibt bei leerem PufferFalsezurück, die Abschaltschwelle greift also wieder. Zusammen mit der obigen Unterdrückung voncondition_3_to_1bleibt genau eineswitch_off_delaystehen statt der Kaskade aus Rückschaltverzögerung,phase_switch_delayund Abschaltverzögerung.Das ist auch inhaltlich richtig: unterhalb des Mindest-SoC hat der Speicher Vorrang („Speicher-Vorrang bis zum Min-Soc",
bat_all.py:359), undregulate_upsetzt dort ohnehin schon die Abschaltbedingung incounter.py. Einphasig mit 6 A weiterzuladen sind 1,4 kW, die dem Speicher beim Wiederaufladen fehlen — und die Rückschaltung kostet den Weg dorthin zusätzlich Zeit. Erholt sich der Puffer, entscheidet die normale Einschaltlogik neu, ob ein- oder dreiphasig gestartet wird.Die verbleibende
switch_off_delayist bewusst nicht wegoptimiert: sie filtert kurze Einbrüche in der Überschussmessung, und dieser Filter soll erhalten bleiben.Veto gegen die Abschaltschwelle
_bat_buffer_holds_charge()incounter.pyprüft zusätzlich zuis_buffering():current_prev or charge_state) — der Puffer soll eine laufende Ladung halten, aber keine neue startenIn
switch_off_check_threshold()bricht das eine laufende Abschaltverzögerung ab (über die vorhandene Buchhaltungreleased_surplus -= required_power, ZustandCHARGING_ALLOWED) und verhindert, dass eine neue gestartet wird.Das ist vor allem für ein- und festphasige LP nötig. Bei mehrphasigen Automatik-LP hat die Phasensperre ohnehin Vorrang: solange der Puffer stützt, ist
is_buffer_depleted()falsch, undphase_switch_necessary()lässt die Abschaltschwelle dort gar nicht erst erreichen.Was nicht nötig war
Ein expliziter 6-A-Boden.
limit_adjust_current()liefert bereits strukturell nie weniger alsmin_current:Solange der LP lädt und nicht abgeschaltet wird, liegt der Strom also nicht unter dem Mindeststrom. Genau das leisten die beiden Vetos: sie verhindern das Abschalten und das Zurückschalten, der Boden ergibt sich.
Ablauf über einen Puffer-Zyklus
is_buffering()is_buffer_depleted()switch_off_delay, dann ausDer Umschlagpunkt selbst bleibt, wo er ist — dieser PR ändert nur, was dort passiert.
Test
Sechsundzwanzig neue Fälle:
bat_all_test.py::test_is_buffering— alle Bedingungen einzeln, inklusive der Altwert-Fälle inbat_mode/ev_modebat_all_test.py::test_is_buffer_depleted— Grenze am Mindest-SoC, kein Puffer ohne freigegebene Entladeleistungev_test.py::test_check_phase_switch_conditions_bat_buffering— Sperre greift, greift ohne Puffer nicht, lässt 1 → 3 durch, greift außerhalb des PV-Submodus nichtev_test.py::test_check_phase_switch_conditions_bat_buffer_depleted— keine Rückschaltung bei leerem Puffer, unverändert ohnecounter_test.py::test_switch_off_check_threshold_bat_buffering— Abbruch einer laufenden Verzögerung, kein Start einer neuen, unveränderte Wege ohne Puffer, keine Wirkung ohne fließende Ladungsurplus_controlled_test.py::test_check_submode_pv_charging_buffer_depleted— die Abschaltschwelle wird bei leerem Puffer auch für einen dreiphasigen Automatik-LP geprüft, sonst nichtGegenprobe mit neutralisierten Vetos: genau die sieben positiven Fälle schlagen fehl, die Negativkontrollen bleiben grün.
Dieselben 17 Fehlschläge (
ocpp_test.py,charge_template_test.py), sie bestehen aufmasterunverändert.flake8sauber.Bezug: #3980
🤖 Generated with Claude Code