Ocpp
Open Charge Point Protocol
Install / Use
/learn @ShellRechargeSolutionsEU/OcppREADME
Open Charge Point Protocol for Scala

The Open Charge Point Protocol (OCPP) is a network protocol for communication between electric vehicle chargers and a central backoffice system. It is developed by the Open Charge Alliance (OCA). You can find more details on the official website of the OCA.
Note to open source users
Open source users of this library will want to use the IHomer fork which is more actively supported and published to Maven Central.
Functionality
This library is the implementation of OCPP developed and used by NewMotion, one of Europe's largest Electric Vehicle Charge Point Operators.
This library only implements the network protocol. That is, it provides data types for the OCPP messages, remote procedure call using those request and response messages, and error reporting about those remote procedure calls. It does not provide any actual handling of the message contents. For an actual app speaking OCPP using this library, see docile-charge-point.
The library is designed with versatility in mind. OCPP comes in 4 versions (1.2, 1.5, 1.6 and 2.0), two transport variants (SOAP/XML aka OCPP-S and WebSocket/JSON aka OCPP-J), and two roles ("Charge Point" and "Central System"). This library will help you with 1.5 and 1.6 over JSON. For 1.2 and 1.5 over SOAP, there is a separate library by NewMotion that depends on this one. Some OCPP 2.0 support is present, but not a full implementation yet. The main body of this README will be writing about the OCPP 1.5 and 1.6 support; for OCPP 2.0 see here.
Version 2.0 with SOAP/XML is not possible. Version 1.2 with WebSocket/JSON and version 1.6 with SOAP/XML are not supported by this library.
Users of this library probably want to use different WebSocket libraries for different scenarios: a production back-office server with tens of thousands of concurrent connections, a client in a load testing tool, or a simple one-off script to test a certain behavior. This library uses the cake pattern to make it easy to swap out the underlying WebSocket implementation while still using the same concise high-level API.
How to use
Setup
The library is divided into three separate modules so applications using it won't get too many dependencies dragged in. Those are:
ocpp-j-api: high-level interface to OCPP-J connectionsocpp-json: serialization of OCPP messages to/from JSONocpp-messages: The definitions of OCPP messages, independent from the transport variant used
So if you want to use the high-level OCPP-J connection interface, and you're
using SBT, you can declare the dependency by adding this this to your build.sbt after publishing the library:
libraryDependencies += "com.thenewmotion.ocpp" %% "ocpp-j-api" % "9.2.2"
With Maven, add this to your dependencies:
<dependency>
<groupId>com.thenewmotion.ocpp</groupId>
<artifactId>ocpp-j-api_2.11</artifactId>
<version>9.2.2</version>
</dependency>
Using the simple client API
An example OCPP-J client application included. You can run it like this:
sbt "project example-json-client" "run 01234567 ws://localhost:8017/ocppws 1.5,1.6"
This means: connect to the Central System running at
ws://localhost:8017/ocppws, as a charge point with ID 01234567, using OCPP
version 1.5 and if that is not supported try 1.6 instead. If you don't specify
a version, 1.6 is used by default.
If you look at the code of the example by clicking here, you can see how the client API is used:
-
A connection is established by creating an instance of
OcppJsonClientusing theOcppJsonClient.forVersion1xfactory method. The server endpoint URI, charge point ID and OCPP version to use are passed to the method, followed by a handler for incoming OCPP requests in a second parameter list. -
To send OCPP messages to the Central System, you call the
sendmethod on theOcppJsonClientinstance. You will get aFutureback that will be completed with the Central System's response. If the Central System fails to respond to your request, theFuturewill fail. -
OcppJsonClientis an instance of theOutgoingOcppEndpointtrait. This trait defines this interface.
Handling requests
To specify the request handler, we use a magnet pattern.
You can specify the request handler in different ways. After the
val requestHandler: ChargePointRequestHandler =, you see a
ChargePoint
instance in the example program. But you can also specify the request handler
as a function from ChargePointReq to Future[ChargePointRes]:
val ocppJsonClient = OcppJsonClient.forVersion1x(chargerId, new URI(centralSystemUri), versions) {
(req: ChargePointReq) =>
req match {
case GetConfigurationReq(keys) =>
System.out.println(s"Received GetConfiguration for $keys")
Future.successful(GetConfigurationRes(
values = List(),
unknownKeys = keys
))
case x =>
val opName = x.getClass.getSimpleName
Future.failed(OcppException(
PayloadErrorCode.NotSupported,
s"Demo app doesn't support $opName"
))
}
}
This behavior of this request handler is more or less equivalent to that of the one in the example app. It is shorter at the price of being less type-safe: this code does not check if you generate the right response type for the request, so if you generate a GetConfigurationRes in response to a GetConfigurationReq for instance.
Sending requests
Sending requests is simple, as explained. You call the send method of your
endpoint and off you go, like this:
connection.send(HeartbeatReq)
The set of messages you can send with OCPP 1.x connections is defined in
ocpp-messages.
For every request type, you represent requests as instances of a case class
named <Operation Name>Req, e.g. StatusNotificationReq, HeartbeatReq.
For OCPP 1.x, these case classes in ocpp-messages are designed
according to two principles:
- They are independent of OCPP version, so you have one interface to charging stations that use different versions
- They sometimes group and rearrange fields to make it impossible to specify
nonsense messages (e.g., no
vendorErrorCodein status notifications that are not about errors). This makes it easier to write the code dealing with those requests, which does not have to validate things first.
This does mean that sometimes the way these case classes are defined may be a bit surprising to people familiar with the OCPP specification. It be so. Use the link to the file above, or use ⌘P in IntelliJ IDEA, to see how to give these case classes the right parameters to formulate the request you want to send.
This also means that it is possible to send requests that cannot be represented
in the OCPP version that is used for the connection you send them over. In that
case send will return a failed future with an OcppError with error code
NotSupported.
The result of the send method is a Future[RES], where RES is the type
of the response that belongs to the request you sent. So the type of this
expression:
connection.send(AuthorizeReq(idTag = "12345678"))
is Future[AuthorizeRes].
And if you want to do something with the result, the code could look like this:
connection.send(AuthorizeReq(idTag = "12345678")).map { res =>
if (res.idTag.status == AuthorizationStatus.Accepted)
System.out.println("12345678 is authorized.")
else
System.out.println("12345678 has been rejected. No power to you!")
}
Note that the library does not by itself
enforce the OCPP requirement that you wait for the response before sending the
next request. A simple way to obey it is chaining the send operations in a for
comprehension, as shown in the example app.
Error handling
If the remote side responds to your OCPP requests with a CALLERROR message
indicating a failure to process your request, the future returned from .send
will be failed. The exception in there will be an OcppException object, which
contains an OcppError object, which contains the error code and description
sent from the other side.
It works the same way in your own request handlers. You can return a failed
future with an OcppException, and the library will turn this into a
CALLERROR message and sends it back to the remote side.
Using the cake pattern directly
If you want to build an OCPP-J client using a different WebSocket implementation, or an OCPP-J server, you'll have to use the cake layers directly.
The OCPP cake has three layers:
OcppConnectionComponent: handles serialization and deserialization b
Related Skills
canvas
347.2kCanvas Skill Display HTML content on connected OpenClaw nodes (Mac app, iOS, Android). Overview The canvas tool lets you present web content on any connected node's canvas view. Great for: -
node-connect
347.2kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
108.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
347.2kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
