Skip to content

Commit 21b1210

Browse files
committed
Update to EcoG-io/iso15118 version 0.27.0
2 parents 827833a + fff2863 commit 21b1210

10 files changed

Lines changed: 76 additions & 56 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
55

66
## [Unreleased]
77

8+
## [0.27.0] - 2024-04-17
9+
* ScheduleExchangeRes parsing fix by @heavyweight87 in https://github.com/SwitchEV/iso15118/pull/391
10+
* Moved contactor status check for dc to be after cable check by @shalinnijel2 in https://github.com/SwitchEV/iso15118/pull/396
11+
* Simulate soc in -2, -20 and din. by @shalinnijel2 in https://github.com/SwitchEV/iso15118/pull/393
12+
813
## [0.26.0] - 2024-03-20
914
* Jtt 770 return ongoing if cs is not ready by @shalinnijel2 in https://github.com/SwitchEV/iso15118/pull/387
1015
* Fixes for issue where the saved session context wasn't found on waking up. by @shalinnijel2 in https://github.com/SwitchEV/iso15118/pull/388

iso15118/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.26.1"
1+
__version__ = "0.27.0"

iso15118/evcc/controller/interface.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@
5858
SelectedEnergyService,
5959
SelectedVAS,
6060
)
61-
from iso15118.shared.messages.iso15118_20.common_types import RationalNumber
61+
from iso15118.shared.messages.iso15118_20.common_types import (
62+
DisplayParameters,
63+
RationalNumber,
64+
)
6265
from iso15118.shared.messages.iso15118_20.dc import (
6366
BPTDCChargeParameterDiscoveryReqParams,
6467
BPTDynamicDCChargeLoopReqParams,
@@ -681,3 +684,12 @@ async def enable_charging(self, enabled: bool) -> None:
681684
- ISO 15118-2
682685
- ISO 15118-20
683686
"""
687+
688+
@abstractmethod
689+
async def get_display_params(self) -> DisplayParameters:
690+
"""
691+
Enables charging for the EVCC.
692+
Can be used as an indication to go to state C
693+
Relevant for:
694+
- ISO 15118-20
695+
"""

iso15118/evcc/controller/simulator.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,10 @@
108108
SelectedEnergyService,
109109
SelectedVAS,
110110
)
111-
from iso15118.shared.messages.iso15118_20.common_types import RationalNumber
111+
from iso15118.shared.messages.iso15118_20.common_types import (
112+
DisplayParameters,
113+
RationalNumber,
114+
)
112115
from iso15118.shared.messages.iso15118_20.dc import (
113116
BPTDCChargeParameterDiscoveryReqParams,
114117
BPTDynamicDCChargeLoopReqParams,
@@ -141,7 +144,8 @@ class SimEVController(EVControllerInterface):
141144

142145
def __init__(self, evcc_config: EVCCConfig):
143146
self.config = evcc_config
144-
self.charging_loop_cycles: int = evcc_config.charge_loop_cycle
147+
self.charging_loop_cycles: int = max(evcc_config.charge_loop_cycle, 1)
148+
self.increment = (1 / self.charging_loop_cycles) * 100
145149
self.precharge_loop_cycles: int = 0
146150
self.welding_detection_cycles: int = 0
147151
self._charging_is_completed = False
@@ -617,8 +621,19 @@ async def process_sa_schedules_v2(
617621

618622
async def continue_charging(self) -> bool:
619623
"""Overrides EVControllerInterface.continue_charging()."""
624+
# if self.charging_loop_cycles == 0 or await self.is_charging_complete():
625+
# # To simulate a bit of a charging loop, we'll let it run chargingLoopCycle
626+
# # times specified in config file
627+
# return False
628+
# else:
629+
# self.charging_loop_cycles -= 1
630+
# self._soc = min(int(self._soc + self.increment), 100)
631+
# # The line below can just be called once process_message in all states
632+
# # are converted to async calls
633+
# # await asyncio.sleep(0.5)
634+
# return True
620635
return not EVEREST_EV_STATE.StopCharging
621-
636+
622637
async def pause(self) -> bool:
623638
return EVEREST_EV_STATE.Pause
624639

@@ -772,14 +787,14 @@ async def get_dc_ev_status_dinspec(self) -> DCEVStatusDINSPEC:
772787
return DCEVStatusDINSPEC(
773788
ev_ready=True,
774789
ev_error_code=DCEVErrorCode.NO_ERROR,
775-
ev_ress_soc=60,
790+
ev_ress_soc=self._soc,
776791
)
777792

778793
async def get_dc_ev_status(self) -> DCEVStatus:
779794
return DCEVStatus(
780795
ev_ready=True,
781796
ev_error_code=DCEVErrorCode.NO_ERROR,
782-
ev_ress_soc=60,
797+
ev_ress_soc=self._soc,
783798
)
784799

785800
async def get_scheduled_dc_charge_loop_params(
@@ -864,6 +879,13 @@ async def enable_charging(self, enabled: bool) -> None:
864879
"""Overrides EVControllerInterface.enable_charging()."""
865880
pass
866881

882+
async def get_display_params(self) -> DisplayParameters:
883+
"""Overrides EVControllerInterface.get_display_params()."""
884+
return DisplayParameters(
885+
present_soc=self._soc,
886+
charging_complete=await self.is_charging_complete(),
887+
)
888+
867889
# ============================================================================
868890
# | SAE J2847/2 FUNCTIONS |
869891
# ============================================================================

iso15118/evcc/states/iso15118_20_states.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -857,8 +857,8 @@ async def process_message(
857857
else:
858858
bpt_channel_selection = ChannelSelection.CHARGE
859859

860+
await self.comm_session.ev_controller.enable_charging(True)
860861
if self.comm_session.selected_charging_type_is_ac:
861-
await self.comm_session.ev_controller.enable_charging(True)
862862
power_delivery_req = PowerDeliveryReq(
863863
header=MessageHeader(
864864
session_id=self.comm_session.session_id,
@@ -1006,6 +1006,7 @@ async def process_message(
10061006
session_id=self.comm_session.session_id,
10071007
timestamp=time.time(),
10081008
),
1009+
display_parameters=await self.comm_session.ev_controller.get_display_params(), # noqa
10091010
scheduled_params=scheduled_params,
10101011
dynamic_params=dynamic_params,
10111012
bpt_scheduled_params=bpt_scheduled_params,
@@ -1046,6 +1047,7 @@ async def process_message(
10461047
session_id=self.comm_session.session_id,
10471048
timestamp=time.time(),
10481049
),
1050+
display_parameters=await ev_controller.get_display_params(),
10491051
ev_present_voltage=await ev_controller.get_present_voltage(),
10501052
scheduled_params=scheduled_params,
10511053
dynamic_params=dynamic_params,
@@ -1092,15 +1094,15 @@ async def create_new_power_delivery_req(
10921094

10931095
# Information from EV to show if charging or discharging is planned
10941096
bpt_channel_selection = None
1095-
if self.comm_session.selected_energy_service in (
1097+
if self.comm_session.selected_energy_service.service in (
10961098
ServiceV20.AC_BPT,
10971099
ServiceV20.DC_BPT,
10981100
):
1099-
power_value = ev_power_profile.entry_list.entries.pop().power.value
1100-
if power_value < 0:
1101-
bpt_channel_selection = ChannelSelection.DISCHARGE
1102-
else:
1103-
bpt_channel_selection = ChannelSelection.CHARGE
1101+
bpt_channel_selection = ChannelSelection.CHARGE
1102+
if ev_power_profile is not None:
1103+
power_value = ev_power_profile.entry_list.entries[-1].power.value
1104+
if power_value < 0:
1105+
bpt_channel_selection = ChannelSelection.DISCHARGE
11041106

11051107
power_delivery_req = PowerDeliveryReq(
11061108
header=MessageHeader(
@@ -1328,6 +1330,7 @@ async def process_message(
13281330
session_id=self.comm_session.session_id,
13291331
timestamp=time.time(),
13301332
),
1333+
display_parameters=await self.comm_session.ev_controller.get_display_params(), # noqa
13311334
scheduled_params=scheduled_params,
13321335
dynamic_params=dynamic_params,
13331336
bpt_scheduled_params=bpt_scheduled_params,
@@ -1581,16 +1584,15 @@ async def build_power_delivery_req(self):
15811584

15821585
# Information from EV to show if charging or discharging is planned
15831586
bpt_channel_selection = None
1584-
if self.comm_session.selected_energy_service in (
1587+
if self.comm_session.selected_energy_service.service in (
15851588
ServiceV20.AC_BPT,
15861589
ServiceV20.DC_BPT,
15871590
):
1588-
power_value = ev_power_profile.entry_list.entries.pop().power.value
1589-
if power_value < 0:
1590-
bpt_channel_selection = ChannelSelection.DISCHARGE
1591-
else:
1592-
bpt_channel_selection = ChannelSelection.CHARGE
1593-
await self.comm_session.ev_controller.enable_charging(True)
1591+
bpt_channel_selection = ChannelSelection.CHARGE
1592+
if ev_power_profile is not None:
1593+
power_value = ev_power_profile.entry_list.entries[-1].power.value
1594+
if power_value < 0:
1595+
bpt_channel_selection = ChannelSelection.DISCHARGE
15941596
power_delivery_req = PowerDeliveryReq(
15951597
header=MessageHeader(
15961598
session_id=self.comm_session.session_id,
@@ -1713,6 +1715,7 @@ async def build_current_demand_data(self):
17131715
session_id=self.comm_session.session_id,
17141716
timestamp=time.time(),
17151717
),
1718+
display_parameters=await self.comm_session.ev_controller.get_display_params(), # noqa
17161719
ev_present_voltage=await self.comm_session.ev_controller.get_present_voltage(), # noqa
17171720
scheduled_params=scheduled_params,
17181721
dynamic_params=dynamic_params,

iso15118/secc/states/iso15118_20_states.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1609,7 +1609,15 @@ async def process_message(
16091609
if not self.cable_check_req_was_received:
16101610
# First DCCableCheckReq received. Start cable check.
16111611
await self.comm_session.evse_controller.start_cable_check()
1612+
self.cable_check_req_was_received = True
16121613

1614+
next_state = None
1615+
processing = EVSEProcessing.ONGOING
1616+
isolation_level = (
1617+
await self.comm_session.evse_controller.get_cable_check_status()
1618+
)
1619+
1620+
if isolation_level in [IsolationLevel.VALID, IsolationLevel.WARNING]:
16131621
# Requirement in 6.4.3.106 of the IEC 61851-23
16141622
# Any relays in the DC output circuit of the DC station shall
16151623
# be closed during the insulation test
@@ -1621,15 +1629,6 @@ async def process_message(
16211629
)
16221630
return
16231631

1624-
self.cable_check_req_was_received = True
1625-
1626-
next_state = None
1627-
processing = EVSEProcessing.ONGOING
1628-
isolation_level = (
1629-
await self.comm_session.evse_controller.get_cable_check_status()
1630-
)
1631-
1632-
if isolation_level in [IsolationLevel.VALID, IsolationLevel.WARNING]:
16331632
if isolation_level == IsolationLevel.WARNING:
16341633
logger.warning(
16351634
"Isolation resistance measured by EVSE is in Warning range"

iso15118/shared/comm_session.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ async def stop(self, reason: str):
413413
evse_controller = self.comm_session.evse_controller
414414
await evse_controller.update_data_link(terminate_or_pause)
415415
await evse_controller.session_ended(str(self.current_state), reason)
416+
elif hasattr(self.comm_session, "ev_controller"):
417+
await self.comm_session.ev_controller.enable_charging(False)
416418
logger.info(f"{terminate_or_pause}d the data link")
417419
await asyncio.sleep(3)
418420
try:

iso15118/shared/messages/iso15118_20/common_messages.py

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
(or class) that matches the definitions in the XSD schema, including the XSD
1111
element names by using the 'alias' attribute.
1212
"""
13+
1314
from dataclasses import dataclass
1415
from enum import Enum
1516
from typing import List, Tuple
@@ -821,30 +822,6 @@ def min_soc_less_than_or_equal_to_target_soc(cls, values):
821822

822823
return values
823824

824-
@root_validator(pre=True)
825-
def either_price_levels_or_absolute_prices(cls, values):
826-
"""
827-
Either price_level_schedule or absolute_price_schedule must be set,
828-
depending on abstract price levels or absolute prices are used to
829-
indicate costs for the charging session.
830-
831-
Pydantic validators are "class methods",
832-
see https://pydantic-docs.helpmanual.io/usage/validators/
833-
"""
834-
# pylint: disable=no-self-argument
835-
# pylint: disable=no-self-use
836-
if one_field_must_be_set(
837-
[
838-
"price_level_schedule",
839-
"PriceLevelSchedule",
840-
"absolute_price_schedule",
841-
"AbsolutePriceSchedule",
842-
],
843-
values,
844-
True,
845-
):
846-
return values
847-
848825

849826
class ScheduleExchangeRes(V2GResponse):
850827
"""See section 8.3.4.3.7.3 in ISO 15118-20"""

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "iso15118"
3-
version = "0.26.1"
3+
version = "0.27.0"
44
description = "Implementation of DIN SPEC 70121, ISO 15118-2 and -20 specs for SECC"
55
authors = ["André Duarte <andre@switch-ev.com>",
66
"Dr. Marc Mültin <marc@switch-ev.com>",

tests/iso15118_20/secc/test_iso15118_20_dc_states.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ async def test_15118_20_schedule_exchange_res(
212212
"cable_check_status, "
213213
"expected_state",
214214
[
215-
(False, False, None, Terminate),
215+
(False, False, IsolationLevel.VALID, Terminate),
216216
(False, True, None, None),
217217
(False, True, IsolationLevel.VALID, DCPreCharge),
218218
(True, True, None, None),

0 commit comments

Comments
 (0)