OCPP 1.6 and 2.x with the Combined Module

EVerest provides a single module, OCPPmulti, that implements OCPP 1.6J, OCPP 2.0.1 and OCPP 2.1. It is the recommended way to run OCPP in EVerest and replaces the separate OCPP 1.6 and OCPP 2.x modules. Which protocol generation is used is controlled by a single module configuration parameter, Mode, so the same EVerest configuration can serve charging stations that talk to 1.6 or 2.x CSMSs.

For the full list of configuration parameters, provided and required interfaces, please see the module documentation.

This tutorial includes:

  • How to run EVerest SIL with OCPPmulti against a local CSMS

  • How the OCPP version is chosen via the Mode parameter

  • How to configure the OCPP device model via component configs

  • How to handle OCPP 1.6 configuration options

  • How to connect to a different CSMS

  • How to enable Plug&Charge

Prerequisites

If you’re new to EVerest, start with our Quick Start Guide to get a simulation in EVerest running for the first time. If you have done that successfully, you can move on with this tutorial.

Depending on the protocol generation you want to test, you need a local CSMS:

  • For OCPP 1.6, the Open Source CSMS SteVe is used as an example. Make sure you have set up the required docker containers for Mosquitto and SteVe.

  • For OCPP 2.x, EVerest provides a simple CSMS that responds “friendly” to all OCPP messages initiated by the charging station. Follow the instructions of its README to start it up locally. By default it listens on localhost:9000.

Run EVerest SIL with a CSMS

The EVerest repository provides the configuration config-sil-ocpp-multi.yaml that you can use to run EVerest with OCPPmulti.

Simply run

${EVEREST_WORKSPACE:?}/EVerest/build/run-scripts/run-sil-ocpp-multi.sh

to start EVerest with the combined OCPP module. You can start playing around with the EVerest simulation to start charging sessions.

Which protocol generation is used is selected by the module’s Mode configuration parameter (see Choosing the OCPP version). The example configuration ships with Mode: Only1.6; switch it to Mode: Only2 to run OCPP 2.x:

  • With OCPP 1.6, the example configuration connects to SteVe. You have to add the chargepoint id cp001 in SteVe’s webinterface to allow the charging station to connect. If you want to simulate charging sessions, you also need to add OCPP tags for the authorization in SteVe.

  • With OCPP 2.x, the default device model configuration connects to localhost:9000, which is also the default address and port of our simple CSMS.

You can find the OCPP message log in different formats in the /tmp/everest_ocpp_logs directory. A new logfile is created every time EVerest is started.

Choosing the OCPP version

The protocol generation (OCPP 1.6 or OCPP 2.x) is selected by the Mode configuration parameter of the OCPPmulti module:

  • Only1.6: run OCPP 1.6

  • Only2: run OCPP 2.x (default)

  • Prefer1.6 / Prefer2: currently behave exactly like Only1.6 / Only2; they are reserved for a possible future automatic fallback to the other protocol generation, which is not implemented yet

Within OCPP 2.x, the concrete version (2.0.1 or 2.1) is negotiated with the CSMS during the initial websocket handshake. The SupportedOcppVersions variable of the InternalCtrlr device model component controls which 2.x versions the charging station offers; it is a comma-separated list of ocpp2.1 and ocpp2.0.1 in order of preference (by default both are offered). Configure it like any other device model variable, by setting the value of its Actual attribute in the InternalCtrlr component config (see Device model configuration via component configs).

Note

It depends on the CSMS which of the offered 2.x versions is actually used. For more information about the version selection, please refer to the OCPPmulti module documentation and the OCPP 2.1 Part 4 - JSON over WebSockets implementation guide.

Device model configuration via component configs

OCPPmulti is configured through the OCPP device model, regardless of the OCPP version in use. OCPP 2.x defines a device model structure and a lot of standardized variables that are used within the functional requirements of the protocol. Please see “Part 1 - Architecture & Topology” of the OCPP 2.0.1 specification for further information about the device model and how it is composed. You should be familiar with the OCPP 2.x terms Component, Variable, VariableCharacteristics, VariableAttributes and VariableMonitoring to be able to follow the further explanations.

