Skip to content
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

Feature/add protocol state to interface #136

4 changes: 4 additions & 0 deletions iso15118/secc/comm_session_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ def _is_tls(self, transport: Tuple[StreamReader, StreamWriter]) -> bool:
_, writer = transport
return True if writer.get_extra_info("sslcontext") else False

async def stop(self, reason: str):
await self.evse_controller.stop_charger()
await super().stop(reason)


class CommunicationSessionHandler:
"""
Expand Down
11 changes: 11 additions & 0 deletions iso15118/secc/controller/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,17 @@ async def get_evse_status(self) -> EVSEStatus:
"""
raise NotImplementedError

@abstractmethod
def set_present_protocol_state(self, state_name: str):
"""
This method sets the present state of the charging protocol.

Relevant for:
- DIN SPEC 70121
- ISO 15118-2
"""
raise NotImplementedError

# ============================================================================
# | AC-SPECIFIC FUNCTIONS |
# ============================================================================
Expand Down
3 changes: 3 additions & 0 deletions iso15118/secc/controller/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,9 @@ async def get_evse_status(self) -> EVSEStatus:
notification_max_delay=0, evse_notification=EVSENotificationV20.TERMINATE
)

def set_present_protocol_state(self, state_name: str):
pass

# ============================================================================
# | AC-SPECIFIC FUNCTIONS |
# ============================================================================
Expand Down
17 changes: 10 additions & 7 deletions iso15118/secc/states/din_spec_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ class PreCharge(StateSECC):

def __init__(self, comm_session: SECCCommunicationSession):
super().__init__(comm_session, Timeouts.V2G_SECC_SEQUENCE_TIMEOUT)
self.expect_pre_charge_req = True
self.expecting_pre_charge_req = True

