From c3ebf8c4323e9b09e09524a5137f277d1dbdc048 Mon Sep 17 00:00:00 2001 From: Niklas Hildebrandt Date: Tue, 23 Jun 2026 13:17:22 +0200 Subject: [PATCH] feat: add SCSP role (2.2.1 sessions + chargingprofiles receiver) The SCSP (Smart Charging Service Provider) is a receiver of Sessions and ChargingProfiles, so it reuses the existing eMSP receiver-side module routers. get_application now mounts them under the /scsp/ prefix when RoleEnum.scsp is enabled, e.g. /ocpi/scsp/2.2.1/sessions/{country_code}/{party_id}/{session_id}. Mirrors the PTP role wiring; no behaviour change for existing roles. Co-Authored-By: Claude Opus 4.8 (1M context) --- ocpi/core/routers/v_2_2_1/__init__.py | 7 ++++++- ocpi/main.py | 10 ++++++++++ ocpi/routers/__init__.py | 1 + ocpi/routers/v_2_2_1/scsp.py | 20 ++++++++++++++++++++ 4 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 ocpi/routers/v_2_2_1/scsp.py diff --git a/ocpi/core/routers/v_2_2_1/__init__.py b/ocpi/core/routers/v_2_2_1/__init__.py index 072723a..e107475 100644 --- a/ocpi/core/routers/v_2_2_1/__init__.py +++ b/ocpi/core/routers/v_2_2_1/__init__.py @@ -1,8 +1,13 @@ from ocpi.modules.versions import versions_v_2_2_1_router -from ocpi.routers import v_2_2_1_cpo_router, v_2_2_1_emsp_router +from ocpi.routers import ( + v_2_2_1_cpo_router, + v_2_2_1_emsp_router, + v_2_2_1_scsp_router, +) ROUTERS_DICT = { "version_router": versions_v_2_2_1_router, "cpo_router": v_2_2_1_cpo_router, "emsp_router": v_2_2_1_emsp_router, + "scsp_router": v_2_2_1_scsp_router, } diff --git a/ocpi/main.py b/ocpi/main.py index b2c86f8..f56dc31 100644 --- a/ocpi/main.py +++ b/ocpi/main.py @@ -271,6 +271,16 @@ def get_application( tags=[f"PTP {version.value}"], ) + if RoleEnum.scsp in roles: + for module in modules: + scsp_router = mapped_version.get("scsp_router", {}).get(module) # type: ignore[attr-defined] + if scsp_router: + _app.include_router( + scsp_router, # type: ignore[arg-type] + prefix=f"/{settings.OCPI_PREFIX}/scsp/{version.value}", + tags=[f"SCSP {version.value}"], + ) + def override_get_crud(): return crud diff --git a/ocpi/routers/__init__.py b/ocpi/routers/__init__.py index 1ebc9b5..96c8cd9 100644 --- a/ocpi/routers/__init__.py +++ b/ocpi/routers/__init__.py @@ -2,6 +2,7 @@ from .v_2_1_1.emsp import router as v_2_1_1_emsp_router from .v_2_2_1.cpo import router as v_2_2_1_cpo_router from .v_2_2_1.emsp import router as v_2_2_1_emsp_router +from .v_2_2_1.scsp import router as v_2_2_1_scsp_router from .v_2_3_0.cpo import router as v_2_3_0_cpo_router from .v_2_3_0.emsp import router as v_2_3_0_emsp_router from .v_2_3_0.ptp import router as v_2_3_0_ptp_router diff --git a/ocpi/routers/v_2_2_1/scsp.py b/ocpi/routers/v_2_2_1/scsp.py new file mode 100644 index 0000000..9a5c975 --- /dev/null +++ b/ocpi/routers/v_2_2_1/scsp.py @@ -0,0 +1,20 @@ +"""SCSP routers for OCPI 2.2.1. + +The SCSP (Smart Charging Service Provider) is a *receiver* of Sessions and +ChargingProfiles, so it reuses the eMSP receiver-side module routers (the +receiver interface is identical). Mounted under the ``/scsp/`` prefix by +``get_application``. +""" + +from ocpi.core.enums import ModuleID +from ocpi.modules.chargingprofiles.v_2_2_1.api import ( + emsp_router as chargingprofiles_emsp_2_2_1_router, +) +from ocpi.modules.sessions.v_2_2_1.api import ( + emsp_router as sessions_emsp_2_2_1_router, +) + +router = { + ModuleID.sessions: sessions_emsp_2_2_1_router, + ModuleID.charging_profile: chargingprofiles_emsp_2_2_1_router, +}