Citrine is an OCPP 2.0.1 Charging Station Management System (CSMS) designed to be adaptable to various infrastructures and easily extensible via modular design. It uses the fastify web framework.

Below is a diagram to introduce you to Citrine’s high-level architecture: Citrine's C4

N.B.: In the diagram above the websocket connections pass through the cloud before touching the central system. The definitions for the central system in 00_Base do not require direct websocket connectivity. Use of an infrastructure layer between the websockets and central system, such as AWS’s API Gateway, is thus supported. The implementation which lives in Server handles the websockets directly.

Codebase Strucutre

Citrine’s code structure includes 3 common packages: 00_Base, 01_Data, 02_Util and 03_Modules.


00_Base defines the interfaces and abstract classes needed for the Module implementations, you can view this as setting the underlying structure that the modules will implement. All OCPP messages and datatypes are here as well.


We make use of custom decorators that define methodes to be used for specific logic use cases.


01_Data implements all the logic for Citrine’s persistent data, stored in a relational database. This package is powered by sequelize-typescript. New modules which add persistent datatypes will need to extend this package.


02_Util contains implementations of various infrastructure components and tools.

This includes:


Citrine is set up that Modules have the actual implementations of OCPP Functional Blocks. They pull in the other packages like 00_base, 01_Data, 02_Util and are built on top.

The structure for each module should be roughly the same, set up as:


Is responsible for handling certificate management, especially relevant for ISO15118. Certificates are also used to maintain websocket and OTA firmware update security.


Handles the configuration of the Charging Station. Example messages are BootNotification and Reset.


Is responsible for handling driver related functionality, example messages are Authorize and RequestStartTransaction.


Is responsible for handling Monitoring related functionality. Example message are NotifyEvent and SetVariables.


The OCPP router handles the OCPP messages and routes them to and from the correct charger. Furthermore, you can register callbacks for websocket events or specific OCPP messages to be executed in the future. As an example, our directus extension, on boot, registers a callback for onConnect of a charger, to have real time insights on which chargers are currently online.


Is responsible for handling Reporting related functionality. Example message are SecurityEventNotification and GetBaseReport.


Is responsible for handling SmartCharging related functionality. Example message are ReportChargingProfiles and SetChargingProfile.


Is responsible for handling Transaction related functionality. Example message are TransactionEvent and CostUpdated.


The server directory is an example implementation using the citrine modules. It is not designed for production use, but rather for local development and test environments. Citrine is designed in a modular fashion scale each module independently. If you want to just use it for local development, check out our guide here: QuickStart


Directus is quite customizable and can load custom extensions. We make use of this to add some functionality to the UI such as real time charger connection insights.
Here we have Directus register callbacks with Citrine for when a charger connects or disconnects to publish updates.

Other Module Examples

Outside of the OCPP 2.0.1 protocol, modules could do things like provide OCPI interfaces, feed data to analysis tools, handle payments, or more.