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

Support 15118-20 DC BPT #169

Merged
merged 14 commits into from
Dec 20, 2022
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
123 changes: 88 additions & 35 deletions iso15118/evcc/controller/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from abc import ABC, abstractmethod
from dataclasses import dataclass
from typing import List, Optional, Tuple
from typing import List, Optional, Tuple, Union

from iso15118.shared.messages.datatypes import (
DCEVChargeParams,
Expand Down Expand Up @@ -38,6 +38,9 @@
DynamicACChargeLoopReqParams,
ScheduledACChargeLoopReqParams,
)
from iso15118.shared.messages.iso15118_20.common_messages import (
ChargeProgress as ChargeProgressV20,
)
from iso15118.shared.messages.iso15118_20.common_messages import (
DynamicScheduleExchangeReqParams,
DynamicScheduleExchangeResParams,
Expand All @@ -49,9 +52,14 @@
SelectedEnergyService,
SelectedVAS,
)
from iso15118.shared.messages.iso15118_20.common_types import RationalNumber
from iso15118.shared.messages.iso15118_20.dc import (
BPTDCChargeParameterDiscoveryReqParams,
BPTDynamicDCChargeLoopReqParams,
BPTScheduledDCChargeLoopReqParams,
DCChargeParameterDiscoveryReqParams,
DynamicDCChargeLoopReqParams,
ScheduledDCChargeLoopReqParams,
)


Expand Down Expand Up @@ -201,7 +209,7 @@ async def get_dynamic_se_params(
@abstractmethod
async def process_scheduled_se_params(
self, scheduled_params: ScheduledScheduleExchangeResParams, pause: bool
) -> Tuple[Optional[EVPowerProfile], ChargeProgress]:
) -> Tuple[Optional[EVPowerProfile], ChargeProgressV20]:
"""
Processes the ScheduleExchangeRes parameters for the Scheduled mode.

Expand All @@ -224,7 +232,7 @@ async def process_scheduled_se_params(
@abstractmethod
async def process_dynamic_se_params(
self, dynamic_params: DynamicScheduleExchangeResParams, pause: bool
) -> Tuple[Optional[EVPowerProfile], ChargeProgress]:
) -> Tuple[Optional[EVPowerProfile], ChargeProgressV20]:
"""
Processes the ScheduleExchangeRes parameters for the Dynamic mode.

Expand Down Expand Up @@ -388,7 +396,9 @@ async def get_dc_ev_status(self) -> DCEVStatus:
raise NotImplementedError

@abstractmethod
async def is_precharged(self, present_voltage_evse: PVEVSEPresentVoltage) -> bool:
async def is_precharged(
self, present_voltage_evse: Union[PVEVSEPresentVoltage, RationalNumber]
) -> bool:
"""
Return True if the output voltage of the EVSE has reached
the requested precharge voltage. Otherwise return False.
Expand Down Expand Up @@ -418,10 +428,23 @@ async def get_charge_params_v2(self, protocol: Protocol) -> ChargeParamsV2:
raise NotImplementedError

@abstractmethod
async def get_ac_charge_params_v20(self) -> ACChargeParameterDiscoveryReqParams:
async def get_charge_params_v20(
self, selected_service: SelectedEnergyService
) -> Union[
ACChargeParameterDiscoveryReqParams,
BPTACChargeParameterDiscoveryReqParams,
DCChargeParameterDiscoveryReqParams,
BPTDCChargeParameterDiscoveryReqParams,
]:
"""
Gets the charge parameters needed for a ChargeParameterDiscoveryReq for
AC charging.
Gets the charge parameter needed for
ACChargeParameterDiscovery/DCChargeParameterDiscovery (ISO 15118-20).
Returns:
One of [ACChargeParameterDiscoveryReqParams,
BPTACChargeParameterDiscoveryReqParams,
DCChargeParameterDiscoveryReqParams,
BPTDCChargeParameterDiscoveryReqParams]
based on the currently selected service.