Note

The device model configured here is the OCPP device model: components and variables that you as an integrator define and configure via JSON component config files. It is distinct from the EVerest device model, which the module builds at runtime from the connected EVerest modules (e.g. EVSE and Connector components). You do not configure the latter via component configs. Please see the module documentation for a full explanation of the two device models and how they interact.

Device model definition and configuration structure

The device model is defined and configured using JSON files. These files serve two main purposes:

  • Definition: the device model (including its components and variables)

  • Configuration: the value of variable attributes

There is one JSON file for each Component. Each Component contains the definition of its Variables. Each Variable contains the definition of its VariableCharacteristics, VariableAttributes and VariableMonitoring. The actual value of a Variable can be configured as part of the VariableAttribute(s).

This is how a definition and configuration for the LocalAuthListCtrlr component could look like (abbreviated):

{
  "description": "Schema for LocalAuthListCtrlr",
  "name": "LocalAuthListCtrlr",
  "type": "object",
  "properties": {
    "LocalAuthListCtrlrEnabled": {
      "variable_name": "Enabled",
      "characteristics": {
        "supportsMonitoring": true,
        "dataType": "boolean"
      },
      "attributes": [
        {
          "type": "Actual",
          "mutability": "ReadWrite",
          "value": true
        }
      ],
      "description": "If this variable exists and reports a value of true, Local Authorization List is enabled.",
      "default": true,
      "type": "boolean"
    },
    "BytesPerMessageSendLocalList": {
      "variable_name": "BytesPerMessage",
      "characteristics": {
        "supportsMonitoring": true,
        "dataType": "integer"
      },
      "attributes": [
        {
          "type": "Actual",
          "mutability": "ReadOnly",
          "value": 4096
        }
      ],
      "description": "Maximum number of bytes in a SendLocalList message.",
      "type": "integer"
    },
    "LocalAuthListCtrlrEntries": {
      "variable_name": "Entries",
      "characteristics": {
        "supportsMonitoring": true,
        "dataType": "integer"
      },
      "attributes": [
        {
          "type": "Actual",
          "mutability": "ReadOnly"
        }
      ],
      "description": "Amount of IdTokens currently in the Local Authorization List",
      "type": "integer"
    }
  },
  "required": [
    "BytesPerMessageSendLocalList",
    "LocalAuthListCtrlrEntries"
  ]
}

You can change the components according to your needs, but note that the definitions for the variable_name and characteristics are usually defined by the OCPP 2.x specifications. To configure a variable attribute value, specify the value for the attribute type that you would like to configure. In the example above, the actual value of the VariableAttribute of the Variable Enabled is set to true. Note that not all variables have specified variable attributes with a value, e.g. LocalAuthListCtrlrEntries does not specify a value. It is telemetry rather than configuration, and therefore a configuration value it is not required. It’s an example of a variable that is only defined.

The config files are parsed at startup and used to initialize an SQLite database. You should specify the path to the directory of your device model definitions using the configuration parameter DeviceModelConfigPath of the OCPPmulti module within EVerest. It shall point to the directory where the component files are located in these two subdirectories:

  • standardized

  • custom

By default, DeviceModelConfigPath is pointing to the installation directory of the component files. The split between the two directories only has semantic reasons. The standardized directory usually does not need to be modified since it contains standardized components and variables that the specification refers to in its functional requirements. The custom directory is meant to be used for components that are custom for your specific charging station.

It is recommended to use the device model definitions of libocpp as a starting point. This is an exemplary device model configuration for two EVSEs.

OCPP 1.6 configuration options

