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
8 changes: 6 additions & 2 deletions packages/control/chargepoint/chargepoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ def remember_previous_values(self):
self.data.set.plug_state_prev = self.data.get.plug_state
self.data.set.current_prev = self.data.set.current
self.data.set.ev_prev = self.data.config.ev
self.data.set.state_prev = self.data.control_parameter.state

def reset_log_data_chargemode_switch(self) -> None:
reset_log = Log()
Expand Down Expand Up @@ -284,9 +285,12 @@ def initiate_control_pilot_interruption(self):
if self.data.config.control_pilot_interruption_hw:
control_parameter = self.data.control_parameter
retry_interval = charging_ev.ev_template.data.control_pilot_interruption_retry_interval
# Wird die Ladung gestartet? (nicht nach Phasenumschaltung, da diese bereits CP umschaltet)
# Wird die Ladung gestartet? Nicht, wenn eine Phasenumschaltung gerade lief oder jetzt
# ansteht - die schaltet CP bereits selbst um (state_prev statt state, da
# WAIT_FOR_USING_PHASES auch unabhängig von einer Umschaltung erreicht wird).
started_now = (self.data.set.current_prev == 0 and self.data.set.current != 0 and
self.data.control_parameter.state != ChargepointState.WAIT_FOR_USING_PHASES)
self.data.set.state_prev != ChargepointState.PERFORMING_PHASE_SWITCH and
self._is_phase_switch_required() is False)
# Ladung angefordert, Auto lädt aber trotz gültigem Signal seit geraumer Zeit nicht.
stuck = (
retry_interval > 0 and
Expand Down
6 changes: 6 additions & 0 deletions packages/control/chargepoint/chargepoint_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from threading import Event
from typing import Dict, List, Optional, Protocol
from control.chargemode import Chargemode
from control.chargepoint.chargepoint_state import ChargepointState
from control.chargepoint.chargepoint_template import CpTemplate

from control.chargepoint.control_parameter import ControlParameter, control_parameter_factory
Expand Down Expand Up @@ -174,6 +175,11 @@ class Set:
charging_ev_data: Ev = field(default_factory=ev_factory)
ocpp_transaction_id: Optional[int] = field(default=None, metadata={"topic": "set/ocpp_transaction_id"})
charge_state_prev: bool = field(default=False, metadata={"topic": "set/charge_state_prev"})
# control_parameter.state aus dem vorherigen Zyklus, um eine Control-Pilot-Unterbrechung beim
# Ladestart von einer, die direkt nach einer echten Phasenumschaltung erfolgt, zu unterscheiden
# (siehe initiate_control_pilot_interruption()).
state_prev: ChargepointState = field(default=ChargepointState.NO_CHARGING_ALLOWED,
metadata={"topic": "set/state_prev"})
# letzter CP-SoC-Timestamp, für den bereits ein force_soc_update ausgelöst wurde, und das zugehörige EV,
# um bei dauerhaft veraltetem EV-SoC (zB API-Fehler) nicht jeden Zyklus erneut ein Update anzustoßen,
# aber bei einem EV-Wechsel am selben Ladepunkt trotzdem einmal neu auszulösen
Expand Down
69 changes: 69 additions & 0 deletions packages/control/chargepoint/chargepoint_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,75 @@ def test_check_min_max_current(required_current, phases, expected_required_curre
assert ret == expected_required_current


@pytest.mark.parametrize("state_prev, expected_message_present",
[
pytest.param(ChargepointState.SWITCH_ON_DELAY, True,
id="Ladestart nach Einschaltverzoegerung: CP-Unterbrechung noetig"),
pytest.param(ChargepointState.NO_CHARGING_ALLOWED, True,
id="regulaerer Ladestart: CP-Unterbrechung noetig"),
pytest.param(ChargepointState.PERFORMING_PHASE_SWITCH, False,
id="direkt nach Phasenumschaltung: keine zusaetzliche CP-Unterbrechung"),
])
def test_initiate_control_pilot_interruption_uses_state_prev_not_state(state_prev, expected_message_present):
""" WAIT_FOR_USING_PHASES wird nicht nur direkt nach einer echten Phasenumschaltung erreicht, sondern
zB auch direkt nach Ablauf der Einschaltverzoegerung (siehe Discussion #3908, lackylacky) - dort war
dann also nach jedem PV-Ladestart mit reiner Ein-Phasen-Ladung (kein hw_supports_phase_switch())
dauerhaft keine Control-Pilot-Unterbrechung mehr moeglich. state_prev unterscheidet die beiden
Faelle korrekt, state (aktuell WAIT_FOR_USING_PHASES in beiden Faellen) nicht. """
# setup
cp = Chargepoint(0, None)
cp.chargepoint_module = Mock(interrupt_cp=Mock(), config=Mock(id=0))
cp.data.set.charging_ev_data = Ev(0)
cp.data.set.charging_ev_data.ev_template.data.control_pilot_interruption = True
cp.data.set.charging_ev_data.ev_template.data.control_pilot_interruption_duration = 4
cp.data.set.charging_ev_data.ev_template.data.control_pilot_interruption_retry_interval = 0
cp.data.config.control_pilot_interruption_hw = True
# state_prev ueber remember_previous_values() setzen statt direkt zuzuweisen
cp.data.set.current = 0
cp.data.control_parameter.state = state_prev
cp.remember_previous_values()
# aktueller Zyklus: Ladung startet
cp.data.control_parameter.state = ChargepointState.WAIT_FOR_USING_PHASES
cp.data.set.current = 6

# evaluation
cp.initiate_control_pilot_interruption()

# assertion
message_present = (cp.data.get.state_str is not None and
"Control-Pilot-Unterbrechung" in cp.data.get.state_str)
assert message_present == expected_message_present


def test_initiate_control_pilot_interruption_skipped_when_phase_switch_pending():
""" Kontaktoren stehen noch auf falscher Phasenzahl -> initiate_phase_switch() schaltet im selben
Zyklus bereits CP um, keine zusaetzliche Unterbrechung noetig. """
# setup
cp = Chargepoint(0, None)
cp.chargepoint_module = Mock(interrupt_cp=Mock(), config=Mock(id=0))
cp.data.set.charging_ev_data = Ev(0)
cp.data.set.charging_ev_data.ev_template.data.control_pilot_interruption = True
cp.data.set.charging_ev_data.ev_template.data.control_pilot_interruption_duration = 4
cp.data.set.charging_ev_data.ev_template.data.control_pilot_interruption_retry_interval = 0
cp.data.config.control_pilot_interruption_hw = True
cp.data.set.current = 0
cp.data.control_parameter.state = ChargepointState.SWITCH_ON_DELAY
cp.remember_previous_values()
cp.data.control_parameter.state = ChargepointState.WAIT_FOR_USING_PHASES
cp.data.set.current = 6
# Kontaktoren (1p) weichen von der benoetigten Phasenzahl (3p) ab
cp.data.set.phases_to_use = 3
cp.data.control_parameter.phases = 1

# evaluation
cp.initiate_control_pilot_interruption()

# assertion
message_present = (cp.data.get.state_str is not None and
"Control-Pilot-Unterbrechung" in cp.data.get.state_str)
assert message_present is False


@pytest.mark.parametrize("required_current, max_discharge_power, dc_max_current, expected_required_current",
[
pytest.param(-50, -30000, 25, -25,
Expand Down
2 changes: 2 additions & 0 deletions packages/helpermodules/setdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,8 @@ def process_chargepoint_topic(self, msg: mqtt.MQTTMessage):
"/set/charge_state_prev" in msg.topic or
"/set/plug_state_prev" in msg.topic):
self._validate_value(msg, bool)
elif "/set/state_prev" in msg.topic:
self._validate_value(msg, int, [(0, 7)])
elif "/set/autolock_state" in msg.topic:
self._validate_value(msg, int, [(0, 4)])
elif "/set/rfid" in msg.topic:
Expand Down
Loading