diff --git a/iso15118/evcc/comm_session_handler.py b/iso15118/evcc/comm_session_handler.py index 4e658e8aa..7e382e424 100644 --- a/iso15118/evcc/comm_session_handler.py +++ b/iso15118/evcc/comm_session_handler.py @@ -144,6 +144,7 @@ def __init__( self.is_tls = False self.sae_j2847_active: int = 0 + self.service_hpc1_active: bool = False def create_sap(self) -> Union[SupportedAppProtocolReq, None]: """ diff --git a/iso15118/evcc/controller/simulator.py b/iso15118/evcc/controller/simulator.py index b8f1ea5a3..37cced111 100644 --- a/iso15118/evcc/controller/simulator.py +++ b/iso15118/evcc/controller/simulator.py @@ -580,7 +580,7 @@ async def process_sa_schedules_v2( self, sa_schedules: List[SAScheduleTuple] ) -> Tuple[ChargeProgressV2, int, ChargingProfile]: """Overrides EVControllerInterface.process_sa_schedules().""" - secc_schedule = sa_schedules.pop() + secc_schedule = sa_schedules.pop(0) #[V2G2-297] evcc_profile_entry_list: List[ProfileEntryDetails] = [] # The charging schedule coming from the SECC is called 'schedule', the @@ -886,6 +886,9 @@ async def get_display_params(self) -> DisplayParameters: charging_complete=await self.is_charging_complete(), ) + async def is_service_hpc1_active(self) -> bool: + return EVEREST_EV_STATE.ServiceHPC1_Active + # ============================================================================ # | SAE J2847/2 FUNCTIONS | # ============================================================================ diff --git a/iso15118/evcc/everest/ev_state.py b/iso15118/evcc/everest/ev_state.py index 0b3fed4e1..da6d470cd 100644 --- a/iso15118/evcc/everest/ev_state.py +++ b/iso15118/evcc/everest/ev_state.py @@ -30,6 +30,9 @@ class EVState: dc_discharge_max_power_limit: float = 0 dc_discharge_target_current: float = 0 + # Service HPC1 + ServiceHPC1_Active: bool = False + # SAE J2847/2 SAEJ2847_V2H_V2G_Active = False minimal_soc = 20 diff --git a/iso15118/evcc/states/iso15118_2_states.py b/iso15118/evcc/states/iso15118_2_states.py index 6222cdb17..7eb3a46e2 100644 --- a/iso15118/evcc/states/iso15118_2_states.py +++ b/iso15118/evcc/states/iso15118_2_states.py @@ -344,8 +344,17 @@ async def select_services(self, service_discovery_res: ServiceDiscoveryRes): ) self.comm_session.sae_j2847_active = service.service_id - # Request more service details if you're interested in e.g. - # an Internet service or a use case-specific service + # check if service HPC1 is offered + if (service.service_category == ServiceCategory.CUSTOM + and await self.comm_session.ev_controller.is_service_hpc1_active() == True + and service.service_id == 63000): + self.comm_session.selected_services.append( + SelectedService(service_id=service.service_id) + ) + self.comm_session.service_hpc1_active = True + + # Request more service details if you're interested in e.g. + # an Internet service or a use case-specific service logger.debug(f"Offered value-added services: {offered_services}") @@ -793,6 +802,9 @@ async def process_message( # if e.g. EVSENotification is set to STOP_CHARGING or if RCD # is True. But let's do that after the testival + if self.comm_session.service_hpc1_active and len(charge_params_res.sa_schedule_list) > 2: + charge_params_res.sa_schedule_list = charge_params_res.sa_schedule_list[:2] # [V2G2-PnC-CharIN-017] + ( charge_progress, schedule_id, @@ -830,7 +842,10 @@ async def process_message( Namespace.ISO_V2_MSG_DEF, ) - self.comm_session.selected_schedule = schedule_id + if await self.comm_session.ev_controller.is_service_hpc1_active(): + self.comm_session.selected_schedule = charge_params_res.sa_schedule_list.schedule_tuples[0].sa_schedule_tuple_id # [V2G2-PnC-CharIN-036] + else: + self.comm_session.selected_schedule = schedule_id await self.comm_session.ev_controller.enable_charging(True) else: @@ -866,6 +881,9 @@ async def process_message( dc_ev_charge_parameter=charge_params.dc_parameters, ) + if await self.comm_session.ev_controller.is_service_hpc1_active(): + charge_parameter_discovery_req.max_entries_sa_schedule_tuple = None #[V2G2-PnC-CharIN-018] + self.create_next_message( ChargeParameterDiscovery, charge_parameter_discovery_req, @@ -925,7 +943,12 @@ async def process_message( Timeouts.WELDING_DETECTION_REQ, Namespace.ISO_V2_MSG_DEF, ) - elif self.comm_session.renegotiation_requested: + elif self.comm_session.renegotiation_requested and not await self.comm_session.ev_controller.is_service_hpc1_active(): + # In HPC1, the EVSE and the EV do not use the renegotiation mechanism. + # [V2G2-PnC-CharIN-016] If the SECC sent the ServiceID service + # 63000, Service Name and ServiceCategory for HPC1 as + # defined in Table 105 it shall not use EVSENotification = + # Renegotiate. self.comm_session.renegotiation_requested = False charge_params = await self.comm_session.ev_controller.get_charge_params_v2( @@ -1040,7 +1063,7 @@ async def process_message( Timeouts.POWER_DELIVERY_REQ, Namespace.ISO_V2_MSG_DEF, ) - elif notification == EVSENotification.RE_NEGOTIATION: + elif notification == EVSENotification.RE_NEGOTIATION and not await self.comm_session.ev_controller.is_service_hpc1_active(): logger.debug("SECC requested a renegotiation") self.comm_session.renegotiation_requested = True self.create_next_message(