Historically, the OCPP 1.6 implementation was configured using a separate JSON configuration file containing the OCPP 1.6 configuration keys. With OCPPmulti, the OCPP 1.6 configuration keys are also served from the device model, so there are two ways to configure OCPP 1.6:

  1. Pure device model (recommended for new deployments): Configure everything via the component configs described in Device model configuration via component configs. The module maps OCPP 1.6 configuration keys to device model variables via built-in mappings (documented in lib/everest/ocpp/config/v16_to_v2_mapping.md). Custom mappings can be provided using the DeviceModelConfigMappings configuration parameter.

  2. Legacy JSON with a one-time migration: For existing OCPP 1.6 deployments, set EnableLegacyConfigMigration: true. On the first startup (while the device model database does not yet exist), the legacy OCPP 1.6 JSON config referenced by ChargePointConfigPath is migrated into the device model database once. Network connection details (CentralSystemURI, SecurityProfile, AuthorizationKey, …) are migrated to the NetworkConfiguration slot given by Ocpp16NetworkConfigSlot. Once the database is initialized, the migration is skipped and the legacy JSON is no longer read.

For a detailed walkthrough of migrating an existing OCPP 1.6 deployment, please see the storage migration guide.

Network configuration

OCPP uses NetworkConfiguration components in the device model to define how the charging station connects to a CSMS. This applies to all protocol versions, including OCPP 1.6. Each connection profile is stored as a separate component instance (called a slot), and a priority list determines the order in which slots are tried during connection and failover.

Connect to a different CSMS

Each connection profile is defined in its own JSON file under the device model configuration directory. At least two slots must be configured; you may add as many additional slots as you need (see Adding more network configuration slots). The default profiles are:

  • component_config/standardized/NetworkConfiguration_1.json (slot 1)

  • component_config/standardized/NetworkConfiguration_2.json (slot 2)

To connect to a different CSMS, modify the following variables in the appropriate slot’s JSON file:

  • OcppCsmsUrl: The WebSocket endpoint of the CSMS, without the charging-station identifier path segment (e.g. ws://csms.example.com:9000 or wss://csms.example.com:443). The identifier from Identity is appended at connect time.

  • SecurityProfile: Defines the transport layer security level:

    • 0: No security (OCPP 1.6 compatibility, disabled by default)

    • 1: Basic authentication over ws://

    • 2: TLS with server certificate over wss://

    • 3: TLS with mutual authentication (client + server certificates) over wss://

  • MessageTimeout: Message timeout in seconds (minimum 1)

Each slot can optionally override the charging station’s identity and authentication credentials:

  • Identity: Per-slot identity override. If empty, falls back to SecurityCtrlr.Identity.

  • BasicAuthPassword: Per-slot password override. If empty, falls back to SecurityCtrlr.BasicAuthPassword.

The global fallback values are configured in the SecurityCtrlr component:

  • Identity in SecurityCtrlr: The default identity of the charging station

  • BasicAuthPassword in SecurityCtrlr: The default password for HTTP Basic Authentication (SecurityProfile 1 or 2)

The connection priority is controlled by the NetworkConfigurationPriority variable in OCPPCommCtrlr. This is a comma-separated list of slot numbers that determines the order in which profiles are tried. For example, "1,2" means slot 1 is tried first; if it fails, slot 2 is tried, then back to slot 1 (round-robin failover).

Note

For TLS (SecurityProfile 2 or 3), you must prepare the required certificates and private keys. Please see the documentation of the EvseSecurity module for more information on how to set up the TLS connection for OCPP.

Adding more network configuration slots

By default, two NetworkConfiguration slots are shipped. To add more:

  1. Create the JSON file. Copy an existing slot file (e.g. NetworkConfiguration_1.json) to a new file named NetworkConfiguration_N.json where N is your slot number.

  2. Update the instance number. In the new file, change the "instance" field at the top level to match your slot number:

    {
      "name": "NetworkConfiguration",
      "instance": "3",
      ...
    }
    
  3. Configure the slot’s variables. Set OcppCsmsUrl, SecurityProfile, and other variables as needed for this connection profile.

  4. Add the slot to the priority list. In OCPPCommCtrlr.json, append the new slot number to the NetworkConfigurationPriority value. For example, change "1,2" to "1,2,3".

  5. Rebuild and restart. The device model database will be re-initialized with the new slot on next startup.

Enable Plug&Charge

In order to enable Plug&Charge, adjust your component files according to the Plug&Charge configuration documentation.


Authors: Piet Gömpel