MaEVe is an EV charge station management system (CSMS). It began life as a simple proof of concept for implementing ISO-15118-2 Plug and Charge (PnC) functionality and remains a work in progress. It is hoped that over time it will become more complete, but already provides a useful basis for experimentation.
Originally developed by Thoughtworks, the project was archived on Jun 2, 2025 and has been revived and maintained by EVorada since then.
The system currently integrates with Hubject for PnC functionality and fully supports OCPP 1.6 and 2.0.1.
MaEVe fully supports OCPP 1.6j and OCPP 2.0.1. Charge stations negotiate the protocol version via the WebSocket Sec-WebSocket-Protocol header; the gateway defaults to OCPP 2.0.1 when no preference is indicated.
The table below lists every implemented action:
| Action | 1.6 Call | 1.6 CallResult | 2.0.1 Call | 2.0.1 CallResult |
|---|---|---|---|---|
| Authorize | ✅ | ✅ | ||
| BootNotification | ✅ | ✅ | ||
| CancelReservation | ✅ | |||
| CertificateSigned | ✅ | ✅ | ||
| ChangeAvailability | ✅ | ✅ | ||
| ChangeConfiguration | ✅ | |||
| ClearCache | ✅ | ✅ | ||
| ClearChargingProfile | ✅ | ✅ | ||
| ClearedChargingLimit | ✅ | |||
| CostUpdated | ✅ | |||
| DataTransfer (PnC) | ✅ | ✅ | ||
| DeleteCertificate | ✅ | ✅ | ||
| DiagnosticsStatusNotification | ✅ | |||
| ExtendedTriggerMessage | ✅ | |||
| FirmwareStatusNotification | ✅ | ✅ | ||
| Get15118EVCertificate | ✅ | ✅ | ||
| GetBaseReport | ✅ | |||
| GetCertificateStatus | ✅ | ✅ | ||
| GetChargingProfiles | ✅ | |||
| GetCompositeSchedule | ✅ | ✅ | ||
| GetConfiguration | ✅ | |||
| GetDiagnostics | ✅ | |||
| GetInstalledCertificateIds | ✅ | ✅ | ||
| GetLocalListVersion | ✅ | ✅ | ||
| GetLog | ✅ | |||
| GetReport | ✅ | |||
| GetTransactionStatus | ✅ | |||
| GetVariables | ✅ | |||
| Heartbeat | ✅ | ✅ | ||
| InstallCertificate | ✅ | ✅ | ||
| LogStatusNotification | ✅ | ✅ | ||
| MeterValues | ✅ | ✅ | ||
| NotifyChargingLimit | ✅ | |||
| NotifyEVChargingNeeds | ✅ | |||
| NotifyEVChargingSchedule | ✅ | |||
| NotifyReport | ✅ | |||
| RemoteStartTransaction | ✅ | |||
| RemoteStopTransaction | ✅ | |||
| ReportChargingProfiles | ✅ | |||
| RequestStartTransaction | ✅ | |||
| RequestStopTransaction | ✅ | |||
| ReserveNow | ✅ | |||
| Reset | ✅ | ✅ | ||
| SecurityEventNotification | ✅ | ✅ | ||
| SendLocalList | ✅ | ✅ | ||
| SetChargingProfile | ✅ | ✅ | ||
| SetNetworkProfile | ✅ | |||
| SetVariables | ✅ | |||
| SignCertificate | ✅ | ✅ | ||
| SignedFirmwareStatusNotification | ✅ | |||
| SignedUpdateFirmware | ✅ | |||
| StartTransaction | ✅ | |||
| StatusNotification | ✅ | ✅ | ||
| StopTransaction | ✅ | |||
| TransactionEvent | ✅ | |||
| TriggerMessage | ✅ | ✅ | ||
| UnlockConnector | ✅ | ✅ | ||
| UpdateFirmware | ✅ |
MaEVe supports three pluggable storage backends, selected via the type field in the [storage] section of the manager configuration.
| Feature | PostgreSQL | Firestore | In-Memory |
|---|---|---|---|
| Config type key | postgres |
firestore |
in_memory |
| Persistent storage | ✅ | ✅ | |
| Self-hosted | ✅ | ✅ | |
| Open source | ✅ | ✅ | |
| ACID transactions | ✅ | ||
| Multi-instance support | ✅ | ✅ | |
| Auto-migrations | ✅ | ||
| Recommended for production | ✅ | ✅ |
A self-hosted, open-source option backed by pgx/v5 with connection pooling and type-safe queries via sqlc. Schema migrations run automatically on startup or via the manager migrate command. A ready-to-use Docker Compose file is provided at docker-compose-postgres.yml.
[storage]
type = "postgres"
[storage.postgres]
host = "localhost"
port = 5432
database = "maeve_csms"
user = "maeve"
password = "your_secure_password"
ssl_mode = "disable" # use "require" or "verify-full" in production
run_migrations = trueSee manager/store/postgres/README.md for full setup instructions, migration commands, and performance tuning.
Google Cloud Firestore — a managed, serverless document database. Requires a GCP project ID. This is the default backend in the example configuration.
[storage]
type = "firestore"
[storage.firestore]
project_id = "your-gcp-project-id"A volatile, non-persistent store held entirely in process memory. All data is lost on restart. Does not support running more than one manager instance simultaneously. Intended for unit testing and local development only — no configuration parameters required.
[storage]
type = "in_memory"MaEVe is implemented in Go 1.20. Learn more about MaEVe and its existing components through this High-level design document.
MaEVe runs in a set of Docker containers. This means you need to have docker, docker-compose and a docker daemon (e.g. docker desktop, colima or rancher) installed and running.
Scripts that fetch various tokens use jq. Make sure you have it installed.
To get the system up and running:
(cd config/certificates && make)- Run the ./scripts/run.sh script
Charge stations can connect to the CSMS using:
ws://localhost/ws/<cs-id>wss://localhost/ws/<cs-id>
If the charge station is also running in a Docker container then the charge
station docker container can connect to the maeve-csms network and the
charge station can connect to the CSMS using:
ws://gateway:9310/ws/<cs-id>wss://gateway:9311/ws/<cs-id>
Charge stations can use either OCPP 1.6j or OCPP 2.0.1.
For TLS, the charge station should use a certificate provisioned using the Hubject CPO EST service.
A charge station must first be registered with the CSMS before it can be used. This can be done using the manager API. e.g. for TLS with client certificate, use:
$ curl http://localhost:9410/api/v0/cs/<cs-id> -H 'content-type: application/json' -d '{"securityProfile":2}'Tokens, which identify a payment method for a non-contract charge, must also be registered with the CSMS before they can be used. This can also be done using the manager API. e.g.:
$ curl http://localhost:9410/api/v0/token -H 'content-type: application/json' -d '{
"countryCode": "GB",
"partyId": "TWK",
"type": "RFID",
"uid": "DEADBEEF",
"contractId": "GBTWK012345678V",
"issuer": "Thoughtworks",
"valid": true,
"cacheMode": "ALWAYS"
}'Docker compose doesn't always rebuild the docker images which can cause all kinds of errors. If in doubt, force a rebuild by docker-compose build before launching containers.
java.io.IOException: keystore password was incorrect
This error results from incompatibility between java version and openssl; try upgrading your java version.
The gateway is configured through command-line flags. The available flags can be viewed using the -h flag.
The manager is configured through a TOML configuration file. An example configuration file can be found in ./config/manager/config.toml. Details of the available configuration options can be found in ./manager/config/README.md.
Learn more about how to contribute on this project through Contributing
MaEVe is Apache licensed.