diff --git a/README.md b/README.md index c176b3fc0..a1d55f96c 100644 --- a/README.md +++ b/README.md @@ -1,570 +1,36 @@ -# C++ implementation of OCPP -![Github Actions](https://github.com/EVerest/libocpp/actions/workflows/build_and_test.yaml/badge.svg) - -This is a C++ library implementation of OCPP for version 1.6 and 2.0.1 -(see [OCPP protocols at OCA website](https://openchargealliance.org/protocols/open-charge-point-protocol/)). - -It enables charging stations to communicate with cloud backends for remote -control, monitoring and billing of charging processes. - -Libocpp can be used for the communication of one charging station and multiple EVSE using a single websocket connection. - -Libocpp provides a complete implementation of OCPP 1.6. The implementation of OCPP 2.0.1 is currently under development. - -## Get Involved - -See the [COMMUNITY.md](https://github.com/EVerest/EVerest/blob/main/COMMUNITY.md) and [CONTRIBUTING.md](https://github.com/EVerest/EVerest/blob/main/CONTRIBUTING.md) of the EVerest project to get involved. - -## Table of contents -- [C++ implementation of OCPP](#c-implementation-of-ocpp) - - [Table of contents](#table-of-contents) - - [OCPP 1.6 Support](#feature-support) - - [Feature Profile Support OCPP 1.6](#feature-profile-support-ocpp-16) - - [Support for OCPP 2.0.1](#support-for-ocpp-201) - - [Feature Profile Support OCPP 2.0.1](#feature-profile-support-ocpp-201) - - [CSMS Compatibility](#csms-compatibility) - - [CSMS Compatibility OCPP 1.6](#csms-compatibility-ocpp-16) - - [CSMS Compatibility OCPP 2.0.1](#csms-compatibility-ocpp-201) - - [Integration with EVerest](#integration-with-everest) - - [Run OCPP1.6 with EVerest](#run-ocpp16-with-everest) - - [Run OCPP2.0.1 with EVerest](#run-ocpp201-with-everest) - - [Integrate this library with your Charging Station Implementation for OCPP1.6](#integrate-this-library-with-your-charging-station-implementation-for-ocpp16) - - [Overview of the required callbacks and events and what libocpp expects to happen](#overview-of-the-required-callbacks-and-events-and-what-libocpp-expects-to-happen) - - [ChargePoint() constructor](#chargepoint-constructor) - - [registering callbacks](#registering-callbacks) - - [Functions that need to be triggered from the outside after new information is availble (on\_... functions in the charge point API)](#functions-that-need-to-be-triggered-from-the-outside-after-new-information-is-availble-on_-functions-in-the-charge-point-api) - - [The following functions are triggered depending on different so called "Session Events" from the EvseManager](#the-following-functions-are-triggered-depending-on-different-so-called-session-events-from-the-evsemanager) - - [Authorization](#authorization) - - [Integrate this library with your Charging Station Implementation for OCPP2.0.1](#integrate-this-library-with-your-charging-station-implementation-for-ocpp201) - - [Register event callbacks and on\_handlers](#register-event-callbacks-and-on_handlers) - - [Initialize the database](#initialize-the-database) - - [Install libocpp](#install-libocpp) - - [Quickstart for OCPP 1.6](#quickstart-for-ocpp-16) - - [Building the doxygen documentation](#building-the-doxygen-documentation) - - [Unit testing](#unit-testing) - - [Building with FetchContent instead of EDM](#building-with-fetchcontent-instead-of-edm) - - [Support for security profile 2 and 3 with TPM in OCPP 1.6 using libwebsockets](#support-for-security-profile-2-and-3-with-tpm-in-ocpp-16-using-libwebsockets) - -## OCPP 1.6 Support - -The following tables show the current support for the listed OCPP 1.6 feature profiles / functional blocks and application notes. - -All documentation and the issue tracking can be found in our main repository here: https://github.com/EVerest/ - -### Feature Profile Support OCPP 1.6 - -| Feature Profile | Supported | -| -------------------------- | ------------------------- | -| Core | :heavy_check_mark: yes | -| Firmware Management | :heavy_check_mark: yes | -| Local Auth List Management | :heavy_check_mark: yes | -| Reservation | :heavy_check_mark: yes | -| Smart Charging | :heavy_check_mark: yes | -| Remote Trigger | :heavy_check_mark: yes | - -| Whitepapers & Application Notes | Supported | -| ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -| [OCPP 1.6 Security Whitepaper (3rd edition)](https://www.openchargealliance.org/uploads/files/OCPP-1.6-security-whitepaper-edition-3.zip) | :heavy_check_mark: yes | -| [Using ISO 15118 Plug & Charge with OCPP 1.6](https://www.openchargealliance.org/uploads/files/ocpp_1_6_ISO_15118_v10.pdf) | :heavy_check_mark: yes | -| [OCPP & California Pricing Requirements](https://www.openchargealliance.org/uploads/files/ocpp_and_dms_evse_regulation-v2.0.pdf) | :heavy_check_mark: yes | - -## Support for OCPP 2.0.1 - -The development of OCPP2.0.1 is in progress. -[Current implementation status.](/doc/ocpp_201_status.md) - -### Feature Profile Support OCPP 2.0.1 - -| Feature Profile | Supported | -| -------------------------- | ------------------------- | -| Core | :heavy_check_mark: yes | -| Advanced Security | WIP | -| Local Auth List Management | | -| Smart Charging | WIP | -| Advanced Device Management | | -| Advanced User Interface | | -| Reservation | | -| ISO 15118 support | WIP | - -| Whitepapers & Application Notes | Supported | -| ----------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- | -| [OCPP & California Pricing Requirements](https://www.openchargealliance.org/uploads/files/ocpp_and_dms_evse_regulation-v2.0.pdf) | WIP | - - - -## CSMS Compatibility - -### CSMS Compatibility OCPP 1.6 - -The EVerest implementation of OCPP 1.6 has been tested against the -OCPP Compliance Test Tool (OCTT and OCTT2) during the implementation. - -The following table shows CSMS with which this library was tested. -If you provide a CSMS that is not yet listed here, feel free to -[contact us](https://lists.lfenergy.org/g/everest)! - -- chargecloud -- chargeIQ -- Chargetic -- Compleo -- Current -- Daimler Truck -- ev.energy -- eDRV -- Fastned -- [Open Charging Cloud (GraphDefined)](https://github.com/OpenChargingCloud/WWCP_OCPP) -- Electrip Global -- EnergyStacks -- EV-Meter -- Fraunhofer IAO (ubstack CHARGE) -- Green Motion -- gridundco -- ihomer (Infuse CPMS) -- iLumen -- JibeCompany (CharlieV CMS and Chargebroker proxy) -- MSI -- PUMP (PUMP Connect) -- Scoptvision (Scopt Powerconnect) -- Siemens -- [SteVe](https://github.com/steve-community/steve) -- Syntech -- Trialog -- ubitricity -- Weev Energy - -### CSMS Compatibility OCPP 2.0.1 - -The current, ongoing implementation of OCPP 2.0.1 has been tested against a -few CSMS and is continuously tested against OCTT2. - -Additionally, the implementation has been tested against those CSMS: - -- [CitrineOS](https://lfenergy.org/projects/citrineos/) -- Chargepoint -- Current -- ihomer (Infuse CPMS) -- Instituto Tecnológico de la Energía (ITE) -- [MaEVe (Thoughtworks)](https://github.com/thoughtworks/maeve-csms) -- [Monta](https://monta.com) -- [Open Charging Cloud (GraphDefined)](https://github.com/OpenChargingCloud/WWCP_OCPP) -- Switch EV -- SWTCH - -## Integration with EVerest - -This library is automatically integrated as the OCPP and OCPP201 module within [everest-core](https://github.com/EVerest/everest-core) - the complete software stack for your charging station. It is recommended to use EVerest together with this OCPP implementation. - -### Run OCPP1.6 with EVerest -If you run libocpp with OCPP1.6 with EVerest, the build process of [everest-core](https://github.com/EVerest/everest-core) will take care of installing all necessary dependencies for you. - -### Run OCPP2.0.1 with EVerest -If you run libocpp with OCPP1.6 with EVerest, the build process of [everest-core](https://github.com/EVerest/everest-core) will take care of installing all necessary dependencies for you. This includes the initialization of the device model database using the [component config](config/v201/component_config) files. - -## Integrate this library with your Charging Station Implementation for OCPP1.6 - -OCPP is a protocol that affects, controls and monitors many areas of a charging station's operation. - -If you want to integrate this library with your charging station implementation, you have to register a couple of **callbacks** and integrate **event handlers**. This is necessary for the library to interact with your charging station according to the requirements of OCPP. - -Libocpp needs registered **callbacks** in order to execute control commands defined within OCPP (e.g Reset.req or RemoteStartTransaction.req) - -The implementation must call **event handlers** of libocpp so that the library can track the state of the charging station and trigger OCPP messages accordingly (e.g. MeterValues.req , StatusNotification.req) - -Your reference within libocpp to interact is a single instance to the class [ChargePoint](include/ocpp/v16/charge_point.hpp) for OCPP 1.6 or to the class [ChargePoint](include/ocpp/v201/charge_point.hpp) for OCPP 2.0.1. - -### Overview of the required callbacks and events and what libocpp expects to happen - -The following section will give you a high level overview of how to integrate libocpp with your application. Please use the [Doxygen Documentation](#building-the-doxygen-documentation) as an additional source for the ChargePoint API. - -In EVerest the OCPP module leverages several other modules to perform tasks that relate to authorization, reservations, charging session handling and system tasks like rebooting or firmware updates. -- Auth orchestrates authorization, utilizing different token providers like RFID reads and token validators. Libocpp mainly acts as a token validator, but in the case of RemoteStartTransactions it acts as a token provider as well -- EvseManager manages the charging session and charging state machine by communicating with a "board support package", a driver for the charging hardware that abstracts away the control pilot, relay control, power meters, etc. The EvseManager also handles reservations. -- System handles firmware updates, log uploads and resets - -The following sections explain the steps you can follow to implement their functionality on your own and integrate the libocpp directly into your charging station software without relying on EVerest. However, in most cases it's much easier to write an EVerest driver using the *everest-core/interfaces/board_support_AC.yaml* interface. - -#### ChargePoint() constructor -The main entrypoint for libocpp for OCPP1.6 is the ocpp::v16::ChargePoint constructor. -This is defined in libocpp/include/ocpp/v16/charge_point.hpp and takes the following parameters: -- config: a std::string that contains the libocpp 1.6 config. There are example configs that work with a [SteVe](https://github.com/steve-community/steve) installation [running in Docker](https://github.com/EVerest/everest-utils/tree/main/docker/steve), for example: [config-docker.json](config/v16/config-docker.json) - -- share_path: a std::filesystem path containing the path to the OCPP modules folder, for example pointing to */usr/share/everest/modules/OCPP*. This path contains the following files and directories and is installed by the libocpp install target: - ```bash - . - ├── config-docker.json - ├── config-docker-tls.json - ├── config.json - ├── init.sql - ├── logging.ini - └── profile_schemas - ├── Config.json - ├── Core.json - ├── FirmwareManagement.json - ├── Internal.json - ├── LocalAuthListManagement.json - ├── PnC.json - ├── Reservation.json - ├── Security.json - ├── SmartCharging.json - └── Custom.json - ``` - Here you can find: - - the aforementioned config files - - - a *logging.ini* that is needed to initialize logging with Everest::Logging::init(path_to_logging_ini, "name_of_binary") - - - a *init.sql* file which contains the database schema used by libocpp for its sqlite database - - - and a *profile_schemas* directory. This contains json schema files that are used to validate the libocpp config. The schemas are split up according to the OCPP1.6 feature profiles like Core, FirmwareManagement and so on. Additionally there is a schema for "Internal" configuration options (for example the ChargePointId, or CentralSystemURI). A "PnC" schema for the ISO 15118 Plug & Charge with OCPP 1.6 Application note, a "Security" schema for the OCPP 1.6 Security Whitepaper (3rd edition) and an exemplary "Custom" schema are provided as well. The Custom.json could be modified to be able to add custom configuration keys. Finally there's a Config.json schema that ties everything together - -- user_config_path: this points to a "user config", which we call a configuration file that's merged with the config that's provided in the "config" parameter. Here you can add, remove and overwrite settings without modifying the config passed in the first parameter directly. This is also used by libocpp to persistently modify config entries that are changed by the CSMS that should persist across restarts. - -- database_path: this points to the location of the sqlite database that libocpp uses to keep track of connector availability, the authorization cache and auth list, charging profiles and transaction data - -- sql_init_path: this points to the aforementioned init.sql file which contains the database schema used by libocpp for its sqlite database - -- message_log_path: this points to the directory in which libocpp can put OCPP communication logfiles for debugging purposes. This behavior can be controlled by the "LogMessages" (set to true by default) and "LogMessagesFormat" (set to ["log", "html", "session_logging"] by default, "console" and "console_detailed" are also available) configuration keys in the "Internal" section of the config file. Please note that this is intended for debugging purposes only as it logs all communication, including authentication messages. - -- evse_security: this is a pointer to an implementation of the [evse_security](include/ocpp/common/evse_security.hpp) interface. This allows you to include your custom implementation of the security related operations according to this interface. If you set this value to nullptr, the internal implementation of the security related operations of libocpp will be used. In this case you need to specify the parameter security_configuration - -- security_configuration: this parameter should only be set in case the evse_security parameter is nullptr. It specifies the file paths that are required to set up the internal evse_security implementation. Note that you need to specify bundle files for the CA certificates and directories for the certificates and keys - - The directory layout expected is as follows - ```bash - . - ├── ca - │ ├── csms - │ │ └── CSMS_ROOT_CA.pem - │ ├── cso - │ │ ├── CPO_CERT_CHAIN.pem - │ │ ├── CPO_SUB_CA1_LEAF.der - │ │ ├── CPO_SUB_CA1.pem - │ │ ├── CPO_SUB_CA2_LEAF.der - │ │ └── CPO_SUB_CA2.pem - │ ├── mf - │ │ └── MF_ROOT_CA.pem - │ ├── mo - │ │ ├── INTERMEDIATE_MO_CA_CERTS.pem - │ │ ├── MO_ROOT_CA.der - │ │ ├── MO_ROOT_CA.pem - │ │ ├── MO_SUB_CA1.der - │ │ ├── MO_SUB_CA1.pem - │ │ ├── MO_SUB_CA2.der - │ │ └── MO_SUB_CA2.pem - │ └── v2g - │ ├── V2G_ROOT_CA.der - │ └── V2G_ROOT_CA.pem - ├── client - │ ├── csms - │ │ ├── CPO_CERT_CHAIN.pem - │ │ ├── CPO_SUB_CA1.key - │ │ ├── CPO_SUB_CA2.key - │ │ ├── SECC_LEAF.der - │ │ ├── SECC_LEAF.key - │ │ └── SECC_LEAF.pem - │ ├── cso - │ │ ├── CPO_CERT_CHAIN.pem - │ │ ├── CPO_SUB_CA1.key - │ │ ├── CPO_SUB_CA2.key - │ │ ├── SECC_LEAF.der - │ │ ├── SECC_LEAF.key - │ │ └── SECC_LEAF.pem - │ └── v2g - │ └── V2G_ROOT_CA.key - ``` - -#### registering callbacks -You can (and in many cases MUST) register a number of callbacks so libocpp can interact with the charger. In EVerest most of this functionality is orchestrated by the "EvseManager" module, but you can also register your own callbacks interacting directly with your chargers software. Following is a list of callbacks that you must register and a few words about their purpose. - -TODO: in a future version of libocpp the callbacks will be organised in a struct with optional members emphasizing the required and optional callbacks. - -Some general notes: the "connector" parameter of some of the callbacks refers to the connector number as understood in the OCPP 1.6 specification, "0" means the whole charging station, the connectors with EVSEs used for charging cars start at "1". - -- register_pause_charging_callback - - this callback is used by libocpp to request pausing of charging, the "connector" parameter tells you which connector/EVSE has to pause charging - -- register_resume_charging_callback - - this callback is used by libocpp the request resuming of charging, the "connector" parameter tells you which connector/EVSE can resume charging - -- register_stop_transaction_callback - - in EVerest this calls the EvseManagers stop_transaction command which "Stops transactions and cancels charging externally, charging can only be resumed by replugging car. EVSE will also stop transaction automatically e.g. on disconnect, so this only needs to be called if the transaction should end before." - this will then signal the following events: - - ChargingFinished - - TransactionFinished - -- register_unlock_connector_callback - - can be used by libocpp to force unlock a connector - -- register_reserve_now_callback - - libocpp can use this to reserve a connector, reservation handling is outsourced to a reservation manager in EVerest that implements the reservation interface (everest-core/interfaces/reservation.yaml) - -- register_upload_diagnostics_callback - - uses a function (in EVerest provided by the System module) to upload the requested diagnostics file - -- register_upload_logs_callback - - uses a function (in EVerest provided by the System module) to upload the requested log file - -- register_update_firmware_callback - - uses a function (in EVerest provided by the System module) to perform a firmware update - -- register_signed_update_firmware_callback - - uses a function (in EVerest provided by the System module) to perform a signed firmware update - -- register_provide_token_callback - - this callback is used in a remote start transaction to provide a token (prevalidated or not) to the authorization system - -- register_set_connection_timeout_callback - - used by libocpp to set the authorization or plug in connection timeout in the authorization system based on the "ConnectionTimeout" configuration key - -- register_disable_evse_callback - used to disable the EVSE (ChangeAvailability.req) - -- register_enable_evse_callback - - used to enable the EVSE (ChangeAvailability.req) - -- register_cancel_reservation_callback - - used to cancel a reservation in the reservation manager (CancelReservation.req) - -- register_signal_set_charging_profiles_callback - - used to signal that new charging schedule(s) have been set, you can then use - get_all_composite_charging_schedules(duration_s) to get the new valid charging schedules - -- register_is_reset_allowed_callback - - used to inquire (in EVerest from the System module) if a reset is allowed - -- register_reset_callback - - used to perform a reset of the requested type - -- register_connection_state_changed_callback - - used to inform about the connection state to the CSMS (connected = true, disconnected = false) - -- register_configuration_key_changed_callback - used to react on a changed configuration key. This callback is called when the specified configuration key has been changed by the CSMS - - -#### Functions that need to be triggered from the outside after new information is availble (on_... functions in the charge point API) -- on_log_status_notification(int32_t request_id, std::string log_status) - - can be used to notify libocpp of a log status notification - -- on_firmware_update_status_notification(int32_t request_id, std::string firmware_update_status) - - can be used to notify libocpp of a firmware update status notification - -- on_meter_values(int32_t connector, const Powermeter& powermeter) - - provides a Powermeter struct to libocpp (for sending meter values during charging sessions or periodically) - -- on_max_current_offered(int32_t connector, int32_t max_current) - - the maximum current offered to the EV on this connector (in ampere) - -#### The following functions are triggered depending on different so called "Session Events" from the EvseManager -each of these functions will have a small note what the Session Event was and what it triggers in libocpp - -- on_enabled(int32_t connector) - - Notifies libocpp that the connector is functional and operational - -- on_disabled(int32_t connector) - - Notifies libocpp that the connector is disabled - -- on_transaction_started - - Notifies libocpp that a transaction at the given connector has started, this means that authorization is available and the car is plugged in. - - Some of its parameters: - - session_id is an internal session_id originating in the EvseManager to keep track of the transaction, this is NOT to be mistaken for the transactionId from the StartTransactionResponse in OCPP! - - id_token is the token with which the transaction was authenticated - - meter_start contains the meter value in Wh for the connector at start of the transaction - - timestamp at the start of the transaction - -- on_transaction_stopped - - Notifies libocpp that the transaction on the given connector with the given reason has been stopped. - - Some of its parameters: - - timestamp at the end of the transaction - - energy_wh_import contains the meter value in Wh for the connector at end of the transaction - -- on_suspend_charging_ev - - Notifies libocpp that the EV has paused charging - -- on_suspend_charging_evse - - Notifies libocpp that the EVSE has paused charging - -- on_resume_charging - - Notifies libocpp that charging has resumed - -- on_session_started - - this is mostly used for logging and changing the connector state - -- on_session_stopped - - this is mostly used for logging and changing the connector state - -- on_error - - Notify libocpp of an error - -- on_reservation_start - - Notifies libocpp that a reservation has started - -- on_reservation_end - - Notifies libocpp that a reservation has ended - -#### Authorization -In EVerest authorization is handled by the Auth module and various auth token providers and validators. The OCPP module acts as both a token provider (for pre validated tokens in RemoteStartTransactions) and a token validator (using the authorize requests, or plug & charge) -To use libocpp as a auth token validator (e.g. before starting a transaction) you can call the "authorize_id_token" function of the ChargePoint object - -## Integrate this library with your Charging Station Implementation for OCPP2.0.1 -TODO - -### Register event callbacks and on_handlers - -### Initialize the database -- Use provided sql database or implement your own storage drive - - - -## Install libocpp - -For Debian GNU/Linux 11 you will need the following dependencies: - -```bash - sudo apt install build-essential cmake python3-pip libboost-all-dev libsqlite3-dev libssl-dev -``` - -OpenSSL version 3.0 or above is required. - -Clone this repository. - -```bash - git clone https://github.com/EVerest/libocpp -``` - -In the libocpp folder create a folder named build and cd into it. -Execute cmake and then make install: - -```bash - mkdir build && cd build - cmake .. - make install -``` - -## Quickstart for OCPP 1.6 - -Libocpp provides a small standalone OCPP1.6 client that you can control using command line. - -Install the dependencies and libocpp as described in [Install libocpp](#install-libocpp). - -Make sure you modify the following config entries in the [config.json](config/v16/config.json) file according to the CSMS you want to connect to before executing make install. - -```json -{ - "Internal": { - "ChargePointId": "", - "CentralSystemURI": "" - } -} -``` - -Change into libocpp/build and execute cmake and then make install: - -```bash - cd build - cmake -DLIBOCPP16_BUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=./dist .. - make -j$(nproc) install -``` - -Use the following command to start the charge point. Replace the config with [config-docker.json](config/v16/config-docker.json) if you want to test with the [SteVe](https://github.com/steve-community/steve#docker) CSMS running in a docker container. - -```bash - ./dist/bin/charge_point \ - --maindir ./dist \ - --conf config.json -``` - -Type `help` to see a list of possible commands. - -## Building the doxygen documentation -```bash - cmake -S . -B build - cmake --build build --target doxygen-ocpp -``` -You will find the generated doxygen documentation at: -`build/dist/docs/html/index.html` - -The main reference for the integration of libocpp for OCPP1.6 is the ocpp::v16::ChargePoint class defined in libocpp/include/ocpp/v16/charge_point.hpp . +![Header](doc/img/banner-ocpp.jpg) +![Github Actions](https://github.com/EVerest/libocpp/actions/workflows/build_and_test.yaml/badge.svg) -## Unit testing +--- -GTest is required for building the test cases target. -To build the target and run the tests you can reference the script `.ci/build-kit/install_and_test.sh`. -The script allows the GitHub Actions runner to execute. +# EVerest OCPP Module (`libocpp`) -Local testing: -```bash -mkdir build -cmake -B build -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="./dist" -cd build -make -j$(nproc) install -``` -Run any required tests from build/tests. +EVerest's Open Charge Point Protocol (OCPP) modules are based on this library—`libocpp`—a standalone C++ library implementing client-side OCPP 1.6 and 2.0.1 communications. This library can be used independently of EVerest to enable OCPP communication for a charging station. + -## Building with FetchContent instead of EDM -In [doc/build-with-fetchcontent](doc/build-with-fetchcontent) you can find an example how to build libocpp with FetchContent instead of EDM. +### What is OCPP? -### Support for TPM keys +[OCPP](https://en.wikipedia.org/wiki/Open_Charge_Point_Protocol) is an open standard for communication between EV charging stations and central management systems. Developed by the [Open Charge Alliance (OCA)](https://openchargealliance.org/), OCPP ensures interoperability among various charging station manufacturers and management systems, playing a vital role in the EV charging ecosystem. -In order to use the TPM keys, it is mandatory to use the default libwebsocket implementation. -## Support for websocket++ +## Table of Contents -The old websocket++ implementation has been deprecated. For enabling websocket++ support use the following cmake option: +| [OCPP 2.0.1](/doc/ocpp_201_README.md) – Under active development :construction: | [OCPP 1.6](/doc/ocpp_16_README.md) – Complete implementation :white_check_mark: | +|------------|----------| +| • [Quickstart Guide](/doc/ocpp_201_README.md#quickstart-for-ocpp-201) | • [Quickstart Guide](/doc/ocpp_16_README.md#quickstart-for-ocpp-16) | +| • [Build and Install libocpp](/doc/ocpp_201_README.md#build-and-install-libocpp) | • [Build and Install libocpp](/doc/ocpp_16_README.md#build-and-install-libocpp) | +| • [Supported Certification Profiles](/doc/ocpp_201_README.md#supported-certification-profiles) | • [Functionality Support](/doc/ocpp_16_README.md#functionality-support) | +| • [Integration with EVerest](/doc/ocpp_201_README.md#integration-with-everest) | • [Integration with EVerest](/doc/ocpp_16_README.md#integration-with-everest) | +| • [Standalone Integration](/doc/ocpp_201_README.md#standalone-integration) | • [Standalone Integration](/doc/ocpp_16_README.md#standalone-integration) | +| • [Unit testing](doc/ocpp_201_README.md#unit-testing) | • [Unit testing](doc/ocpp_16_README.md#unit-testing) | +| • [CSMS Compatibility](/doc/ocpp_201_README.md#csms-compatibility) | • [CSMS Compatibility](/doc/ocpp_16_README.md#csms-compatibility) | -```bash - cmake .. -DLIBOCPP_ENABLE_DEPRECATED_WEBSOCKETPP=ON -``` +## Get Involved -### Support for iface +We welcome contributions from the community! Whether you're interested in adding features, fixing bugs, or improving documentation, your help is valuable. Check out our [CONTRIBUTING.md](https://github.com/EVerest/EVerest/blob/main/CONTRIBUTING.md) guide to get started. -In order to connect through a custom network iface, a custom internal config variable 'IFace' can be used. +For more information on how to engage with the EVerest community, please refer to our [COMMUNITY.md](https://github.com/EVerest/EVerest/blob/main/COMMUNITY.md) document. -```json -"Internal": { - "IFace" : "enp43s0" -} -``` +Together, we can drive the future of EV charging infrastructure! diff --git a/doc/img/banner-ocpp.jpg b/doc/img/banner-ocpp.jpg new file mode 100644 index 000000000..63c75beea Binary files /dev/null and b/doc/img/banner-ocpp.jpg differ diff --git a/doc/ocpp_16_README.md b/doc/ocpp_16_README.md new file mode 100644 index 000000000..c9632b19b --- /dev/null +++ b/doc/ocpp_16_README.md @@ -0,0 +1,406 @@ +![Github Actions](https://github.com/EVerest/libocpp/actions/workflows/build_and_test.yaml/badge.svg) + +----- + +# OCPP 1.6 in `libocpp` + +This C++ library provides a complete and production-ready solution for integrating OCPP 1.6 into your electric vehicle (EV) charging stations. Our implementation enables seamless communication between charging stations and central management systems, supporting remote control, monitoring, and billing functionalities. + +## Table of contents + +- [Functionality Support](#functionality-support) +- [CSMS Compatibility](#csms-compatibility) +- [Integration with EVerest](#integration-with-everest) +- [Standalone Integration](#standalone-integration) + - [Overview of Expected Callbacks and Event Handlers](#overview-of-expected-callbacks-and-event-handlers) + - [Usage for OCPP 1.6](#usage-for-ocpp-16) + - [`ChargePoint` Constructor](#chargepoint-constructor) + - [Registering Callbacks](#registering-callbacks) + - [Authorization](#authorization) + - [Initialize the Database](#initialize-the-database) +- [Quickstart for OCPP 1.6](#quickstart-for-ocpp-16) +- [Build and Install `libocpp`](#build-and-install-libocpp) +- [Building with FetchContent Instead of EDM](#building-with-fetchcontent-instead-of-edm) +- [Unit Testing](#unit-testing) +- [Building the Doxygen Documentation](#building-the-doxygen-documentation) +- [Support for TPM Keys](#support-for-tpm-keys) +- [Support for `websocket++`](#support-for-websocket) +- [Support for `iface`](#support-for-iface) + +## Functionality Support + +The EVerest OCPP 1.6 implementation (`libocpp`) provides comprehensive support for OCPP 1.6 functionalities. Below is an overview of the supported features: + +| OCPP 1.6 Functionality | Supported | +| ---------------------------- | ---------------------------- | +| Core | :heavy_check_mark: Yes | +| Firmware Management | :heavy_check_mark: Yes | +| Local Auth List Management | :heavy_check_mark: Yes | +| Reservation | :heavy_check_mark: Yes | +| Smart Charging | :heavy_check_mark: Yes | +| Remote Trigger | :heavy_check_mark: Yes | + +| Whitepapers & Application Notes | Supported | +| ------------------------------------------- | ---------------------- | +| OCPP 1.6 Security Whitepaper (3rd edition) | :heavy_check_mark: Yes | +| Using ISO 15118 Plug & Charge with OCPP 1.6 | :heavy_check_mark: Yes | +| OCPP & California Pricing Requirements | :heavy_check_mark: Yes | + +## CSMS Compatibility + +The EVerest implementation of OCPP 1.6 has been tested against the +OCPP Compliance Test Tool (OCTT and OCTT2) during the implementation. + +The following table shows CSMSs with which this library was tested. +If you provide a CSMS that is not yet listed here, feel free to +[contact us](https://lists.lfenergy.org/g/everest)! + +| CSMS | | +| :------------------------------ | :-------- | +| chargecloud | gridundco | +| chargeIQ | ihomer (Infuse CPMS) | +| Chargetic | iLumen | +| Compleo | JibeCompany (CharlieV CMS and Chargebroker proxy) | +| Current | MSI | +| Daimler Truck | [Open Charging Cloud (GraphDefined)](https://github.com/OpenChargingCloud/WWCP_OCPP) | +| eDRV | PUMP (PUMP Connect) | +| Electrip Global | Scoptvision (Scopt Powerconnect) | +| EnergyStacks | Siemens | +| EV-Meter | [SteVe](https://github.com/steve-community/steve) | +| ev.energy | Syntech | +| Fastned | Trialog | +| Fraunhofer IAO (ubstack CHARGE) | ubitricity | +| Green Motion | Weev Energy | + +## Integration with EVerest + +The libocpp OCPP 1.6 module is automatically integrated within [everest-core](https://github.com/EVerest/everest-core) — the complete software stack for your charging station. + +When you run libocpp with OCPP 1.6 through EVerest, the build process of everest-core handles the installation of all necessary dependencies. This includes initializing the device model database using the [config.json](/config/v16/config.json) file. + +## Standalone Integration + +OCPP is a protocol that affects, controls, and monitors many areas of a charging station's operation. The `libocpp` library is just the messenger for this protocol. It is intended to provide mechanisms for connecting to and authenticating with a CSMS, sending and receiving the OCPP messages that govern behaviors in the standard, and to the track state required for a charging station to conform to the protocol all while minimizing hardware- or implementation-specific functionality. + +The actual substance of how a charging station reacts to or initiates an OCPP command (such as `Reset.req` or `RemoteStartTransaction.req`) is left to the rest of the charging station's systems. This is done by providing means of (a) registering **callbacks** that can be triggered by a `libocpp` `ChargePoint` in response to certain events and (b) reacting to various **event handlers** defined on a `ChargePoint` in other areas of the charging station's codebase. + +> [!IMPORTANT] +> Integrating this library with your charging station requires both (a) defining **callbacks** that enable control of your station by `libocpp` and (b) calling `libocpp` **event handlers** in your charging station's systems in response to new events and data in order to keep `libocpp` up to date on station information. + +### Terminology +Throughout this document and the `libocpp` codebase, the following conventions are followed: + +- A **callback** is a function providing the actual station-specific implementation of an OCPP command. It allows a `libocpp` `ChargePoint` to control other systems within a charging station. By convention, each callback on a `ChargePoint` has a name suffixed with `_callback` (for instance, `unlock_connector_callback`). A suitable `std::function` can be **registered** as a callback on a `ChargePoint` by providing it as an argument for the relevant `register_` function (such as `register_unlock_connector_callback`). + +- An **event handler** is a public function defined on a `ChargePoint` that allows a charging station to update the state being tracked by the `ChargePoint` based on new information (meter values, charging session events, etc.) and (indirectly) send messages to a CSMS. By convention, the names of event handlers on the `ChargePoint` are each prefixed with `on_` (for instance, `on_meter_values`). + +The complete set of callbacks and event handlers defined on an OCPP 1.6 `ChargePoint` can be viewed in the latter's [header file](/include/ocpp/v16/charge_point.hpp). + +### Overview of Expected Callbacks and Event Handlers + +The following section will give you a high-level overview of how to integrate `libocpp` with your application. Please use the [Doxygen documentation](#building-the-doxygen-documentation) as an additional source of information about the `ChargePoint` API. + +In EVerest the OCPP module leverages several other modules to perform tasks that relate to authorization, reservations, charging session handling and system tasks like rebooting or firmware updates. + +- Auth orchestrates authorization, utilizing different token providers like RFID reads and token validators. Libocpp mainly acts as a token validator, but in the case of RemoteStartTransactions it acts as a token provider as well +- EvseManager manages the charging session and charging state machine by communicating with a "board support package", a driver for the charging hardware that abstracts away the control pilot, relay control, power meters, etc. The EvseManager also handles reservations. +- System handles firmware updates, log uploads and resets + +The following sections explain the steps you can follow to implement their functionality on your own and integrate the libocpp directly into your charging station software without relying on EVerest. However, in most cases it's much easier to write an EVerest driver using the *everest-core/interfaces/board_support_AC.yaml* interface. + +### Usage for OCPP 1.6 + +#### `ChargePoint` Constructor + +The main entrypoint for `libocpp` for OCPP 1.6 is the `ocpp::v16::ChargePoint` constructor. +This is defined in libocpp/include/ocpp/v16/charge_point.hpp and takes the following parameters: + +- config: a std::string that contains the libocpp 1.6 config. There are example configs that work with a [SteVe](https://github.com/steve-community/steve) installation [running in Docker](https://github.com/EVerest/everest-utils/tree/main/docker/steve), for example: [config-docker.json](/config/v16/config-docker.json) + +- share_path: a std::filesystem path containing the path to the OCPP modules folder, for example pointing to */usr/share/everest/modules/OCPP*. This path contains the following files and directories and is installed by the libocpp install target: + + ```bash + . + ├── config-docker.json + ├── config-docker-tls.json + ├── config.json + ├── init.sql + ├── logging.ini + └── profile_schemas + ├── Config.json + ├── Core.json + ├── FirmwareManagement.json + ├── Internal.json + ├── LocalAuthListManagement.json + ├── PnC.json + ├── Reservation.json + ├── Security.json + ├── SmartCharging.json + └── Custom.json + ``` + + Here you can find: + - the aforementioned config files + + - a *logging.ini* that is needed to initialize logging with Everest::Logging::init(path_to_logging_ini, "name_of_binary") + + - a *init.sql* file which contains the database schema used by libocpp for its sqlite database + + - and a *profile_schemas* directory. This contains json schema files that are used to validate the libocpp config. The schemas are split up according to the OCPP1.6 feature profiles like Core, FirmwareManagement and so on. Additionally there is a schema for "Internal" configuration options (for example the ChargePointId, or CentralSystemURI). A "PnC" schema for the ISO 15118 Plug & Charge with OCPP 1.6 Application note, a "Security" schema for the OCPP 1.6 Security Whitepaper (3rd edition) and an exemplary "Custom" schema are provided as well. The Custom.json could be modified to be able to add custom configuration keys. Finally there's a Config.json schema that ties everything together + +- user_config_path: this points to a "user config", which we call a configuration file that's merged with the config that's provided in the "config" parameter. Here you can add, remove and overwrite settings without modifying the config passed in the first parameter directly. This is also used by libocpp to persistently modify config entries that are changed by the CSMS that should persist across restarts. + +- database_path: this points to the location of the sqlite database that libocpp uses to keep track of connector availability, the authorization cache and auth list, charging profiles and transaction data + +- sql_init_path: this points to the aforementioned init.sql file which contains the database schema used by libocpp for its sqlite database + +- message_log_path: this points to the directory in which libocpp can put OCPP communication logfiles for debugging purposes. This behavior can be controlled by the "LogMessages" (set to true by default) and "LogMessagesFormat" (set to ["log", "html", "session_logging"] by default, "console" and "console_detailed" are also available) configuration keys in the "Internal" section of the config file. Please note that this is intended for debugging purposes only as it logs all communication, including authentication messages. + +- evse_security: this is a pointer to an implementation of the [evse_security](/include/ocpp/common/evse_security.hpp) interface. This allows you to include your custom implementation of the security related operations according to this interface. If you set this value to nullptr, the internal implementation of the security related operations of libocpp will be used. In this case you need to specify the parameter security_configuration + +- security_configuration: this parameter should only be set in case the evse_security parameter is nullptr. It specifies the file paths that are required to set up the internal evse_security implementation. Note that you need to specify bundle files for the CA certificates and directories for the certificates and keys + + The directory layout expected is as follows + + ```bash + . + ├── ca + │ ├── csms + │ │ └── CSMS_ROOT_CA.pem + │ ├── cso + │ │ ├── CPO_CERT_CHAIN.pem + │ │ ├── CPO_SUB_CA1_LEAF.der + │ │ ├── CPO_SUB_CA1.pem + │ │ ├── CPO_SUB_CA2_LEAF.der + │ │ └── CPO_SUB_CA2.pem + │ ├── mf + │ │ └── MF_ROOT_CA.pem + │ ├── mo + │ │ ├── INTERMEDIATE_MO_CA_CERTS.pem + │ │ ├── MO_ROOT_CA.der + │ │ ├── MO_ROOT_CA.pem + │ │ ├── MO_SUB_CA1.der + │ │ ├── MO_SUB_CA1.pem + │ │ ├── MO_SUB_CA2.der + │ │ └── MO_SUB_CA2.pem + │ └── v2g + │ ├── V2G_ROOT_CA.der + │ └── V2G_ROOT_CA.pem + ├── client + │ ├── csms + │ │ ├── CPO_CERT_CHAIN.pem + │ │ ├── CPO_SUB_CA1.key + │ │ ├── CPO_SUB_CA2.key + │ │ ├── SECC_LEAF.der + │ │ ├── SECC_LEAF.key + │ │ └── SECC_LEAF.pem + │ ├── cso + │ │ ├── CPO_CERT_CHAIN.pem + │ │ ├── CPO_SUB_CA1.key + │ │ ├── CPO_SUB_CA2.key + │ │ ├── SECC_LEAF.der + │ │ ├── SECC_LEAF.key + │ │ └── SECC_LEAF.pem + │ └── v2g + │ └── V2G_ROOT_CA.key + ``` + +#### Registering Callbacks + +You can (and in many cases MUST) register a number of callbacks so libocpp can interact with the charger. In EVerest most of this functionality is orchestrated by the "EvseManager" module, but you can also register your own callbacks interacting directly with your chargers software. Following is a list of callbacks that you must register and a few words about their purpose. + +TODO: in a future version of libocpp the callbacks will be organised in a struct with optional members emphasizing the required and optional callbacks. + +Some general notes: the "connector" parameter of some of the callbacks refers to the connector number as understood in the OCPP 1.6 specification, "0" means the whole charging station, the connectors with EVSEs used for charging cars start at "1". + +| Callbacks | Description | +| :----------------------------------------------- | :-------------------------------------- | +| `register_pause_charging_callback` | this callback is used by libocpp to request pausing of charging, the "connector" parameter tells you which connector/EVSE has to pause charging | +| `register_resume_charging_callback` | this callback is used by libocpp the request resuming of charging, the "connector" parameter tells you which connector/EVSE can resume charging | +| `register_stop_transaction_callback` | in EVerest this calls the EvseManagers stop_transaction command which "Stops transactions and cancels charging externally, charging can only be resumed by replugging car. EVSE will also stop transaction automatically e.g. on disconnect, so this only needs to be called if the transaction should end before." this will then signal the following events:
• ChargingFinished
• TransactionFinished | +| `register_unlock_connector_callback` | can be used by libocpp to force unlock a connector | +| `register_reserve_now_callback` | libocpp can use this to reserve a connector, reservation handling is outsourced to a reservation manager in EVerest that implements the reservation interface (everest-core/interfaces/reservation.yaml) | +| `register_upload_diagnostics_callback` | uses a function (in EVerest provided by the System module) to upload the requested diagnostics file | +| `register_upload_logs_callback` | uses a function (in EVerest provided by the System module) to upload the requested log file | +| `register_update_firmware_callback` | uses a function (in EVerest provided by the System module) to perform a firmware update | +| `register_signed_update_firmware_callback` | uses a function (in EVerest provided by the System module) to perform a signed firmware update | +| `register_provide_token_callback` | this callback is used in a remote start transaction to provide a token (prevalidated or not) to the authorization system | +| `register_set_connection_timeout_callback` | used by libocpp to set the authorization or plug in connection timeout in the authorization system based on the "ConnectionTimeout" configuration key | +| `register_disable_evse_callback` | used to disable the EVSE (ChangeAvailability.req) | +| `register_enable_evse_callback` | used to enable the EVSE (ChangeAvailability.req) | +| `register_cancel_reservation_callback` | used to cancel a reservation in the reservation manager (CancelReservation.req) | +| `register_signal_set_charging_profiles_callback` | used to signal that new charging schedule(s) have been set, you can then use get_all_composite_charging_schedules(duration_s) to get the new valid charging schedules | +| `register_is_reset_allowed_callback` | used to inquire (in EVerest from the System module) if a reset is allowed | +| `register_reset_callback` | used to perform a reset of the requested type | +| `register_connection_state_changed_callback` | used to inform about the connection state to the CSMS (connected = true, disconnected = false) | +| `register_configuration_key_changed_callback` | used to react on a changed configuration key. This callback is called when the specified configuration key has been changed by the CSMS | + +#### Functions that need to be triggered from the outside after new information is availble (on_... functions in the charge point API) + +| on_ functions | Description | +| :-------- | :---------- | +| `on_log_status_notification(int32_t request_id, std::string log_status)` | can be used to notify libocpp of a log status notification | +| `on_firmware_update_status_notification(int32_t request_id, std::string firmware_update_status)` | can be used to notify libocpp of a firmware update status notification | +| `on_meter_values(int32_t connector, const Powermeter& powermeter)` | provides a Powermeter struct to libocpp (for sending meter values during charging sessions or periodically) | +| `on_max_current_offered(int32_t connector, int32_t max_current)` | the maximum current offered to the EV on this connector (in ampere) | + +#### The following functions are triggered depending on different so called "Session Events" from the EvseManager + +each of these functions will have a small note what the Session Event was and what it triggers in libocpp + +| on_ functions | Description | +| :------------------------------- | :----------------------------------------- | +| `on_enabled(int32_t connector)` | Notifies libocpp that the connector is functional and operational | +| `on_disabled(int32_t connector)` | Notifies libocpp that the connector is disabled | +| `on_transaction_started` | Notifies libocpp that a transaction at the given connector has started, this means that authorization is available and the car is plugged in.
Some of its parameters:
• session_id is an internal session_id originating in the EvseManager to keep track of the transaction, this is NOT to be mistaken for the transactionId from the StartTransactionResponse in OCPP!
• id_token is the token with which the transaction was authenticated
• meter_start contains the meter value in Wh for the connector at start of the transaction
• timestamp at the start of the transaction
| +| `on_transaction_stopped` | Notifies libocpp that the transaction on the given connector with the given reason has been stopped.
Some of its parameters:
• timestamp at the end of the transaction
• energy_wh_import contains the meter value in Wh for the connector at end of the transaction
| +| `on_suspend_charging_ev` | Notifies libocpp that the EV has paused charging | +| `on_suspend_charging_evse` | Notifies libocpp that the EVSE has paused charging | +| `on_resume_charging` | Notifies libocpp that charging has resumed | +| `on_session_started` | this is mostly used for logging and changing the connector state | +| `on_session_stopped` | this is mostly used for logging and changing the connector state | +| `on_error` | Notify libocpp of an error | +| `on_reservation_start` | Notifies libocpp that a reservation has started | +| `on_reservation_end` | Notifies libocpp that a reservation has ended | + +#### Authorization + +In EVerest authorization is handled by the Auth module and various auth token providers and validators. The OCPP module acts as both a token provider (for pre validated tokens in RemoteStartTransactions) and a token validator (using the authorize requests, or plug & charge). + +To use libocpp as a auth token validator (e.g. before starting a transaction) you can call the "authorize_id_token" function of the ChargePoint object. + + +### Initialize the Database + +Use provided sql database or implement your own storage drive. + +----- + +## Quickstart for OCPP 1.6 + +Libocpp provides a small standalone OCPP 1.6 client that you can control using command line. + +Install the dependencies and libocpp as described in [Build and Install libocpp](#build-and-install-libocpp). + +Make sure you modify the following config entries in the [config.json](/config/v16/config.json) file according to the CSMS you want to connect to before executing make install. + +```json +{ + "Internal": { + "ChargePointId": "", + "CentralSystemURI": "" + } +} +``` + +Change into libocpp/build and execute cmake and then make install: + +```bash + cd build + cmake -DLIBOCPP16_BUILD_EXAMPLES=ON -DCMAKE_INSTALL_PREFIX=./dist .. + make -j$(nproc) install +``` + +Use the following command to start the charge point. Replace the config with [config-docker.json](/config/v16/config-docker.json) if you want to test with the [SteVe](https://github.com/steve-community/steve#docker) CSMS running in a docker container. + +```bash + ./dist/bin/charge_point \ + --maindir ./dist \ + --conf config.json +``` + +Type `help` to see a list of possible commands. + +----- + +## Build and Install `libocpp` + +For Debian GNU/Linux 11 you will need the following dependencies: + +```bash + sudo apt install build-essential cmake python3-pip libboost-all-dev libsqlite3-dev libssl-dev +``` + +OpenSSL version 3.0 or above is required. + +Clone this repository. + +```bash + git clone https://github.com/EVerest/libocpp +``` + +In the libocpp folder create a folder named build and cd into it. +Execute cmake and then make install: + +```bash + mkdir build && cd build + cmake .. + make install +``` + +----- + +## Building with FetchContent Instead of EDM + +In [doc/build-with-fetchcontent](/doc/build-with-fetchcontent) you can find an example how to build libocpp with FetchContent instead of EDM. + +----- + + +## Unit Testing + +GTest is required for building the test cases target. +To build the target and run the tests you can reference the script `.ci/build-kit/install_and_test.sh`. +The script allows the GitHub Actions runner to execute. + +Local testing: + +```bash +mkdir build +cmake -B build -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="./dist" +cd build +make -j$(nproc) install +``` + +Run any required tests from build/tests. + +----- + +## Building the Doxygen Documentation + +```bash + cmake -S . -B build + cmake --build build --target doxygen-ocpp +``` + +You will find the generated doxygen documentation at: +`build/dist/docs/html/index.html` + +The main reference for the integration of libocpp for OCPP1.6 is the ocpp::v16::ChargePoint class defined in libocpp/include/ocpp/v16/charge_point.hpp. + +----- + +## Support for TPM Keys + +In order to use the TPM keys, it is mandatory to use the default `libwebsocket` implementation. + +----- + +## Support for `websocket++` + +The old `websocket++` implementation has been deprecated. For enabling `websocket++` support use the following cmake option: + +```bash + cmake .. -DLIBOCPP_ENABLE_DEPRECATED_WEBSOCKETPP=ON +``` +----- + +## Support for `iface` + +In order to connect through a custom network `iface`, a custom internal config variable 'IFace' can be used. + +```json +"Internal": { + "IFace" : "enp43s0" +} +``` diff --git a/doc/ocpp_201_README.md b/doc/ocpp_201_README.md new file mode 100644 index 000000000..2f69b1528 --- /dev/null +++ b/doc/ocpp_201_README.md @@ -0,0 +1,654 @@ +![Github Actions](https://github.com/EVerest/libocpp/actions/workflows/build_and_test.yaml/badge.svg) + +----- + +# OCPP 2.0.1 in `libocpp` + +The `ocpp::v201` namespace exposes a `ChargePoint` class capable of client-side OCPP 2.0.1 communications. It enables charging stations to communicate with a cloud backend over a websocket for the remote control of charging stations and administration of charging sessions. + +> [!NOTE] +> For more information about the differences between versions of the Open Charge Point Protocol, please refer to the [Open Charge Alliance's website](https://openchargealliance.org/protocols/open-charge-point-protocol/). + +The OCPP 2.0.1 implementation in `libocpp` is nearing completion, but there remain areas of active development. The OCA also does not currently plan to provide an official validation tool for all functionality within the protocol until the end of 2024. A high-level overview of supported functionality is provided [below](#supported-certification-profiles). For a more granular and up-to-date analysis of available OCPP 2.0.1 features in `libocpp`, please refer to the [OCPP 2.0.1 Status document](ocpp_201_status.md). + + +## Table of Contents + +- [Supported Certification Profiles](#supported-certification-profiles) +- [CSMS Compatibility](#csms-compatibility) +- [Integration with EVerest](#integration-with-everest) +- [Standalone Integration](#standalone-integration) + - [Callbacks to Register](#callbacks-to-register) + - [Event Handlers](#event-handlers) + - [Initialize the Database](#initialize-the-database) +- [OCPP 2.0.1 Use Cases in `libocpp`](#ocpp-201-use-cases-in-libocpp) +- [Quickstart for OCPP 2.0.1](#quickstart-for-ocpp-201) +- [Building with FetchContent Instead of EDM](#building-with-fetchcontent-instead-of-edm) +- [Unit Testing](#unit-testing) +- [Building the Doxygen Documentation](#building-the-doxygen-documentation) +- [Support for TPM Keys](#support-for-tpm-keys) +- [Support for `websocket++`](#support-for-websocket) +- [Support for `iface`](#support-for-iface) + + +## Supported Certification Profiles + +Some optional OCPP 2.0.1 features are still being actively developed by the `libocpp` community. The following table shows which portions of the OCPP 2.0.1 implementation within `libocpp` are still being built out, broken down by [OCPP 2.0.1 Certification Profile](https://openchargealliance.org/certificationocpp/certification-ocpp-2-0-1/): + +| OCPP 2.0.1 Functionality | Supported | +| :------------------------- | :------------------------- | +| Core | :heavy_check_mark: Yes | +| Advanced Security | :construction: In Progress | +| Local Auth List Management | :hourglass: Planned | +| Smart Charging | :construction: In Progress | +| Advanced Device Management | :hourglass: Planned | +| Advanced User Interface | :hourglass: Planned | +| Reservation | :hourglass: Planned | +| ISO 15118 Support | :construction: In Progress | + +| Whitepapers & Application Notes | Supported | +| :------------------------------------- | :------------------------- | +| OCPP & California Pricing Requirements | :construction: In Progress | + + +## CSMS Compatibility + +The ongoing development of OCPP 2.0.1 implementation is continuously tested against OCTT2 (OCPP Compliance Testing Tool 2), and has been tested against the following Charging Station Management Systems (CSMS): + +| CSMS | +| :----------------------------------------------------------------------------------- | +| [ChargePoint](https://www.chargepoint.com/businesses/software) | +| [CitrineOS](https://lfenergy.org/projects/citrineos/) | +| [Current](https://www.current.eco/) | +| ihomer (Infuse CPMS) | +| [Instituto Tecnológico de la Energía (ITE) HySGrid+](https://www.ite.es/i-d-i/proyectos/hysgrid/) | +| [MaEVe (Thoughtworks)](https://github.com/thoughtworks/maeve-csms) | +| [Monta](https://monta.com) | +| [Open Charging Cloud (GraphDefined)](https://github.com/OpenChargingCloud/WWCP_OCPP) | +| [Switch EV](https://www.switch-ev.com/platform) | +| [SWTCH Energy](https://swtchenergy.com/) | + +## Integration with EVerest + +EVerest provides a simplified OCPP 2.0.1 integration path through its `OCPP201` module. + +When setting up a development environment (or building) EVerest through the [`everest-core`](https://github.com/EVerest/everest-core) project, a version of `libocpp` will be pulled down as a dependency. If you wish to use the `OCPP201` module, you will want to defined your charging station's Device Model in the [`config.json` file](/config/v201/config.json) for the `libocpp` repository pulled in by `everest-core` as a dependency. This configuration will be incorporated into `everest-core` during the latter's build process. + +Once `everest-core` has been built with your station-specific `libocpp` configuration, you can then specify and configure `OCPP201` as a module in the [runtime configuration](https://everest.github.io/nightly/general/04_detail_module_concept.html#wiring-it-all-together-the-run-configuration) of your EVerest deployment. + +## Standalone Integration + +OCPP is a protocol that affects, controls, and monitors many areas of a charging station's operation. The `libocpp` library is just the messenger for this protocol. It is intended to provide mechanisms for connecting to and authenticating with a CSMS, sending and receiving the OCPP messages that govern behaviors in the standard, and to the track state required for a charging station to conform to the protocol all while minimizing hardware- or implementation-specific functionality. + +The actual substance of how a charging station reacts to an OCPP command (such as `ResetRequest`) or when it should consider sending a command to the CSMS (such as `NotifyChargingLimitRequest`) is left to the rest of the charging station's systems. This is done by providing means of (a) registering **callbacks** that can be triggered by a `libocpp` `ChargePoint` in response to certain events and (b) reacting to various **event handlers** defined on a `ChargePoint` in other areas of the charging station's codebase. + +> [!IMPORTANT] +> Integrating this library with your charging station requires both (a) defining **callbacks** that enable control of your station by `libocpp` and (b) calling `libocpp` **event handlers** in your charging station's systems in response to new events and data in order to keep `libocpp` up to date on station information. + +### Terminology +Throughout this document and the `libocpp` codebase, the following conventions are followed: + +- A **callback** is a function providing the actual station-specific implementation of an OCPP command. It allows a `libocpp` `ChargePoint` to control other systems within a charging station. By convention, each callback on a `ChargePoint` has a name suffixed with `_callback` (for instance, `unlock_connector_callback`). A `Callbacks` `struct` containing a complete set of desired callback implementations (as suitable `std::function` instances) should be provided to a 2.0.1 `ChargePoint` at construction time. + +- An **event handler** is a public function defined on a `ChargePoint` that allows a charging station to update the state being tracked by the `ChargePoint` based on new information (meter values, charging session events, etc.) and (indirectly) send messages to a CSMS. By convention, the names of event handlers on the `ChargePoint` are each prefixed with `on_` (for instance, `on_meter_value`). + +The complete set of callbacks and event handlers defined on an OCPP 2.0.1 `ChargePoint` can be viewed in the latter's [header file](/include/ocpp/v201/charge_point.hpp). Please use the [Doxygen documentation](#building-the-doxygen-documentation) as an additional source of information about the `ChargePoint` API. + + +### Callbacks to Register + +| Callbacks | Description | +| :------------------------------------------------------ | :---------- | +| `all_connectors_unavailable_callback` | Notifies that all connectors are unavailable. Used to handle charge availability requests and firmware updates. | +| `boot_notification_callback` | Callback to notify of a system boot | +| `clear_customer_information_callback` | Called to clear customer information based on passed in Customer Certificate, the IdToken for this request, and the Customer Identified that the request refers to. If IdToken is passed in will delete authorization cache entry from database. | +| `configure_network_connection_profile_callback` | Called to configure a network connection profile when none is configured. | +| `connector_effective_operative_status_changed_callback` | Notifies the user of liboccp that the Operative/Inoperative state of a specific EVSE has changed. | +| `cs_effective_operative_status_changed_callback` | Used to notify the user of libocpp that the Operative/Inoperative state of the charging station itself has changed. Will also call evse_effective_operative_status_changed_callback for each EVSE, and connector_effective_operative_status_changed_callback for each connector whose status has changed. | +| `data_transfer_callback` | Used to handle arbitrary data transfers. | +| `evse_effective_operative_status_changed_callback` | Notifies the user of libocpp that the Operative/Inoperative state of an EVSE has changed. If as a result the state of connectors changed as well, libocpp will additionally call the connector_effective_operative_status_changed_callback for each connector. | +| `get_customer_information_callback` | Returns human readable customer information based on the CertificateHashDataType, IdToken and Customer Identifier passed in. | +| `get_log_request_callback` | Callback to return logs | +| `is_reservation_for_token_callback` | Check if the current reservation for the given evse id is made for the id token / group id token. | +| `is_reset_allowed_callback` | Callback if reset is allowed. If evse_id has a value, reset only applies to the given evse id. If it has no value, applies to complete charging station. | +| `ocpp_messages_callback` | Callback to congfigure ocpp message logging. | +| `pause_charging_callback` | Used to request pausing of charging, the "connector" parameter instructing which connector/EVSE to pause. | +| `remote_start_transaction_callback` | Called when the request can be accepted. The boolean authorize_remote_start indicates if Authorize.req needs to follow or not | +| `reset_callback` | Performs a reset of the requested type | +| `security_event_callback` | Used to react to a security event callback. This callback is called only if the SecurityEvent occured internally within libocpp. Typically this callback is used to log security events in the security log. | +| `set_charging_profiles_callback` | Indicates when a charging profile is received and accepted. | +| `stop_transaction_callback` | Used to stop a transaction. Called when the idTagInfo.status of a StartTransaction.conf is not Accepted, when a RemoteStopTransaction.req is received, or when an UnlockConnector.req is received. | +| `time_sync_callback` | Called on boot notification if the TimeSource ControllerComponent contains Heartbeat. | +| `transaction_event_callback` | Called when a transaction_event was sent to the CSMS. | +| `transaction_event_response_callback` | Called when a transaction_event_response was received from the CSMS. | +| `unlock_connector_callback` | Used by libocpp to force unlock a connector | +| `update_firmware_request_callback` | Initiates a firmware update request. Triggers a security event notification if the certificate is Invalid or Revoked. | +| `validate_network_profile_callback` | Validates the submitted Network Profile. Is Rejected if:
• No callback registered to validate network profile
• CSMS attempted to set a network profile with a lower securityProfile
• CSMS attempted to set a network profile that could not be validated
• Network profile could not be written to the device model storage
| +| `variable_changed_callback` | Called when a variable has been changed by the CSMS | + +### Event Handlers + + +The complete set of event handlers defined on an OCPP 2.0.1 `ChargePoint` can be viewed in the latter's [header file](/include/ocpp/v201/charge_point.hpp). Please use the [Doxygen documentation](#building-the-doxygen-documentation) as an additional source of information about the `ChargePoint` API. + +### Initialize the Database + +To initialize the database where a `ChargePoint` will persist state, please use the provided [SQLite database](/doc/database_migrations.md) or implement your own storage drive. + + +## OCPP 2.0.1 Use Cases in `libocpp` +For an in-depth guide to use cases from the OCPP 2.0.1 standard and how these use cases are implemented in `libocpp`, please see [this guide](/doc/ocpp_201_use_cases_in_depth.md). + + +## Quickstart for OCPP 2.0.1 + +This section walks you through how to sanity check that your `libocpp` development environment is set up effectively. The process will involve the following: + + + +1. Download `libocpp` from GitHub +2. Ensuring you've installed `libocpp`'s system dependencies +7. Running unit tests + +This approach can also be used later in development for testing an actual station's device model and configuration is valid in the eyes of a CSMS. + + +### Download `libocpp` +You'll first want to download the source code for `libocpp` from this repository: + +```bash +git clone https://github.com/EVerest/libocpp.git +``` + + +### Installing System Dependencies +To be able to build `libocpp`, your system needs a compatible compiler, build tools, and development libraries and headers for several dependencies installed. For instance, on Debian GNU/Linux 11, these can be installed as follows: + +```bash + sudo apt install build-essential \ + cmake \ + ninja-build \ + libboost-all-dev \ + libsqlite3-dev \ + libssl-dev \ + python3-pip +``` + +> [!WARNING] +> OpenSSL version 3.0 or above is required. + + + + + +### Unit Testing + +GTest is required for building the test cases target. +To build the target and run the tests you can reference the script `.ci/build-kit/install_and_test.sh`. +The script allows the GitHub Actions runner to execute. + +Local testing: + +```bash +mkdir build +cmake -B build -DBUILD_TESTING=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX="./dist" +cd build +make -j$(nproc) install +``` + + +## Building with FetchContent Instead of EDM + +In [doc/build-with-fetchcontent](/doc/build-with-fetchcontent) you can find an example how to build libocpp with FetchContent instead of EDM. + + +Run any required tests from build/tests. + + +## Building the Doxygen Documentation + +```bash + cmake -S . -B build + cmake --build build --target doxygen-ocpp +``` + +You will find the generated Doxygen documentation at: +`build/dist/docs/html/index.html` + +The main reference for the integration of libocpp for OCPP2.0.1 is the ocpp::v201::ChargePoint class defined in libocpp/include/ocpp/v201/charge_point.hpp. + + +## Support for TPM Keys + +In order to use the TPM keys, it is mandatory to use the default `libwebsocket` implementation. + + +## Support for `websocket++` + +The old `websocket++` implementation has been deprecated. For enabling `websocket++` support use the following cmake option: + +```bash + cmake .. -DLIBOCPP_ENABLE_DEPRECATED_WEBSOCKETPP=ON +``` + + +## Support for `iface` + +In order to connect through a custom network `iface`, a custom internal config variable 'IFace' can be used. + +```json +"Internal": { + "IFace" : "enp43s0" +} +``` + diff --git a/doc/ocpp_201_use_cases_in_depth.md b/doc/ocpp_201_use_cases_in_depth.md new file mode 100644 index 000000000..dfccb01c1 --- /dev/null +++ b/doc/ocpp_201_use_cases_in_depth.md @@ -0,0 +1,214 @@ +## OCPP 2.0.1 Use Cases in `libocpp` + +The OCPP 2.0.1 specification is broken down into concrete functional requirements using a three-tier system. At the top, there are sixteen **functional blocks** lettered A through P that describe the high-level desired capabilities of actors adhering to the standard. These functional blocks are then broken into **use cases** that describe different scenarios in which one or more charging stations, local controllers, and charging station management systems might find themselves. The required and optional behaviors of these systems in these scenarios are then declared as **functional requirements** within each use case. + +This section includes an overview of how a subset of the OCPP 2.0.1 use cases that supported by `libocpp` are implemented in conjunction with callbacks provided by the charging station. We hope it serves as a useful guide to portions of the `libocpp` API and illustrates patterns of interaction between `libocpp` and other systems within a charging station. + +> [!NOTE] +> Our goal is not to reproduce the entire OCPP 2.0.1 specification in this document. Rather we intend to illustrate how various use cases are realized using `ChargePoint` methods in `libocpp` in conjunction with callback implementations and event handlers. +> +> Please refer to the [OCPP 2.0.1 standard](https://openchargealliance.org/protocols/open-charge-point-protocol/#OCPP2.0.1) for more details. Functional blocks, use cases, and functional requirements are addressed in Part 2 of Edition 2. + +| Functional Block | Subject | +| :--------------- | :------------------------------------------ | +| A | Security | +| B | Provisioning | +| C | Authorization | +| D | Local Authorization List Management | +| E | Transactions | +| F | Remote Control | +| G | Availability | +| H | Reservation | +| I | Tariff and Cost | +| J | Meter Values | +| K | [Smart Charging](#smart-charging-use-cases) | +| L | Firmware Management | +| M | ISO 15118 Certificate Management | +| N | Diagnostics | +| O | Display Message | +| P | Data Transfer | + +### Smart Charging Use Cases + +The use cases within the Smart Charging functional block are subdivided into the following three categories of use cases: + +1. General Smart Charging (Use Cases K01–K10) +2. External Charging Limit-based Smart Charging (K11–K14) +3. ISO 15118-based Smart Charging (K15–K17) + +Support for General and External Charging Limit-based Smart Charging is largely complete, with ISO 15118-based Smart Charging under active development. For an up-to-date overview of exactly which features are currently supported as well as design decisions that have been made to address optional or ambiguous functional requirements, please refer to the [OCPP 2.0.1 Status document](ocpp_201_status.md). + +#### K01 SetChargingProfile + +Allows the CSMS to influence the charging power or current drawn from a specific EVSE or the +entire Charging Station over a period of time. + +```mermaid +sequenceDiagram + CSMS->>+ChargePoint : SetChargingProfileRequest(call) + + ChargePoint->>+DeviceModel : SmartChargingCtrlrAvailable? + DeviceModel-->>-ChargePoint : Component + + rect rgb(128,202,255) + break SmartChargingCtrlrAvailable = false + ChargePoint-->>CSMS : Smart Charging NotSupported CallError + end + end + + ChargePoint->>+SmartCharging : validate_and_add_profile(call.msg.Profile, call.msg.EVSE ID) + + SmartCharging->>SmartCharging : validate_profile(Profile, EVSE ID) + + rect rgb(128,202,255) + break Invalid Profile + SmartCharging-->>ChargePoint : SetChargingProfileResponse: Rejected + ChargePoint-->>CSMS : SetChargingProfileResponse: Rejected + end + end + + SmartCharging->>+SmartCharging : add_profile(Profile, EVSE ID) + SmartCharging->>-EVerest : signal_set_charging_profiles_callback + + SmartCharging-->>-ChargePoint : SetChargingProfileResponse: Accepted + + ChargePoint-->>-CSMS : SetChargingProfileResponse: Accepted +``` + +Profile validation returns the following errors to the caller when a Profile +is `Rejected`: + +| Errors | Description | +| :------------------------------------------------------------ | :-------------------------------------------------------------- | +| `ChargingProfileFirstStartScheduleIsNotZero` | The `startPeriod` of the first `chargingSchedulePeriod` needs to be 0.
[K01.FR.31] | +| `ChargingProfileNoChargingSchedulePeriods` | Happens when the `ChargingProfile` doesn't have any Charging Schedule Periods. | +| `ChargingScheduleChargingRateUnitUnsupported` | Happens when a chargingRateUnit is passed in that is not configured in the `ChargingScheduleChargingRateUnit`. [K01.FR.26] | +| `ChargingSchedulePeriodInvalidPhaseToUse` | Happens when an invalid `phaseToUse` is passed in. [K01.FR.19] [K01.FR.48] | +| `ChargingSchedulePeriodPhaseToUseACPhaseSwitchingUnsupported` | Happens when phaseToUse is passed in and the EVSE does not have `ACPhaseSwitchingSupported` defined and set to true. [K01.FR.20] [K01.FR.48] | +| `ChargingSchedulePeriodsOutOfOrder` | `ChargingSchedulePeriod.startPeriod` elements need to be in increasing values. [K01.FR.35] | +| `ChargingStationMaxProfileCannotBeRelative` | Happens when a `ChargingStationMaxProfile.chargingProfileKind` is set to `Relative`. [K01.FR.38] | +| `ChargingStationMaxProfileEvseIdGreaterThanZero` | Happens when a `ChargingStationMaxProfile` is attempted to be set with an EvseID isn't `0`. [K01.FR.03] | +| `ChargingProfileMissingRequiredStartSchedule` | Happens when an `Absolute` or `Recurring` `ChargingProfile` doesn't have a `startSchedule`. [K01.FR.40] | +| `ChargingProfileExtraneousStartSchedule` | Happens when a Relative `ChargingProfile` has a `startSchedule`. [K01.FR.41] | +| `EvseDoesNotExist` | Happens when the `evseId`of a `SetChargingProfileRequest` does not exist. [K01.FR.28] | +| `ExistingChargingStationExternalConstraints` | Happens when a `SetChargingProfileRequest` Profile has a purpose of `ChargingStationExternalConstraints` and one already exists with the same `ChargingProfile.id` exists. [K01.FR.05] | +| `InvalidProfileType` | Happens when a `ChargingStationMaxProfile` is attempted to be set with a `ChargingProfile` that isn't a `ChargingStationMaxProfile`. | +| `TxProfileEvseHasNoActiveTransaction` | Happens when a `SetChargingProfileRequest` with a `TxProfile` is submitted and there is no transaction active on the specified EVSE. [K01.FR.09] | +| `TxProfileEvseIdNotGreaterThanZero` | `TxProfile` needs to have an `evseId` greater than 0. [K01.FR.16] | +| `TxProfileMissingTransactionId` | A `transactionId` is required for`SetChargingProfileRequest`s with a `TxProfile` in order to match the profile to a specific transation. [K01.FR.03] | +| `TxProfileTransactionNotOnEvse` | Happens when the provided `transactionId` is not known. [K01.FR.33] | +| `TxProfileConflictingStackLevel` | Happens when a TxProfile has a stackLevel and transactionId combination already exists in a TxProfile with a different id in order to ensure that no two charging profiles with same stack level and purpose can be valid at the same time. [K01.FR.39] | + + +#### K08 Get Composite Schedule + +The CSMS requests the Charging Station to report the Composite Charging +Schedule, as calculated by the Charging Station for a specific point of +time, and may change over time due to external causes such as local +balancing based on grid connection capacity and EVSE availablity. + +The Composite Schedule is the result of result of merging the time periods +set in the `ChargingStationMaxProfile`, `ChargingStationExternalConstraints`, +`TxDefaultProfile` and `TxProfile` type profiles. + +```mermaid +sequenceDiagram + + CSMS->>+ChargePoint: GetCompositeSchedule(call) + + ChargePoint->>+DeviceModel : ChargingScheduleChargingRateUnit? + DeviceModel-->>-ChargePoint : Component + + rect rgb(128,202,255) + break call.msg.chargingRateUnit is not supported + ChargePoint-->>CSMS : ChargingScheduleChargingRateUnitUnsupported CallError + end + end + + ChargePoint->>+EvseManager : does_evse_exist(call.msg.evseId) + EvseManager-->>-ChargePoint : bool + rect rgb(128,202,255) + break EVSE does not exist + ChargePoint-->>CSMS : EvseDoesNotExist CallError + end + end + + ChargePoint->>+SmartChargingHandler : get_valid_profiles(call.msg.evseId) + + SmartChargingHandler-->>-ChargePoint : vector + + ChargePoint->>+SmartChargingHandler : calculate_composite_schedule
(vector>+Profile: calculate_composite_schedule(profiles) + Profile-->>-SmartChargingHandler: composite_schedule + end + + note right of SmartChargingHandler: Create consolidated CompositeSchedule
from all 4 Profile types + + + SmartChargingHandler->>+Profile: calculate_composite_schedule(ExternalConstraints, Max, TxDefault, Tx) + Profile-->>-SmartChargingHandler: CompositeSchedule + + SmartChargingHandler-->>-ChargePoint: CompositeSchedule + + ChargePoint-->>-CSMS : GetCompositeScheduleResponse(CompositeSchedule) +``` + + +#### K09 Get Charging Profiles + +Returns to the CSMS the Charging Schedules/limits installed on a Charging Station based on the +passed in criteria. + +```mermaid +sequenceDiagram + + CSMS->>+ChargePoint: GetChargingProfiles(criteria) + + ChargePoint->>+SmartChargingHandler : get_reported_profiles(criteria) + + loop filter ChargingProfiles + SmartChargingHandler->>SmartChargingHandler: filter on ChargingProfile criteria + end + + SmartChargingHandler-->>-ChargePoint : Vector + + ChargePoint-->>CSMS : GetChargingProfilesResponse(profiles) + + alt no Profiles + rect rgb(128,202,255) + ChargePoint-->>CSMS : GetChargingProfilesResponse(NoProfiles) + ChargePoint->>CSMS : return + end + + else Profiles + ChargePoint-->>CSMS : GetChargingProfilesResponse(Accepted) + end + + ChargePoint->>ChargePoint : determine profiles_to_report + + ChargePoint-->>-CSMS : ReportChargingProfilesRequest(profiles_to_report) +``` + + +#### K10 Clear Charging Profile + +Clears Charging Profiles installed on a Charging Station based on the +passed in criteria. + +```mermaid +sequenceDiagram + + CSMS->>+ChargePoint: ClearChargingProfileRequest(criteria) + + alt no Profiles matching criteria + rect rgb(128,202,255) + ChargePoint-->>CSMS : ClearChargingProfileResponse(Unknown) + + end + + else found matching Profiles + ChargePoint-->>-CSMS : ClearChargingProfileResponse(Accepted) + end +```