async def process_message(
self,
Expand All @@ -530,7 +530,7 @@ async def process_message(
message_exi: bytes = None,
):
msg = self.check_msg_dinspec(
message, [PreChargeReq, PowerDeliveryReq], self.expect_pre_charge_req
message, [PreChargeReq, PowerDeliveryReq], self.expecting_pre_charge_req
)
if not msg:
return
Expand Down Expand Up @@ -572,11 +572,12 @@ async def process_message(
)
return

if self.expect_pre_charge_req:
await self.comm_session.evse_controller.set_precharge(
precharge_req.ev_target_voltage, precharge_req.ev_target_current
)
self.expect_pre_charge_req = False
# Set precharge voltage in every loop.
# Because there are EVs that send a wrong Precharge-Voltage
# in the first message (example: BMW i3 Rex 2018)
await self.comm_session.evse_controller.set_precharge(
precharge_req.ev_target_voltage, precharge_req.ev_target_current
)

dc_charger_state = await self.comm_session.evse_controller.get_dc_evse_status()
evse_present_voltage = (
Expand All @@ -596,6 +597,8 @@ async def process_message(
Namespace.DIN_MSG_DEF,
)

self.expecting_pre_charge_req = False


class PowerDelivery(StateSECC):
"""
Expand Down
17 changes: 10 additions & 7 deletions iso15118/secc/states/iso15118_2_states.py
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ class PreCharge(StateSECC):

def __init__(self, comm_session: SECCCommunicationSession):
super().__init__(comm_session, Timeouts.V2G_SECC_SEQUENCE_TIMEOUT)
self.precharge_req_was_reveived = False
self.expecting_precharge_req = True

async def process_message(
self,
Expand All @@ -1990,7 +1990,7 @@ async def process_message(
msg = self.check_msg_v2(
message,
[PreChargeReq, PowerDeliveryReq],
not self.precharge_req_was_reveived,
self.expecting_precharge_req,
)
if not msg:
return
Expand Down Expand Up @@ -2032,11 +2032,12 @@ async def process_message(
)
return

if not self.precharge_req_was_reveived:
await self.comm_session.evse_controller.set_precharge(
precharge_req.ev_target_voltage, precharge_req.ev_target_current
)
self.precharge_req_was_reveived = True
# Set precharge voltage in every loop.
# Because there are EVs that send a wrong Precharge-Voltage
# in the first message (example: BMW i3 Rex 2018)
await self.comm_session.evse_controller.set_precharge(
precharge_req.ev_target_voltage, precharge_req.ev_target_current
)

dc_charger_state = await self.comm_session.evse_controller.get_dc_evse_status()
evse_present_voltage = (
Expand All @@ -2057,6 +2058,8 @@ async def process_message(
Namespace.ISO_V2_MSG_DEF,
)

self.expecting_precharge_req = False


class CurrentDemand(StateSECC):
"""
Expand Down
3 changes: 3 additions & 0 deletions iso15118/secc/states/secc_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ def __init__(
super().__init__(comm_session, timeout)
self.comm_session: "SECCCommunicationSession" = comm_session

if hasattr(self.comm_session, "evse_controller"):
self.comm_session.evse_controller.set_present_protocol_state(str(self))

T = TypeVar("T")

def check_msg_dinspec(
Expand Down
190 changes: 190 additions & 0 deletions iso15118/shared/messages/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,196 @@ class PVStartValue(PhysicalValue):
unit: Literal[UnitSymbol.WATT] = Field(..., alias="Unit")


class PVEVEnergyCapacityDin(PVEVEnergyCapacity):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for clarity reasons, add comment on top stating that due to the fact the unit field is Option in the DIN, we have to override the ISO 15118 datatypes

"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.WATT_HOURS] = Field(None, alias="Unit")


class PVEVEnergyRequestDin(PVEVEnergyRequest):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.WATT_HOURS] = Field(None, alias="Unit")


class PVEVMaxCurrentLimitDin(PVEVMaxCurrentLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVMaxPowerLimitDin(PVEVMaxPowerLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.WATT] = Field(None, alias="Unit")


class PVEVMaxVoltageLimitDin(PVEVMaxVoltageLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.VOLTAGE] = Field(None, alias="Unit")


class PVEVSECurrentRegulationToleranceDin(PVEVSECurrentRegulationTolerance):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVSEEnergyToBeDeliveredDin(PVEVSEEnergyToBeDelivered):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.WATT_HOURS] = Field(None, alias="Unit")


class PVEVSEMaxCurrentLimitDin(PVEVSEMaxCurrentLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVSEMaxPowerLimitDin(PVEVSEMaxPowerLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.WATT] = Field(None, alias="Unit")


class PVEVSEMaxVoltageLimitDin(PVEVSEMaxVoltageLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.VOLTAGE] = Field(None, alias="Unit")


class PVEVSEMinCurrentLimitDin(PVEVSEMinCurrentLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVSEMinVoltageLimitDin(PVEVSEMinVoltageLimit):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.VOLTAGE] = Field(None, alias="Unit")


class PVEVSEPeakCurrentRippleDin(PVEVSEPeakCurrentRipple):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVSEPresentCurrentDin(PVEVSEPresentCurrent):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVSEPresentVoltageDin(PVEVSEPresentVoltage):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.VOLTAGE] = Field(None, alias="Unit")


class PVEVTargetCurrentDin(PVEVTargetCurrent):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.AMPERE] = Field(None, alias="Unit")


class PVEVTargetVoltageDin(PVEVTargetVoltage):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.VOLTAGE] = Field(None, alias="Unit")


class PVRemainingTimeToFullSOCDin(PVRemainingTimeToFullSOC):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.SECONDS] = Field(None, alias="Unit")


class PVRemainingTimeToBulkSOCDin(PVRemainingTimeToBulkSOC):
"""
See section 9.5.2.4 in DIN SPEC 70121

In DIN the Element unit is optional, in ISO it is mandatory.
"""

unit: Literal[UnitSymbol.SECONDS] = Field(None, alias="Unit")


class DCEVChargeParams(BaseModel):
dc_max_current_limit: PVEVMaxCurrentLimit
dc_max_power_limit: PVEVMaxPowerLimit
Expand Down
Loading