diff --git a/iso15118/evcc/evcc_settings.py b/iso15118/evcc/evcc_settings.py index bec38e63..0a8e31d8 100644 --- a/iso15118/evcc/evcc_settings.py +++ b/iso15118/evcc/evcc_settings.py @@ -6,7 +6,7 @@ import environs from iso15118.shared.network import validate_nic -from iso15118.shared.settings import shared_settings +from iso15118.shared.settings import load_shared_settings, shared_settings logger = logging.getLogger(__name__) @@ -42,6 +42,7 @@ def load_envs(self, env_path: Optional[str] = None) -> None: default="iso15118/shared/examples/evcc/iso15118_2/evcc_config_eim_ac.json", ) env.seal() # raise all errors at once, if any + load_shared_settings() logger.info("EVCC environment settings:") for key, value in shared_settings.items(): logger.info(f"{key:30}: {value}") diff --git a/iso15118/secc/controller/simulator.py b/iso15118/secc/controller/simulator.py index 8ed9ecaf..4beac94e 100644 --- a/iso15118/secc/controller/simulator.py +++ b/iso15118/secc/controller/simulator.py @@ -170,7 +170,7 @@ load_cert, load_priv_key, ) -from iso15118.shared.settings import V20_EVSE_SERVICES_CONFIG +from iso15118.shared.settings import SettingKey, shared_settings from iso15118.shared.states import State logger = logging.getLogger(__name__) @@ -273,7 +273,9 @@ def get_evse_context(): # enum value of the energy transfer mode and value is the service parameter async def read_service_id_parameter_mappings(): try: - async with async_open(V20_EVSE_SERVICES_CONFIG, "r") as v20_service_config: + async with async_open( + shared_settings[SettingKey.V20_SERVICE_CONFIG], "r" + ) as v20_service_config: try: json_mapping = await v20_service_config.read() v20_service_parameter_mapping = V20ServiceParamMapping.parse_raw( @@ -283,11 +285,11 @@ async def read_service_id_parameter_mappings(): except ValueError as exc: raise ValueError( f"Error reading 15118-20 service parameters settings file" - f" at {V20_EVSE_SERVICES_CONFIG}" + f" at {shared_settings[SettingKey.V20_SERVICE_CONFIG]}" ) from exc except (FileNotFoundError, IOError) as exc: raise FileNotFoundError( - f"V20 config not found at {V20_EVSE_SERVICES_CONFIG}" + f"V20 config not found at {shared_settings[SettingKey.V20_SERVICE_CONFIG]}" ) from exc diff --git a/iso15118/secc/main.py b/iso15118/secc/main.py index b33dc720..1bc50a13 100644 --- a/iso15118/secc/main.py +++ b/iso15118/secc/main.py @@ -17,7 +17,7 @@ async def main(): """ config = Config() config.load_envs() - config.log_settings() + config.print_settings() sim_evse_controller = await SimEVSEController.create() await sim_evse_controller.set_status(ServiceStatus.STARTING) diff --git a/iso15118/secc/secc_settings.py b/iso15118/secc/secc_settings.py index 430c173a..32a1fcc3 100644 --- a/iso15118/secc/secc_settings.py +++ b/iso15118/secc/secc_settings.py @@ -7,7 +7,7 @@ from iso15118.secc.controller.interface import EVSEControllerInterface from iso15118.shared.messages.enums import AuthEnum, Protocol -from iso15118.shared.settings import shared_settings +from iso15118.shared.settings import load_shared_settings, shared_settings from iso15118.shared.utils import load_requested_auth_modes, load_requested_protocols logger = logging.getLogger(__name__) @@ -16,7 +16,7 @@ @dataclass class Config: iface: Optional[str] = None - log_level: Optional[int] = None + log_level: Optional[str] = None evse_controller: Type[EVSEControllerInterface] = None enforce_tls: bool = False free_charging_service: bool = False @@ -37,6 +37,7 @@ class Config: "EIM", "PNC", ] + env_dump: Optional[dict] = None def load_envs(self, env_path: Optional[str] = None) -> None: """ @@ -102,13 +103,12 @@ def load_envs(self, env_path: Optional[str] = None) -> None: # enum values in PowerDeliveryReq's ChargeProgress field). In Standby, the # EV can still use value-added services while not consuming any power. self.standby_allowed = env.bool("STANDBY_ALLOWED", default=False) - + load_shared_settings(env_path) env.seal() # raise all errors at once, if any - self.secc_env = env.dump() + self.env_dump = dict(env.dump()) + self.env_dump.update(shared_settings) - def log_settings(self): + def print_settings(self): logger.info("SECC settings:") - for key, value in shared_settings.items(): - logger.info(f"{key:30}: {value}") - for key, value in self.secc_env.items(): + for key, value in self.env_dump.items(): logger.info(f"{key:30}: {value}") diff --git a/iso15118/shared/exi_codec.py b/iso15118/shared/exi_codec.py index 3e0de975..c958f434 100644 --- a/iso15118/shared/exi_codec.py +++ b/iso15118/shared/exi_codec.py @@ -71,7 +71,7 @@ DCWeldingDetectionReq, DCWeldingDetectionRes, ) -from iso15118.shared.settings import MESSAGE_LOG_EXI, MESSAGE_LOG_JSON +from iso15118.shared.settings import SettingKey, shared_settings logger = logging.getLogger(__name__) @@ -244,7 +244,7 @@ def to_exi(self, msg_element: BaseModel, protocol_ns: str) -> bytes: {exc}" ) from exc - if MESSAGE_LOG_JSON: + if shared_settings[SettingKey.MESSAGE_LOG_EXI]: logger.info(f"Message to encode (ns={protocol_ns}): {msg_content}") try: @@ -257,7 +257,7 @@ def to_exi(self, msg_element: BaseModel, protocol_ns: str) -> bytes: f"EXIEncodingError for {str(msg_element)}: " f"{exc}" ) from exc - if MESSAGE_LOG_EXI: + if shared_settings[SettingKey.MESSAGE_LOG_EXI]: logger.debug(f"EXI-encoded message: {exi_stream.hex()}") return exi_stream @@ -283,7 +283,7 @@ def from_exi( Raises: EXIDecodingError """ - if MESSAGE_LOG_EXI: + if shared_settings[SettingKey.MESSAGE_LOG_EXI]: logger.debug(f"EXI-encoded message (ns={namespace}): {exi_message.hex()}") try: @@ -300,7 +300,7 @@ def from_exi( f"processing decoded EXI: {exc}" ) from exc - if MESSAGE_LOG_JSON: + if shared_settings[SettingKey.MESSAGE_LOG_JSON]: logger.info(f"Decoded message (ns={namespace}): {exi_decoded}") try: diff --git a/iso15118/shared/security.py b/iso15118/shared/security.py index a9264b97..63109867 100644 --- a/iso15118/shared/security.py +++ b/iso15118/shared/security.py @@ -80,7 +80,7 @@ Transform, Transforms, ) -from iso15118.shared.settings import ENABLE_TLS_1_3, PKI_PATH +from iso15118.shared.settings import SettingKey, shared_settings logger = logging.getLogger(__name__) @@ -128,7 +128,7 @@ def get_ssl_context(server_side: bool) -> Optional[SSLContext]: as well as read the password. """ - if ENABLE_TLS_1_3: + if shared_settings[SettingKey.ENABLE_TLS_1_3]: ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS) else: # Specifying protocol as `PROTOCOL_TLS` does best effort. @@ -160,7 +160,7 @@ def get_ssl_context(server_side: bool) -> Optional[SSLContext]: logger.exception(exc) return None - if ENABLE_TLS_1_3: + if shared_settings[SettingKey.ENABLE_TLS_1_3]: # In 15118-20 we should also verify EVCC's certificate chain. # The spec however says TLS 1.3 should also support 15118-2 # (Table 5 in V2G20 specification) @@ -201,7 +201,7 @@ def get_ssl_context(server_side: bool) -> Optional[SSLContext]: "ECDHE-ECDSA-AES128-SHA256" ) - if ENABLE_TLS_1_3: + if shared_settings[SettingKey.ENABLE_TLS_1_3]: try: ssl_context.load_cert_chain( certfile=CertPath.OEM_CERT_CHAIN_PEM, @@ -1449,34 +1449,39 @@ class CertPath(str, Enum): """ # Mobility operator (MO) - CONTRACT_LEAF_DER = os.path.join(PKI_PATH, "iso15118_2/certs/contractLeafCert.der") - MO_SUB_CA2_DER = os.path.join(PKI_PATH, "iso15118_2/certs/moSubCA2Cert.der") - MO_SUB_CA1_DER = os.path.join(PKI_PATH, "iso15118_2/certs/moSubCA1Cert.der") - MO_ROOT_DER = os.path.join(PKI_PATH, "iso15118_2/certs/moRootCACert.der") + CONTRACT_LEAF_DER = "contractLeafCert.der" + MO_SUB_CA2_DER = "moSubCA2Cert.der" + MO_SUB_CA1_DER = "moSubCA1Cert.der" + MO_ROOT_DER = "moRootCACert.der" # Charge point operator (CPO) - SECC_LEAF_DER = os.path.join(PKI_PATH, "iso15118_2/certs/seccLeafCert.der") - SECC_LEAF_PEM = os.path.join(PKI_PATH, "iso15118_2/certs/seccLeafCert.pem") - CPO_SUB_CA2_DER = os.path.join(PKI_PATH, "iso15118_2/certs/cpoSubCA2Cert.der") - CPO_SUB_CA1_DER = os.path.join(PKI_PATH, "iso15118_2/certs/cpoSubCA1Cert.der") - V2G_ROOT_DER = os.path.join(PKI_PATH, "iso15118_2/certs/v2gRootCACert.der") - V2G_ROOT_PEM = os.path.join(PKI_PATH, "iso15118_2/certs/v2gRootCACert.pem") + SECC_LEAF_DER = "seccLeafCert.der" + SECC_LEAF_PEM = "seccLeafCert.pem" + CPO_SUB_CA2_DER = "cpoSubCA2Cert.der" + CPO_SUB_CA1_DER = "cpoSubCA1Cert.der" + V2G_ROOT_DER = "v2gRootCACert.der" + V2G_ROOT_PEM = "v2gRootCACert.pem" # Needed for the 'certfile' parameter in ssl_context.load_cert_chain() - CPO_CERT_CHAIN_PEM = os.path.join(PKI_PATH, "iso15118_2/certs/cpoCertChain.pem") + CPO_CERT_CHAIN_PEM = "cpoCertChain.pem" # Certificate provisioning service (CPS) - CPS_LEAF_DER = os.path.join(PKI_PATH, "iso15118_2/certs/cpsLeafCert.der") - CPS_SUB_CA2_DER = os.path.join(PKI_PATH, "iso15118_2/certs/cpsSubCA2Cert.der") - CPS_SUB_CA1_DER = os.path.join(PKI_PATH, "iso15118_2/certs/cpsSubCA1Cert.der") + CPS_LEAF_DER = "cpsLeafCert.der" + CPS_SUB_CA2_DER = "cpsSubCA2Cert.der" + CPS_SUB_CA1_DER = "cpsSubCA1Cert.der" # The root is the V2G_ROOT # EV manufacturer (OEM) - OEM_LEAF_DER = os.path.join(PKI_PATH, "iso15118_2/certs/oemLeafCert.der") - OEM_SUB_CA2_DER = os.path.join(PKI_PATH, "iso15118_2/certs/oemSubCA2Cert.der") - OEM_SUB_CA1_DER = os.path.join(PKI_PATH, "iso15118_2/certs/oemSubCA1Cert.der") - OEM_ROOT_DER = os.path.join(PKI_PATH, "iso15118_2/certs/oemRootCACert.der") - OEM_ROOT_PEM = os.path.join(PKI_PATH, "iso15118_2/certs/oemRootCACert.pem") - OEM_CERT_CHAIN_PEM = os.path.join(PKI_PATH, "iso15118_2/certs/oemCertChain.pem") + OEM_LEAF_DER = "oemLeafCert.der" + OEM_SUB_CA2_DER = "oemSubCA2Cert.der" + OEM_SUB_CA1_DER = "oemSubCA1Cert.der" + OEM_ROOT_DER = "oemRootCACert.der" + OEM_ROOT_PEM = "oemRootCACert.pem" + OEM_CERT_CHAIN_PEM = "oemCertChain.pem" + + def __get__(self, instance, owner): + return os.path.join( + shared_settings[SettingKey.PKI_PATH], "iso15118_2/certs/", self.value + ) class KeyPath(str, Enum): @@ -1489,30 +1494,35 @@ class KeyPath(str, Enum): """ # Mobility operator (MO) - CONTRACT_LEAF_PEM = os.path.join( - PKI_PATH, "iso15118_2/private_keys/contractLeaf" ".key" - ) - MO_SUB_CA2_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/moSubCA2.key") - MO_SUB_CA1_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/moSubCA1.key") - MO_ROOT_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/moRootCA.key") + CONTRACT_LEAF_PEM = "contractLeaf.key" + MO_SUB_CA2_PEM = "moSubCA2.key" + MO_SUB_CA1_PEM = "moSubCA1.key" + MO_ROOT_PEM = "moRootCA.key" # Charge point operator (CPO) - SECC_LEAF_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/seccLeaf.key") - CPO_SUB_CA2_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/cpoSubCA2.key") - CPO_SUB_CA1_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/cpoSubCA1.key") - V2G_ROOT_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/v2gRootCA.key") + SECC_LEAF_PEM = "seccLeaf.key" + CPO_SUB_CA2_PEM = "cpoSubCA2.key" + CPO_SUB_CA1_PEM = "cpoSubCA1.key" + V2G_ROOT_PEM = "v2gRootCA.key" # Certificate provisioning service (CPS) - CPS_LEAF_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/cpsLeaf.key") - CPS_SUB_CA2_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/cpsSubCA2.key") - CPS_SUB_CA1_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/cpsSubCA1.key") + CPS_LEAF_PEM = "cpsLeaf.key" + CPS_SUB_CA2_PEM = "cpsSubCA2.key" + CPS_SUB_CA1_PEM = "cpsSubCA1.key" # The root is the V2G_ROOT # EV manufacturer (OEM) - OEM_LEAF_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/oemLeaf.key") - OEM_SUB_CA2_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/oemSubCA2.key") - OEM_SUB_CA1_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/oemSubCA1.key") - OEM_ROOT_PEM = os.path.join(PKI_PATH, "iso15118_2/private_keys/oemRootCA.key") + OEM_LEAF_PEM = "oemLeaf.key" + OEM_SUB_CA2_PEM = "oemSubCA2.key" + OEM_SUB_CA1_PEM = "oemSubCA1.key" + OEM_ROOT_PEM = "oemRootCA.key" + + def __get__(self, instance, owner): + return os.path.join( + shared_settings[SettingKey.PKI_PATH], + "iso15118_2/private_keys/", + self.value, + ) class KeyPasswordPath(str, Enum): @@ -1524,18 +1534,15 @@ class KeyPasswordPath(str, Enum): """ # Private key password paths - SECC_LEAF_KEY_PASSWORD = os.path.join( - PKI_PATH, "iso15118_2/private_keys/seccLeafPassword.txt" - ) - OEM_LEAF_KEY_PASSWORD = os.path.join( - PKI_PATH, "iso15118_2/private_keys/oemLeafPassword.txt" - ) - CONTRACT_LEAF_KEY_PASSWORD = os.path.join( - PKI_PATH, "iso15118_2/private_keys/contractLeafPassword.txt" - ) - CPS_LEAF_KEY_PASSWORD = os.path.join( - PKI_PATH, "iso15118_2/private_keys/cpsLeafPassword.txt" - ) - MO_SUB_CA2_PASSWORD = os.path.join( - PKI_PATH, "iso15118_2/private_keys/moSubCA2LeafPassword.txt" - ) + SECC_LEAF_KEY_PASSWORD = "seccLeafPassword.txt" + OEM_LEAF_KEY_PASSWORD = "oemLeafPassword.txt" + CONTRACT_LEAF_KEY_PASSWORD = "contractLeafPassword.txt" + CPS_LEAF_KEY_PASSWORD = "cpsLeafPassword.txt" + MO_SUB_CA2_PASSWORD = "moSubCA2LeafPassword.txt" + + def __get__(self, instance, owner): + return os.path.join( + shared_settings[SettingKey.PKI_PATH], + "iso15118_2/private_keys/", + self.value, + ) diff --git a/iso15118/shared/settings.py b/iso15118/shared/settings.py index e369127a..1c62d439 100644 --- a/iso15118/shared/settings.py +++ b/iso15118/shared/settings.py @@ -1,28 +1,37 @@ import os +from typing import Optional import environs -SHARED_CWD = os.path.dirname(os.path.abspath(__file__)) -JAR_FILE_PATH = SHARED_CWD + "/EXICodec.jar" - -WORK_DIR = os.getcwd() -ENV_PATH = WORK_DIR + "/.env" +class SettingKey: + PKI_PATH = "PKI_PATH" + MESSAGE_LOG_JSON = "MESSAGE_LOG_JSON" + MESSAGE_LOG_EXI = "MESSAGE_LOG_EXI" + V20_SERVICE_CONFIG = "V20_SERVICE_CONFIG" + ENABLE_TLS_1_3 = "ENABLE_TLS_1_3" -env = environs.Env(eager=False) -env.read_env(path=ENV_PATH) # read .env file, if it exists -PKI_PATH = env.path("PKI_PATH", default=SHARED_CWD + "/pki/") - -MESSAGE_LOG_JSON = env.bool("MESSAGE_LOG_JSON", default=True) -MESSAGE_LOG_EXI = env.bool("MESSAGE_LOG_EXI", default=False) +shared_settings = {} +SHARED_CWD = os.path.dirname(os.path.abspath(__file__)) +JAR_FILE_PATH = SHARED_CWD + "/EXICodec.jar" -V20_EVSE_SERVICES_CONFIG = env.str( - "V20_SERVICE_CONFIG", - default=SHARED_CWD + "/examples/secc/15118_20/service_config.json", -) +WORK_DIR = os.getcwd() -ENABLE_TLS_1_3 = env.bool("ENABLE_TLS_1_3", default=False) -env.seal() # raise all errors at once, if any -shared_settings = env.dump() +def load_shared_settings(env_path: Optional[str] = None): + env = environs.Env(eager=False) + env.read_env(path=env_path) # read .env file, if it exists + + settings = { + SettingKey.PKI_PATH: env.str("PKI_PATH", default=SHARED_CWD + "/pki/"), + SettingKey.MESSAGE_LOG_JSON: env.bool("MESSAGE_LOG_JSON", default=True), + SettingKey.MESSAGE_LOG_EXI: env.bool("MESSAGE_LOG_EXI", default=False), + SettingKey.V20_SERVICE_CONFIG: env.str( + "V20_SERVICE_CONFIG", + default=SHARED_CWD + "/examples/secc/15118_20/service_config.json", + ), + SettingKey.ENABLE_TLS_1_3: env.bool("ENABLE_TLS_1_3", default=False), + } + shared_settings.update(settings) + env.seal() # raise all errors at once, if any diff --git a/poetry.lock b/poetry.lock index c06467cb..347fd920 100644 --- a/poetry.lock +++ b/poetry.lock @@ -318,13 +318,13 @@ tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, ] [package.extras] @@ -501,13 +501,13 @@ files = [ [[package]] name = "platformdirs" -version = "3.11.0" +version = "4.0.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, - {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, + {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, + {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, ] [package.extras] @@ -677,13 +677,13 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-asyncio" -version = "0.22.0" +version = "0.21.1" description = "Pytest support for asyncio" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "pytest-asyncio-0.22.0.tar.gz", hash = "sha256:01da1bf94ff0b969cc8d760104f7c1011903d0d658bdaef0bbae769660a7fbc4"}, - {file = "pytest_asyncio-0.22.0-py3-none-any.whl", hash = "sha256:c09905acb3b79827aace4c67fe15097daea1b363c00c8236875395414914bad3"}, + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, ] [package.dependencies] diff --git a/tests/iso15118_2/secc/states/test_iso15118_2_states.py b/tests/iso15118_2/secc/states/test_iso15118_2_states.py index 597f4c6d..94622709 100644 --- a/tests/iso15118_2/secc/states/test_iso15118_2_states.py +++ b/tests/iso15118_2/secc/states/test_iso15118_2_states.py @@ -53,6 +53,7 @@ ) from iso15118.shared.messages.iso15118_2.msgdef import V2GMessage as V2GMessageV2 from iso15118.shared.security import get_random_bytes +from iso15118.shared.settings import load_shared_settings from iso15118.shared.states import Pause from tests.iso15118_2.secc.states.test_messages import ( get_charge_parameter_discovery_req_message_departure_time_one_hour, @@ -92,6 +93,7 @@ def _comm_session(self, comm_secc_session_mock): self.comm_session.writer = Mock() self.comm_session.writer.get_extra_info = Mock() self.comm_session.evse_controller.evse_data_context = self.get_evse_data() + load_shared_settings() def get_evse_data(self) -> EVSEDataContext: dc_limits = EVSEDCCPDLimits( diff --git a/tests/iso15118_20/secc/test_iso15118_20_ac_states.py b/tests/iso15118_20/secc/test_iso15118_20_ac_states.py index c00ca2db..2dad9c77 100644 --- a/tests/iso15118_20/secc/test_iso15118_20_ac_states.py +++ b/tests/iso15118_20/secc/test_iso15118_20_ac_states.py @@ -68,6 +68,7 @@ ResponseCode, ) from iso15118.shared.notifications import StopNotification +from iso15118.shared.settings import load_shared_settings from iso15118.shared.states import Terminate from tests.dinspec.secc.test_dinspec_secc_states import MockWriter from tests.iso15118_20.secc.test_messages import ( @@ -99,6 +100,7 @@ def _comm_session(self): self.comm_session.evse_controller.ev_data_context = EVDataContext( ev_rated_limits=EVRatedLimits(ac_limits=EVACCPDLimits()) ) + load_shared_settings() def get_evse_data(self) -> EVSEDataContext: ac_limits = EVSEACCPDLimits( diff --git a/tests/iso15118_20/secc/test_iso15118_20_dc_states.py b/tests/iso15118_20/secc/test_iso15118_20_dc_states.py index fb51e0a9..9abeb731 100644 --- a/tests/iso15118_20/secc/test_iso15118_20_dc_states.py +++ b/tests/iso15118_20/secc/test_iso15118_20_dc_states.py @@ -59,6 +59,7 @@ ScheduledDCChargeLoopResParams, ) from iso15118.shared.notifications import StopNotification +from iso15118.shared.settings import load_shared_settings from iso15118.shared.states import State, Terminate from tests.dinspec.secc.test_dinspec_secc_states import MockWriter from tests.iso15118_20.secc.test_messages import ( @@ -90,6 +91,7 @@ def _comm_session(self): self.comm_session.evse_controller.ev_data_context = EVDataContext( ev_rated_limits=EVRatedLimits(dc_limits=EVDCCPDLimits()) ) + load_shared_settings() def get_evse_data(self) -> EVSEDataContext: dc_limits = EVSEDCCPDLimits(