Relevant for:
- ISO 15118-20
Expand Down Expand Up @@ -473,19 +496,6 @@ async def get_remaining_time_to_full_soc(self) -> PVRemainingTimeToFullSOC:
"""
raise NotImplementedError

@abstractmethod
async def get_ac_bpt_charge_params_v20(
self,
) -> BPTACChargeParameterDiscoveryReqParams:
"""
Gets the charge parameters needed for a ChargeParameterDiscoveryReq for
bidirectional AC charging.

Relevant for:
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_scheduled_ac_charge_loop_params(
self,
Expand Down Expand Up @@ -539,9 +549,65 @@ async def get_bpt_dynamic_ac_charge_loop_params(
# ============================================================================

@abstractmethod
async def get_dc_charge_params_v20(self) -> DCChargeParameterDiscoveryReqParams:
async def get_scheduled_dc_charge_loop_params(
self,
) -> ScheduledDCChargeLoopReqParams:
"""
Gets the parameters for the DCChargeLoopReq in the Scheduled control mode

Relevant for:
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_dynamic_dc_charge_loop_params(self) -> DynamicDCChargeLoopReqParams:
"""
Gets the parameters for the DCChargeLoopReq in the Dynamic control mode

Relevant for:
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_bpt_scheduled_dc_charge_loop_params(
self,
) -> BPTScheduledDCChargeLoopReqParams:
"""
Gets the parameters for the DCChargeLoopReq in the Scheduled control mode for
bi-directional power transfer (BPT)

Relevant for:
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_bpt_dynamic_dc_charge_loop_params(
self,
) -> BPTDynamicDCChargeLoopReqParams:
"""
Gets the parameters for the DCChargeLoopReq in the Dynamic control mode for
bi-directional power transfer (BPT)

Relevant for:
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_present_voltage(self) -> RationalNumber:
"""
Gets current voltage required for DCChargeLoop for
DC charging.
"""
raise NotImplementedError

@abstractmethod
async def get_target_voltage(self) -> RationalNumber:
"""
Gets the charge parameters needed for a ChargeParameterDiscoveryReq for
Gets current voltage required for DCChargeLoop for
DC charging.
"""
raise NotImplementedError
Expand Down Expand Up @@ -577,19 +643,6 @@ async def stop_charging(self) -> None:
"""
raise NotImplementedError

@abstractmethod
async def get_dc_bpt_charge_params_v20(
self,
) -> BPTDCChargeParameterDiscoveryReqParams:
"""
Gets the charge parameters needed for a ChargeParameterDiscoveryReq for
bidirectional DC charging.

Relevant for:
- ISO 15118-20
"""
raise NotImplementedError

@abstractmethod
async def get_dc_ev_power_delivery_parameter_dinspec(
self,
Expand Down
116 changes: 62 additions & 54 deletions iso15118/evcc/controller/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,11 @@
from iso15118.shared.messages.iso15118_20.common_types import RationalNumber
from iso15118.shared.messages.iso15118_20.dc import (
BPTDCChargeParameterDiscoveryReqParams,
BPTDynamicDCChargeLoopReqParams,
BPTScheduledDCChargeLoopReqParams,
DCChargeParameterDiscoveryReqParams,
DynamicDCChargeLoopReqParams,
ScheduledDCChargeLoopReqParams,
)
from iso15118.shared.network import get_nic_mac_address

Expand Down Expand Up @@ -164,11 +168,11 @@ async def get_energy_transfer_mode(
"""Overrides EVControllerInterface.get_energy_transfer_mode()."""
if protocol == Protocol.DIN_SPEC_70121:
return EnergyTransferModeEnum.DC_EXTENDED
return EnergyTransferModeEnum.DC_EXTENDED
return EnergyTransferModeEnum.AC_THREE_PHASE_CORE

async def get_supported_energy_services(self) -> List[ServiceV20]:
"""Overrides EVControllerInterface.get_energy_transfer_service()."""
return [ServiceV20.AC_BPT]
return [ServiceV20.DC_BPT]

async def select_energy_service_v20(
self, services: List[MatchedService]
Expand All @@ -182,10 +186,6 @@ async def select_energy_service_v20(
selected_service = SelectedEnergyService(
service=top_of_list.service,
is_free=top_of_list.is_free,
# Hi Marc/André
# My understanding is that there could be multiple parameter sets
# for matched service.
# When we select a service we pick one of the parameter sets.
parameter_set=top_of_list.parameter_sets[0],
)
return selected_service
Expand Down Expand Up @@ -301,6 +301,7 @@ async def get_charge_params_v20(
logger.error(
f"Energy transfer service {selected_service.service} not supported"
)
return None

async def get_scheduled_se_params(
self, selected_energy_service: SelectedEnergyService
Expand Down Expand Up @@ -388,7 +389,7 @@ async def process_scheduled_se_params(
charge_progress = ChargeProgressV20.STOP

# Let's just select the first schedule offered
selected_schedule = scheduled_params.schedule_tuples.pop()
selected_schedule = scheduled_params.schedule_tuples[0]
charging_schedule = selected_schedule.charging_schedule.power_schedule
charging_schedule_entries = charging_schedule.schedule_entry_list.entries

Expand Down Expand Up @@ -452,7 +453,7 @@ async def process_dynamic_se_params(

async def is_cert_install_needed(self) -> bool:
"""Overrides EVControllerInterface.is_cert_install_needed()."""
return True
return False

async def process_sa_schedules_dinspec(
self, sa_schedules: List[SAScheduleTupleEntryDINSPEC]
Expand Down Expand Up @@ -556,7 +557,9 @@ async def get_prioritised_emaids(self) -> Optional[EMAIDList]:
async def ready_to_charge(self) -> bool:
return await self.continue_charging()

async def is_precharged(self, present_voltage_evse: PVEVSEPresentVoltage) -> bool:
async def is_precharged(
self, present_voltage_evse: Union[PVEVSEPresentVoltage, RationalNumber]
) -> bool:
return True

async def get_dc_ev_power_delivery_parameter_dinspec(
Expand Down Expand Up @@ -617,32 +620,6 @@ async def get_ac_charge_params_v2(self) -> ChargeParamsV2:
await self.get_energy_transfer_mode(), ac_charge_params, None
)

async def get_ac_charge_params_v20(self) -> ACChargeParameterDiscoveryReqParams:
"""Overrides EVControllerInterface.get_ac_charge_params_v20()."""
return ACChargeParameterDiscoveryReqParams(
ev_max_charge_power=RationalNumber(exponent=3, value=3),
ev_max_charge_power_l2=RationalNumber(exponent=3, value=3),
ev_max_charge_power_l3=RationalNumber(exponent=3, value=3),
ev_min_charge_power=RationalNumber(exponent=0, value=100),
ev_min_charge_power_l2=RationalNumber(exponent=0, value=100),
ev_min_charge_power_l3=RationalNumber(exponent=0, value=100),
)

async def get_ac_bpt_charge_params_v20(
self,
) -> BPTACChargeParameterDiscoveryReqParams:
"""Overrides EVControllerInterface.get_bpt_ac_charge_params_v20()."""
ac_charge_params_v20 = (await self.get_ac_charge_params_v20()).dict()
return BPTACChargeParameterDiscoveryReqParams(
**ac_charge_params_v20,
ev_max_discharge_power=RationalNumber(exponent=3, value=11),
ev_max_discharge_power_l2=RationalNumber(exponent=3, value=11),
ev_max_discharge_power_l3=RationalNumber(exponent=3, value=11),
ev_min_discharge_power=RationalNumber(exponent=0, value=100),
ev_min_discharge_power_l2=RationalNumber(exponent=0, value=100),
ev_min_discharge_power_l3=RationalNumber(exponent=0, value=100),
)

async def get_scheduled_ac_charge_loop_params(
self,
) -> ScheduledACChargeLoopReqParams:
Expand Down Expand Up @@ -713,26 +690,57 @@ async def get_dc_ev_status(self) -> DCEVStatus:
ev_ress_soc=60,
)

async def get_dc_charge_params_v20(self) -> DCChargeParameterDiscoveryReqParams:
"""Overrides EVControllerInterface.get_dc_charge_params_v20()."""
return DCChargeParameterDiscoveryReqParams(
ev_max_charge_power=RationalNumber(exponent=3, value=300),
ev_min_charge_power=RationalNumber(exponent=0, value=100),
ev_max_charge_current=RationalNumber(exponent=0, value=300),
ev_min_charge_current=RationalNumber(exponent=0, value=10),
ev_max_voltage=RationalNumber(exponent=0, value=1000),
ev_min_voltage=RationalNumber(exponent=0, value=10),
async def get_scheduled_dc_charge_loop_params(
self,
) -> ScheduledDCChargeLoopReqParams:
"""Overrides EVControllerInterface.get_scheduled_dc_charge_loop_params()."""
return ScheduledDCChargeLoopReqParams(
ev_target_current=RationalNumber(exponent=3, value=40),
ev_target_voltage=RationalNumber(exponent=3, value=60),
)

async def get_dc_bpt_charge_params_v20(
async def get_dynamic_dc_charge_loop_params(self) -> DynamicDCChargeLoopReqParams:
"""Overrides EVControllerInterface.get_dynamic_dc_charge_loop_params()."""
return DynamicDCChargeLoopReqParams(
ev_target_energy_request=RationalNumber(exponent=3, value=40),
ev_max_energy_request=RationalNumber(exponent=3, value=60),
ev_min_energy_request=RationalNumber(exponent=-2, value=20),
ev_max_charge_power=RationalNumber(exponent=3, value=40),
ev_min_charge_power=RationalNumber(exponent=3, value=300),
ev_max_charge_current=RationalNumber(exponent=3, value=40),
ev_max_voltage=RationalNumber(exponent=3, value=300),
ev_min_voltage=RationalNumber(exponent=3, value=300),
)

async def get_bpt_scheduled_dc_charge_loop_params(
self,
) -> BPTDCChargeParameterDiscoveryReqParams:
"""Overrides EVControllerInterface.get_bpt_dc_charge_params_v20()."""
dc_charge_params_v20 = (await self.get_dc_charge_params_v20()).dict()
return BPTDCChargeParameterDiscoveryReqParams(
**dc_charge_params_v20,
ev_max_discharge_power=RationalNumber(exponent=3, value=11),
ev_min_discharge_power=RationalNumber(exponent=3, value=1),
ev_max_discharge_current=RationalNumber(exponent=0, value=11),
ev_min_discharge_current=RationalNumber(exponent=0, value=0),
) -> BPTScheduledDCChargeLoopReqParams:
"""Overrides EVControllerInterface.get_bpt_scheduled_dc_charge_loop_params()."""
dc_scheduled_dc_charge_loop_params_v20 = (
await self.get_scheduled_dc_charge_loop_params()
).dict()
return BPTScheduledDCChargeLoopReqParams(
**dc_scheduled_dc_charge_loop_params_v20
)

async def get_bpt_dynamic_dc_charge_loop_params(
self,
) -> BPTDynamicDCChargeLoopReqParams:
"""Overrides EVControllerInterface.get_bpt_dynamic_dc_charge_loop_params()."""
dc_dynamic_dc_charge_loop_params_v20 = (
await self.get_dynamic_dc_charge_loop_params()
).dict()
return BPTDynamicDCChargeLoopReqParams(
**dc_dynamic_dc_charge_loop_params_v20,
ev_max_discharge_power=RationalNumber(exponent=3, value=300),
ev_min_discharge_power=RationalNumber(exponent=3, value=300),
ev_max_discharge_current=RationalNumber(exponent=3, value=300),
)

async def get_present_voltage(self) -> RationalNumber:
"""Overrides EVControllerInterface.get_present_voltage()."""
return RationalNumber(exponent=3, value=20)

async def get_target_voltage(self) -> RationalNumber:
"""Overrides EVControllerInterface.get_target_voltage()."""
return RationalNumber(exponent=3, value=20)
1 change: 1 addition & 0 deletions iso15118/evcc/evcc_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def load_envs(self, env_path: Optional[str] = None) -> None:
self.supported_protocols = [
Protocol.ISO_15118_2,
Protocol.ISO_15118_20_AC,
Protocol.ISO_15118_20_DC,
Protocol.DIN_SPEC_70121,
]

Expand Down
Loading