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:
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.
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.
@AsHandler
:Defines a method as an OCPP call handler that listens for specific OCPP messages types from the message broker.@AsMessageEndpoint
: Defines a method as a Fastify-exposed API endpoint that takes in HTTP requests that are sent to a charging station.@AsDataEndpoint
: Defines a method as a Fastify-exposed API endpoint that exposes CRUD functionality for entities defined in the 01_Data package.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:
@AsMessageEndpoint
methods initialize flows into Directus.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:
api.ts
: Defines the API endpoints for the modulemodule.ts
: Hold the @AsHandler
decorated methods that handle OCPP messages. Here you will also find the supported call actions listed in an array at the top.service.ts
: Offers the deeper logic for the OCPP functional Blocks and is called by the methods in module.ts
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: Getting Started
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.
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.