A production-quality, full-featured EMSP simulator for validating OCPI 2.2.1 CPO implementations
Overview Β· Features Β· Quick Start Β· Usage Β· Contributing Β· Contact
Savekar is an Indian EV technology company building the infrastructure for the electric vehicle revolution. We develop open, standards-based software for EV charging networks β including Charge Point Management Systems (CPMS), OCPP & OCPI protocol stacks, and fleet management tooling.
We believe open-source collaboration is key to accelerating EV adoption. This simulator is one of our open-source contributions to the global EV developer community.
π Website: savekar.com π§ Contact: savekarev@gmail.com π¬ Discord: Join our community πΌ GitHub Org: github.com/savekar
Are you building a production-grade CPO and want to validate your OCPI implementation against a real EMSP before going live with a roaming partner?
We offer connectivity testing against our hosted EMSP simulator. Reach out to us and we'll help you verify your OCPI handshake, Location pushes, Session updates, CDR submissions, Commands, and Tokens are spec-compliant.
- π§ Email: savekarev@gmail.com
- π¬ GitHub: Open an issue or discussion on this repository
- π¬ Discord: Join our community for discussions and support
- π More details: https://savekar.com/ocpi-simulator
The OCPI 2.2.1 EMSP Simulator is a comprehensive, developer-focused tool designed to simulate an e-Mobility Service Provider (EMSP) that communicates strictly via the Open Charge Point Interface (OCPI) 2.2.1 protocol.
It is used to validate that a Charge Point Operator (CPO) backend correctly implements the OCPI 2.2.1 specification β covering credentials exchange, location synchronization, token management, session lifecycle, commands, and CDR submission β before integrating with real roaming partners.
| Limitation | Details |
|---|---|
| Not a Production EMSP | Testing-only tool. Does not handle real payments, user management, or business logic. |
| OCPI 2.2.1 Only | Strictly adheres to OCPI version 2.2.1. |
| Partial Commands Support | START_SESSION and STOP_SESSION are supported. UNLOCK_CONNECTOR and RESERVE_NOW return NOT_SUPPORTED. |
| Schema Validation | Uses official OCPI 2.2.1 JSON schemas. May not cover every edge case of the full specification. |
This simulator is built for:
- Backend Engineers building CPO platforms who need EMSP validation.
- EV Platform Developers testing OCPI compliance before going live with roaming partners.
- QA & Integration Teams running automated protocol validation pipelines.
- β OCPI endpoint direction and correct usage
- β Credentials handshake (Token A β B β C exchange)
- β Token rotation (PUT /credentials)
- β Schema correctness for Locations, Sessions, CDRs, Tokens, and Commands
- β OCPI response envelope and status code semantics
- β EVSE status PATCH updates
- β Token registration and management (RFID, APP_USER, OTHER)
- β Command handling (START_SESSION, STOP_SESSION) with async callbacks
- β Session lifecycle (PUT full session, PATCH updates, GET queries)
- β CDR ingestion and validation with pagination
- β Date filtering and pagination on Sessions and CDRs
- β Commercial settlement or billing rules
- β Partner-specific extensions or quirks
- β Certification-level compliance
- β Real-world EMSP operational behavior
- β UNLOCK_CONNECTOR and RESERVE_NOW commands (returns NOT_SUPPORTED)
The EMSP Simulator is designed with a clear separation between passive endpoints (for CPO-initiated pushes) and active test clients (for EMSP-initiated requests).
flowchart TB
CPO(("π€ Target CPO Backend<br/>(Under Test)"))
subgraph "OCPI 2.2.1 EMSP Simulator"
direction TB
UI["π» Web Dashboard<br/>(ui/)"]
Tests["π€ Active Test Client<br/>(verify_cpo.py)"]
subgraph "FastAPI Server"
direction LR
Endpoints["π OCPI Endpoints<br/>(app/routes)"]
Validators{"β
Schema Validation<br/>(app/validators)"}
State[("π§ State Manager<br/>(app/state.py)")]
Endpoints --> Validators
Validators --> State
end
UI -.->|Reads state| State
end
CPO == "HTTP POST/PUT/PATCH<br/>(Push Sessions, CDRs)" ==> Endpoints
CPO == "HTTP GET<br/>(Pull Locations, Tariffs)" ==> Endpoints
Tests == "HTTP GET/POST<br/>(Test CPO All Endpoints)" ==> CPO
| Feature | Description |
|---|---|
| Full OCPI 2.2.1 Compliance | Implements all core modules: Versions, Credentials, Locations, Tokens, Sessions, Commands, CDRs |
| Strict Schema Validation | Validates incoming OCPI data against official 2.2.1 JSON schemas. HTTP status is configurable (200 or 400). |
| Credentials Handshake | Full implementation of the CREDENTIALS module including token rotation (PUT). |
| Token Management | Complete Token module support (PUT, PATCH, GET) for RFID, APP_USER, and OTHER token types. |
| Command Support | START_SESSION and STOP_SESSION commands with async callback handling. |
| Session Management | Full session lifecycle with PUT (creation), PATCH (updates), and GET (queries). |
| CDR Ingestion | Accepts and validates Charge Detail Records with pagination support. |
| Pagination & Filtering | Sessions and CDRs support offset/limit pagination and date range filtering. |
| Active Test Client | Comprehensive CPO client that calls all CPO endpoints for validation. |
| Structured Logging | Context-rich logs with direction, module, and payload details. |
| Web Dashboard | Comprehensive browser-based dashboard with real-time stats, token management, commands, and state inspection. |
| Verification Script | verify_cpo.py β one-command PASS/FAIL validation of all 16 endpoint categories. |
- Python 3.8 or higher
- pip (Python package installer)
- A running CPO implementation to test against
git clone https://github.com/savekar/OCPI-2.2.1-EMSP-Simulator.git
cd OCPI-2.2.1-EMSP-Simulatorpip install -r requirements.txtTip: Use a virtual environment to keep your dependencies isolated:
python -m venv venv source venv/bin/activate # Linux/macOS venv\Scripts\activate.bat # Windows pip install -r requirements.txt
Copy the example configuration and edit it for your environment:
cp config.example.yaml config.yaml
# On Windows (if cp is not available):
# copy config.example.yaml config.yamlEdit config.yaml with your CPO's details:
| Setting | Description | Default |
|---|---|---|
host |
Interface to bind to | 127.0.0.1 |
port |
Port to listen on | 8000 |
party_id |
EMSP party ID (3 letters) | ION |
country_code |
EMSP country code (2 letters) | IN |
bootstrap_token |
Token expected from CPO for initial handshake (Token A) | β |
emsp_token_to_cpo |
Token sent by Simulator to CPO in requests (Token C) | β |
cpo_token_to_emsp |
Token expected from CPO after handshake (Token B) | β |
cpo_url |
Base URL of your CPO's OCPI API | β |
python run.pyThe simulator will start at http://127.0.0.1:8000 (or your configured host/port).
Open your browser and navigate to http://localhost:8000 to access the Web Dashboard, where you can:
- Configure connection settings and EMSP identity
- Perform credentials handshake and token rotation
- Register and manage tokens
- Send START_SESSION and STOP_SESSION commands
- View real-time statistics (tokens, sessions, CDRs, commands)
- Monitor logs and inspect simulator state
| Module | Method | Endpoint | Description |
|---|---|---|---|
| Versions | GET |
/ocpi/versions |
Return available OCPI versions |
| Versions | GET |
/ocpi/emsp/2.2.1 |
Return EMSP endpoint details |
| Credentials | GET, POST, PUT |
/ocpi/emsp/2.2.1/credentials |
Credentials exchange and token rotation |
| Locations | PATCH |
/ocpi/emsp/2.2.1/locations/{id}/{evse_uid} |
Receive EVSE status updates |
| Sessions | GET, PUT, PATCH |
/ocpi/emsp/2.2.1/sessions/{...} |
Session management |
| CDRs | GET, POST |
/ocpi/emsp/2.2.1/cdrs/{...} |
CDR ingestion and retrieval |
| Tokens | GET, PUT, PATCH |
/ocpi/emsp/2.2.1/tokens/{cc}/{party}/{uid} |
Token registration and management |
| Commands | POST |
/ocpi/emsp/2.2.1/commands/START_SESSION |
Start charging session |
| Commands | POST |
/ocpi/emsp/2.2.1/commands/STOP_SESSION |
Stop charging session |
| Commands | POST |
/ocpi/emsp/2.2.1/commands/UNLOCK_CONNECTOR |
Not supported |
| Commands | POST |
/ocpi/emsp/2.2.1/commands/RESERVE_NOW |
Not supported |
| Module | Method | Endpoint | Description |
|---|---|---|---|
| Versions | GET |
/ocpi/versions |
Get available versions |
| Versions | GET |
/ocpi/cpo/2.2.1/details |
Get CPO endpoint details |
| Credentials | GET, POST, PUT |
/ocpi/cpo/2.2.1/credentials |
Credentials exchange |
| Locations | GET |
/ocpi/cpo/2.2.1/locations/{id} |
Get locations with pagination |
| Tariffs | GET |
/ocpi/cpo/2.2.1/tariffs/{id} |
Get tariffs |
| Sessions | GET |
/ocpi/cpo/2.2.1/sessions/{id} |
Get sessions with pagination |
| CDRs | GET |
/ocpi/cpo/2.2.1/cdrs/{id} |
Get CDRs with pagination |
| Tokens | GET, PUT, PATCH |
/ocpi/cpo/2.2.1/tokens/{cc}/{party}/{uid} |
Token operations |
| Commands | POST |
/ocpi/cpo/2.2.1/commands/START_SESSION |
Start session command |
| Commands | POST |
/ocpi/cpo/2.2.1/commands/STOP_SESSION |
Stop session command |
| Commands | POST |
/ocpi/cpo/2.2.1/commands/UNLOCK_CONNECTOR |
Unlock connector (not supported) |
| Commands | POST |
/ocpi/cpo/2.2.1/commands/RESERVE_NOW |
Reserve now (not supported) |
Your CPO must initiate the connection by performing the OCPI credentials exchange:
- Ensure
bootstrap_tokeninconfig.yamlmatches what your CPO will send. - From your CPO, send a
POSTrequest to:POST http://localhost:8000/ocpi/emsp/2.2.1/credentials Authorization: Token <bootstrap_token> - The simulator validates your request, stores your credentials, and returns its own (including
emsp_token_to_cpo).
Use the bundled script to actively test your CPO's OCPI endpoints:
python verify_cpo.pyThis script will test 16 endpoint categories:
- GET /versions
- GET /2.2.1/details
- POST /2.2.1/credentials (Handshake)
- GET /2.2.1/credentials
- GET /2.2.1/locations
- GET /2.2.1/tariffs
- PUT /2.2.1/tokens (Register token)
- GET /2.2.1/tokens (Retrieve token)
- PATCH /2.2.1/tokens (Update token)
- POST /2.2.1/commands/START_SESSION
- POST /2.2.1/commands/STOP_SESSION
- POST /2.2.1/commands/UNLOCK_CONNECTOR
- POST /2.2.1/commands/RESERVE_NOW
- GET /2.2.1/sessions
- GET /2.2.1/cdrs
- PUT /2.2.1/credentials (Token Rotation)
The simulator writes structured logs to stdout and optionally to a file (configured in config.yaml):
[CPOβEMSP][credentials] Invalid Token {Token=abc123...}
[EMSPβCPO][sessions] Session update accepted {session_id=xyz}
Format: [Direction][Module] Message {Context}
The simulator includes a comprehensive web dashboard accessible at http://localhost:8000 (or your configured host/port).
- Tokens Counter: Shows number of registered tokens
- Sessions Counter: Shows active and completed sessions
- CDRs Counter: Shows received Charge Detail Records
- Commands Counter: Shows executed commands
- Auto-refreshes every 5 seconds
- Update CPO API URL
- Configure Bootstrap Token (Token A)
- Set EMSP Party ID and Country Code
- Credentials Exchange (POST)
- Get Credentials (GET)
- Token Rotation (PUT)
- Get Versions and Details
- Fetch Locations and Tariffs
- Register New Tokens:
- Support for RFID, APP_USER, and OTHER types
- Whitelist configuration (ALLOWED, ALWAYS, ALLOWED_OFFLINE, NEVER)
- Valid/Invalid status
- Update Tokens: Enable or disable existing tokens
- Query Tokens: Retrieve token details by UID
- START_SESSION: Start charging sessions with full parameters
- STOP_SESSION: Stop sessions by Session ID
- Shows unsupported commands (UNLOCK_CONNECTOR, RESERVE_NOW)
- Query all sessions with pagination
- Get session details by ID
- Query all CDRs with pagination
- Get CDR details by ID
- Tabbed Interface: Switch between Logs and State view
- Colored Log Entries:
- π’ Success messages (green)
- π΅ Info messages (blue)
- π΄ Error messages (red)
- State Inspector: View complete simulator state including all data
- Auto-scroll to latest log entries
- Clear logs functionality
The UI exposes 23 API endpoints for dashboard functionality:
| Category | Endpoints |
|---|---|
| Configuration | GET/POST /ui/config |
| Credentials | POST /ui/actions/credentials/* |
| Discovery | POST /ui/actions/{versions,details,locations,tariffs} |
| Tokens | POST /ui/actions/tokens/{register,update,get} |
| Commands | POST /ui/actions/commands/{start_session,stop_session} |
| Sessions | POST /ui/actions/sessions/* |
| CDRs | POST /ui/actions/cdrs/* |
| State | GET /ui/state* |
OCPI-2.2.1-EMSP-Simulator/
βββ app/
β βββ routes/ # Server-side OCPI endpoint handlers
β β βββ versions.py # Version discovery endpoints
β β βββ credentials.py # Credentials and token management
β β βββ locations.py # Location and EVSE updates
β β βββ sessions.py # Session lifecycle management
β β βββ cdrs.py # CDR ingestion and retrieval
β β βββ tokens.py # Token registration and management
β β βββ commands.py # Command handling with callbacks
β β βββ ui.py # Web dashboard routes
β βββ client/ # Client-side logic to call CPO endpoints
β β βββ cpo_client.py # Comprehensive CPO client
β βββ validators/
β β βββ json_schemas/ # Official OCPI 2.2.1 JSON schemas
β βββ config.py # Configuration loader
β βββ log_utils.py # Structured logging utilities
β βββ state.py # In-memory state management
β βββ main.py # FastAPI application setup
βββ tests/ # Automated verification scripts
βββ ui/ # Comprehensive HTML/JS web dashboard with token management, commands, and state viewer
βββ config.example.yaml # Example configuration file
βββ run.py # Application entrypoint
βββ verify_cpo.py # Comprehensive CPO validation script
βββ requirements.txt # Python dependencies
We welcome contributions from the community! Whether it's a bug fix, new feature, or documentation improvement β all contributions are appreciated.
Please read our Contributing Guide before submitting a pull request.
Quick steps:
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Make your changes and write tests
- Commit:
git commit -m "feat: add your feature" - Push:
git push origin feature/your-feature-name - Open a Pull Request
If you discover a security vulnerability, please do not open a public GitHub issue. Instead, follow our Security Policy and report it privately.
This project is licensed under the BSD 3-Clause License. See the LICENSE file for details.
| Channel | Link |
|---|---|
| π§ Email | savekarev@gmail.com |
| π Bug Reports | Open an Issue |
| π¬ Discussions | GitHub Discussions |
| π¬ Discord | Join our community |
| π Website | savekar.com |
| π OCPI Testing | savekar.com/ocpi-simulator |