Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter

- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
This commit is contained in:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,277 @@
############
EVerest APIs
############
.. tip::
You can find the API reference documentation here:
:doc:`EVerest API Reference </reference/api/autogenerated_api_index>` .
EVerest can be extended and adapted to specific needs via two sets of
APIs: The internal interfaces and the EVerest API.
The EVerest API are versioned and guaranteed to not introduce breaking
changes for the same major version of the API, while the internal
interfaces may change between versions. Therefore, the EVerest API
is the preferred way to implement custom integrations,
extensions and adaptations.
.. tip::
If you plan to integrate EVerest on your charging station hardware we
strongly recommend to use the EVerest APIs for this purpose, since these
interfaces are the ones that are supposed to be kept stable and maintained.
over time.
Overview
========
The EVerest API is the interface for hardware integration,
custom extensions and adaptations.
It is provided via a public MQTT interface, and the format for data
exchange is plain text JSON. The API is defined in AsyncAPI 3.
Custom client software using the EVerest API is therefore only loosely
coupled to the EVerest application and its internal interfaces.
There are no obligatory binary or link time dependencies of any kind.
As a result, the clients can be built individually and without
reference to the EVerest application at all.
This also implies that the programming language used for implementing
the client can be chosen freely. Typically a compiled language is
preferable for an embedded target, but it is not strictly required at
all.
The EVerest API is implemented in terms of EVerest modules, and every
API module implements one or more of EVerest's internal interfaces.
There are two distinct versions of API modules, either to implement
an interface (e.g. a driver for a DC power supply) or to consume it
(e.g. to check for the validation status of a token).
They can be included in the configuration file just like any other
module. E.g. - in this example -, a EVerest API module was loaded to
fulfill the power meter requirement of the EvseManager. The actual code
that talks to the power meter hardware to fetch the measurements can now
be implemented in a process running outside of EVerest (and is started
e.g. by a separate *systemd* unit). It just needs to feed the measured
values via MQTT into the
:ref:`Powermeter API module <everest_modules_powermeter_API>`.
.. figure:: images/everest-api-1.png
:alt: EVerest API - Image 1
:width: 450px
For a better understanding of how the EVerest API works, let us have an
exemplary closer look at the
:ref:`Power Supply DC API module <everest_modules_power_supply_DC_API>`.
The manifest can be reduced to this:
.. code-block:: yaml
config:
cfg_communication_check_to_s:
type: integer
default: 5
cfg_heartbeat_interval_ms:
type: integer
default: 1000
provides:
if_power_supply_DC:
interface: power_supply_DC
There are two configuration variables which are common for every API
module. Both are related to communication checks between EVerest and
the client module.
Below, there is the *provides* section, which states that this API
module *is* a :doc:`DC power supply </reference/interfaces/power_supply_DC>`.
This implies that it can be used in the configuration file for EVerest
wherever a DC power supply is expected.
In a product, this would be the :ref:`EvseManager <everest_modules_EvseManager>`
requiring a DC power supply. During development or validation it could also be a
BringUp module.
In contrast to an integrated driver for actual hardware, the API module
creates MQTT topics according to its specification and by this provides
hooks for the client to do the implementation work.
The documentation of the APIs can be found in the respective :doc:`reference
pages </reference/api/autogenerated_api_index>`. Each API module has its own
reference page describing the messages, topics and data structures used.
Let's take a look at an example configuration that uses the API module:
.. code-block:: yaml
active_modules:
ps_dc_1:
module: power_supply_DC_API
config_module:
cfg_communication_check_to_s: 60
cfg_heartbeat_interval_ms: 1000
cli:
module: BUPowerSupplyDC
standalone: true
connections:
psu:
- module_id: ps_dc_1
implementation_id: if_power_supply_DC
It loads two modules:
The :ref:`power_supply_DC_API <everest_modules_power_supply_DC_API>`
and the
:ref:`BringUp module for DC power supplies <everest_modules_BUPowerSupplyDC>`.
Starting EVerest with this configuration enables the API for DC power
supplies and a BringUp module, that can send to and receive messages from the
API. The actual topics on the MQTT will be available under
*everest_api/1/power_supply_DC/ps_dc_1/*.
It is as simple as this.
As explained previously, the client is only loosely coupled to EVerest.
As a consequence, EVerest cannot know by itself whether the client is
available and in good working conditions. For this reason, a
bidirectional communication check is available.
EVerest APIs sends *heartbeat* messages periodically
(*cfg_heartbeat_interval_ms* - with negative values disabling heartbeat
messages) and on the other hand requires the clients to send
*communication_check* messages within the timeout interval specified
(*cfg_communication_check_to_s* - with negative values disabling the
requirement for these messages).
In situations where a request/reply pattern is implemented, the timeout
for a response can be configured (*cfg_request_reply_to_s* - these timeouts
cannot be disabled since internal EVerest timeouts apply) . In general it
is advisable to respond as quickly as possible in to to prevent EVerest
from blocking internally.
AsyncAPI
========
The EVerest API is defined in terms of AsyncAPI 3.0.0.
For a thorough introduction and reference refer to
https://www.asyncapi.com .
All EVerest API modules are located in *EVerest/modules/API* and each
module contains the API definition in
*EVerest/docs/source/reference/EVerest_API/<name-of-api>.yaml* file.
These files are used to generate the
:doc:`HTML-based documentation </reference/api/autogenerated_api_index>`.
In order to build the documentation including the API reference pages,
run the following command in your *build* folder:
.. code-block:: bash
cmake -DEVEREST_BUILD_DOCS=ON .. && make trailbook_everest
Another possible way is to use the AsyncAPI yaml source file in
`AsyncAPI Studio <https://https://studio.asyncapi.com/>`_.
The *<name-of-api>.yaml* is defined for the client implementing the API and
reflects the client's point of view, when using the words *send* and
*receive* in the context of actions and operations.
The MQTT topics of the EVerest API follow a fixed pattern. All topics
are prefixed with *everest_api/1/{api_type}/{module_id}* - with *1*
being the version and *{api_type}* the type of the API.
*{module_id}* is the *module id* of the API module as configured in the
EVerest configuration file.
The prefix is followed by the direction of the message. There are two
options:
- *m2e* for messages from the module (client) to EVerest and
- *e2m* for messages from EVerest to the module (client).
This is finally followed by the name of the message. Here is a complete
example:
.. code-block:: text
everest_api/1/power_supply_DC/ps_dc_1/m2e/voltage_current
In the example, *power_supply_DC* is the API type, *ps_dc_1* is the
*module id* as configured in the EVerest configuration file, the
message (*m2e*) originates from the client and is directed towards
EVerest. The message name is *voltage_current*.
AsyncAPI defines channels which carry messages. A channel can be
addressed via the topic as defined above. Each channel can in principle
carry multiple messages, but concerning EVerest API, there is a
one-to-one mapping between a message and a channel. A message carries
content in the form of payload and possibly headers.
The content type for EVerest API is always JSON. The content is
individual for each message and defined in *components:schemas* within
the same file or sometimes in a referenced file.
AsyncAPI finally specifies operations on channels. The operations define
the action on a specific channel (for EVerest API always from the
client's point of view), which can be *send* or *receive*.
In many situations, the sender of a message is not interested in the
receive status of a message, e.g. in a situation where a meter publishes
its current values. Simple send and receive operations are used in this
case.
There are situations however, where this is not the case, e.g. remote
procedure calls or when a reply is requested. EVerest API handles this
situation with the request/reply pattern offered by AsyncAPI.
The operations are then augmented with a reply property holding the
reply channel and a dynamic reply address.
If the client receives a request, it has to reply to the topic provided
in the header's *replyTo* property within *cfg_communication_check_to_s*
seconds. If it does not, a default response is given by the API to
EVerest and an error is raised.
If the client sends a request, it has to specify the reply topic, where
it expects the answer. This information is communicated via the
*replyTo* property of the headers object. It is the client's
responsibility to ensure that the topic is unique in order to relate
replies to requests.
Using the EVerest API
======================
In order to use the EVerest API, load the required API modules in the
EVerest configuration file and connect its interfaces as presented in
the *Overview* section.
The chosen *module id* becomes part of the MQTT topic. EVerest API
modules can be loaded multiple times, e.g. if two DC power supplies are
connected.
If needed, adjust the heartbeat interval and communication check timeout
via the *cfg_heartbeat_interval_ms* and *cfg_communication_check_to_s*
configuration variables of the module.
Although communication check and heartbeat can be disabled with values
smaller or equal to zero, this is not recommended in a production
environment, since they are the only way to continuously check whether
the client and EVerest are online and responsive.
EVerest API clients are completely independent applications. They have
to be started independently of EVerest, possibly by their own *systemd*
service.
EVerest cannot start them, since it is agnostic of them. On EVerest
startup, the API modules raise an initial communication check error (if
communication check is enabled). This error is cleared with the first
communication check message sent from the client. It is raised again
when a timeout occurs or a request is not answered. Sending a
communication check message clears the error again.
It is the responsibility of the user to ensure that the client is and
remains available. This includes potentially a *watchdog* that restarts
the client in case of crash or deadlock. It is also the client's
responsibility to ensure proper initialization, shutdown and
surveillance of managed hardware, e.g. a DC power supply.

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 308 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 258 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 402 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

View File

@@ -0,0 +1,14 @@
#############
Adapt EVerest
#############
EVerest is designed to be easily adaptable to different use cases and
environments. This section will guide you through the process of adapting
EVerest to your specific needs by explaining the various sub-systems and APIs
available.
.. toctree::
:maxdepth: 1
sub-systems
apis

View File

@@ -0,0 +1,416 @@
###########
Sub-systems
###########
The following sections are a functional description of the subsystems of
EVerest. A subsystem is a group of modules that together implement a
specific functionality. This documentation guides you through some of the
most important subsystems step by step, showing how to build them up from
individual modules. The following subsystems will be explained:
- Charging subsystem
- Authentication subsystem
- OCPP subsystem
- Energy management subsystem
Charging subsystem
==================
The charging subsystem contains all modules that are responsible for the
charging logic, car communication and hardware drivers related to a
single charging port. For multiple charging ports the whole subsystem
can simply be duplicated.
It depends on the Authentication subsystem to authorize charging
sessions and on the Energy management subsystem to allocate the energy
budget for the charging process.
The main module of this subsystem is the
:ref:`EvseManager <everest_modules_EvseManager>`.
It contains all the logic and state machines for one CCS AC or DC charging
port.
.. _ac-charging-port:
AC charging port
------------------
Let's build an AC charging port step by step. Start with the EvseManager
module. For a simple AC charger, the default configuration of the module
is sufficient.
First, we add a board support module. This is the most important
hardware driver.
In this example, we use the :ref:`YetiDriver <everest_modules_YetiDriver>`
module which is the BSP driver for the BelayBox. Check the configuration of
the module; it should be correct for the BelayBox. Click on the (i) button
to learn more about each configuration setting.
.. figure:: images/yeti-driver-config.png
:alt: Yeti Driver Configuration
:width: 320px
The first connection is for the mandatory
:doc:`evse_board_support interface </reference/interfaces/evse_board_support>`.
It implements the following functionality:
- Control Pilot Signal (CP): Set PWM duty cycle in X2, State X1/F,
report states A-F
- Set allow relays on/off flag
- Report PP resistor (if used)
- Report AC input current / phases capabilities of the system
- Stop charging button input
.. figure:: images/yeti-evse-connection.png
:alt: Yeti Driver connected to EVSE Manager
:width: 360px
As you can see, there are two more connections between the
YetiDriver and the EvseManager. Those are optional:
- :doc:`connector_lock </reference/interfaces/connector_lock>`
(if used in the hardware): EvseManager requests
locking/unlocking of the connector lock (for AC Type 2 Sockets)
- :doc:`ac_rcd </reference/interfaces/ac_rcd>` (optional):
Reports information about the RCD module in an
AC charger. This is only used for telemetry and error reporting,
the actual shutdown needs to be handled in hardware.
These two modules already allow basic AC charging functionality. Next
step is to add a power meter to allow for invoicing the charged amount
of energy. It may not be needed e.g. in a private installation.
You can use any hardware driver module that provides a
:doc:`powermeter interface </reference/interfaces/powermeter>`
implementation. For the BelayBox, we could have used the
*powermeter* implementation of the YetiDriver (which uses the Yeti
onboard metering). In most configurations, an external DIN-rail power
meter is used with an RS485/ModBus connection, so we use the
:ref:`GenericPowermeter <everest_modules_GenericPowermeter>`
module here:
.. figure:: images/powermeter-connection.png
:alt: Power meter connection
:width: 420px
:ref:`GenericPowermeter <everest_modules_GenericPowermeter>`
is a module that can easily be adapted to most ModBus-based
AC power meters by specifying the register mappings in the
configuration of that module. It requires a
:ref:`SerialCommHub <everest_modules_SerialCommHub>`
module to do the actual read/write to the serial RS485 port of the system.
This is a separate module as multiple device drivers may use the same
serial bus, so they can all be connected to the same
:ref:`SerialCommHub <everest_modules_SerialCommHub>` module.
Make sure to configure the correct serial device and baud rate.
Note that there are two optional requirements for power meters in the
EvseManager: *powermeter_grid_side* and *powermeter_car_side*. The first
one should be used if the power meter is measuring on the AC input side,
the second one should be used if it is measuring the output power to the
vehicle. It is ok to connect both if you have two power meters. For AC,
one is generally sufficient. For DC, two meters on AC and DC side may be
useful.
Next step is to add ISO communication, if support for AC ISO15118-2 is
desired:
.. figure:: images/iso-communication-connection.png
:alt: ISO Communication Connection
:width: 700px
Three modules have been added:
:ref:`EvseV2G <everest_modules_EvseV2G>`:
Implementation of ISO15118-2(AC/DC) and DIN SPEC70121(DC).
Connects to the *hlc/ISO15118_charger* requirement of EvseV2G. Make sure
to set the “device” config option to the ethernet device of the PLC
modem. Leave the other options on default for now.
:ref:`EvseSecurity <everest_modules_EvseSecurity>`:
Handles certificates and private keys for TLS/PnC. We
will connect it here even though PnC is not enabled yet.
:ref:`EvseSlac <everest_modules_EvseSlac>`:
Implementation of ISO15118-3 (SLAC) to pair the PLC modems
of the EV and the EVSE at the start of the session. Make sure to
configure the same “device” as used for the EvseV2G. The two must point
to the same PLC modem.
To actually enable ISO 15118, some settings in the EvseManager module
need to be adjusted:
----
.. figure:: images/enable-iso15118.png
:alt: Enable ISO 15118
:width: 350px
----
The recommended setting is to use *ac_hlc_enable*, which allows ISO
15118-2 sessions on AC. In this configuration, nominal PWM (>10% duty
cycle) will be used the same way as it is used for basic charging
(non-ISO) sessions. This is the most interoperable way that charges all
cars, even if they do not support ISO 15118-2 on AC. All other options
will only charge a subset of EVs out there.
Some cars however may not use ISO at all if they detect nominal PWM -
even if they support ISO 15118-2. You enable set *ac_hlc_use_5percent*
to start with 5% duty cycle PWM on CP similar to DC charging.
Several cars will now use ISO communication for AC. The downside is that
there are cars that cannot be charged at all, because they allow only DC
to be used when 5% signaling is enabled. (They violate the ISO 15118-3,
but many car implementations do it that way.)
With this setting, EVerest may switch back to nominal PWM from 5% in
accordance with the ISO 15118-3 regulations. Some EVs may cancel ISO
communication in this case, even though the standard clearly states
differently.
For those EVs, you can set the *ac_enforce_hlc* option to “true”. Then,
the 5% PWM will be used throughout the complete charging session as it
is done for DC. This is not allowed according to the standard though.
For completeness, well also add a
:ref:`PersistentStore <everest_modules_PersistentStore>`
module to the *kvs/persistent_store* requirement of the
:ref:`EvseManager <everest_modules_EvseManager>`.
This is needed to persistently store charging session information e.g-
for German Eichrecht requirements. It may not be needed in simple
configurations.
.. figure:: images/persistent-store-connection.png
:alt: Persistent Store Connection
:width: 700px
For AC, we are complete now.
.. _dc-charging-port:
DC charging port
------------------
Let's build a DC charging port using the phyVERSO board. Start with the
:ref:`EvseManager <everest_modules_EvseManager>` again and adjust
one setting to switch it to DC mode:
.. figure:: images/switch-to-dc-mode.png
:alt: Switch to DC Mode
:width: 320px
The basic configuration looks similar to the AC one. We just exchanged
the :ref:`YetiDriver <everest_modules_YetiDriver>` with the
:ref:`PhyVersoBSP <everest_modules_PhyVersoBSP>` driver and connected the
*connector_1* interface for *evse_board_support* to EvseManager. Note
that *connector_lock* and *ac_rcd* are no longer needed on DC.
The second port of the phyVERSO will not be used here but could be
connected to a second EvseManager. Check the configuration options and
especially verify serial port, baud rate, capabilities and reset GPIO.
They should be correct on the default phyVERSO Board.
.. figure:: images/dc-basic-connection.png
:alt: Basic DC Connection
:width: 700px
The power meter has been replaced by a
:ref:`LEM driver <everest_modules_LemDCBM400600>` , which is a power
meter often used for public DC charging. It is connected via ethernet,
so no SerialCommHub is needed. Verify the correct target IP is set.
Then, we will need to add the additional hardware drivers required for
DC charging:
.. figure:: images/dc-additional-hardware-drivers.png
:alt: Additional DC Hardware Drivers
:width: 750px
For the DC power supply, a
:ref:`Huawei driver <everest_modules_Huawei_R100040Gx>` was added here
to the *power_supply_DC* requirement of EvseManager. Set the correct CAN
device. As isolation monitor, the
:ref:`Bender isoCHA driver <everest_modules_Bender_isoCHA425HV>` was added.
As it is a modbus device, it requires a SerialCommHub again - the same way
as the GenericPowermeter in the AC configuration. Make sure the settings
for the serial port are correct.
Both of the AC and DC example configs will not yet charge a car. They
still need two things from the other subsystems:
- Energy from the energy management system
- Authorization from the Auth subsystem. If you don't need any
Authorization, you can also disable this requirement by setting
“disable_authentication: true” for EvseManager.
Authentication subsystem
========================
Let's add a simple authentication subsystem to the charging part we just
created. Start by adding the :ref:`Auth module <everest_modules_Auth>` .
It is the central logic core of this subsystem and manages all incoming
tokens, validations and reservations. Connect it to the *evse/evse_manager*
implementation on EvseManager. Through this interface, it will authorize
the charging sessions. If you have multiple charging ports (multiple EvseManagers)
you can connect all of them to the same Auth module. The Auth module
will then manage multiple ports.
.. figure:: images/multiple-connections.png
:alt: Authentication Subsystem
:width: 750px
To do anything useful, the Auth module requires two things:
1. :doc:`Auth token providers </reference/interfaces/auth_token_provider>`:
They are sources of auth tokens, e.g. RFID readers etc that output tokens
(but do not know whether they are valid or not).
2. :doc:`Auth token validators </reference/interfaces/auth_token_validator>`:
They can tell whether a token is valid or not.
Move the *token_provider* requirement to the right. The first auth token
provider that we will connect is the *auth_token_provider*
implementation of the EvseManager. This is needed for features such as
“Plug and Charge” and “Autocharge”, where the EV is used as a token to
authenticate the charging session.
----
.. figure:: images/add-pnc-autocharge.png
:alt: Add Plug-and-Charge and Autocharge Feature
:width: 350px
----
Next, we can connect an RFID reader as a second auth token provider:
----
.. figure:: images/add-rfid-reader.png
:alt: Add RFID Reader
:width: 380px
--------------
Now, let's add a very simple token validator:
--------------
.. figure:: images/add-token-validator.png
:alt: Add Token Validator
:width: 500px
--------------
The :ref:`LocalAllowlistTokenValidator <everest_modules_LocalAllowlistTokenValidator>`
module takes a simple ASCII file (see config) with one line per token.
All tokens listed in this file are considered valid, all others are invalid.
With this Auth system, we already have a very simple version that can be
used to authenticate RFID tokens, that have been previously added to the
local whitelist file.
OCPP sub-system
==================
Especially for public charging stations, authentication is done via a
cloud backend instead of a simple local whitelist. For this, we use OCPP
1.6 in this example. OCPP 2.0.1 can be used in a similar way by using
the OCPP201 module instead.
OCPP is both a token provider and a token validator.
It provides tokens when a *RemoteStart* /
*RequestStartTransactionRequest* command is issued, and it is used as a
token validator if e.g. an RFID or Plug&Charge contract should be
validated in the CSMS. So we will connect both of those connections and
remove the LocalWhiteListTokenValidator. OCPP has its own internal local whitelist
and authorization cache implementation, that is according to the standard:
.. figure:: images/remove-whitelist.png
:alt: Remove Whitelist
:width: 650px
OCPP requires several connections. Let's go through them step by step:
- :doc:`Auth token providers </reference/interfaces/auth_token_provider>`
and :doc:`Auth token validators </reference/interfaces/auth_token_validator>`
are the main ones for remote start and token validation functionality.
Connect them to the Auth module.
- :doc:`auth interface </reference/interfaces/auth>` needs to be connected to
the *Auth* module. This connection is mostly used to set the connection
timeout setting via the OCPP protocol.
- :doc:`reservation interface </reference/interfaces/reservation>` is used to
reserve/cancel reservations of connectors via OCPP from the CSMS.
- OCPP also requires a connection to the
:ref:`EvseSecurity <everest_modules_EvseSecurity>` module, which
is now shared between OCPP and EvseV2G. OCPP requires it to load the
certificate / keys for TLS to the CSMS. OCPP can also update/install
certificates for both OCPP and ISO 15118 from the CSMS.
- OCPP requires a helper module for system-specific implementations
(OTA update, logfile collection and upload). Here, we use
:ref:`Linux_Systemd_Rauc <everest_modules_Linux_Systemd_Rauc>`
from EVerest, which is the default implementation using systemd for
log collection and RAUC for OTA updates. This in turn requires a
:ref:`PersistentStore <everest_modules_PersistentStore>` module,
which is shared here with the EvseManager.
For more detailed information about the OCPP configuration, check out the
following resources:
- :ref:`OCPP1.6 module documentation <everest_modules_OCPP>`
- :ref:`OCPP2.0.1 module documentation <everest_modules_OCPP201>`
- :doc:`OCPP1.6 tutorial </tutorials/ocpp16>`
- :doc:`OCPP2.0.1 tutorial </tutorials/ocpp2>`
Now, we have a configuration that can be used in public environments. It
supports authentication via OCPP for RFID tags, and - since the LEM
power supply is used on the DC port - German Eichrecht compliant
metering with OCMF-signed meter values forwarding to the cloud.
Energy management subsystem
====================================
The last subsystem missing is the Energy management. In EVerest, the
energy management distributes energy between charging ports. It is also
needed if only one charging port exists.
Please refer to the
:doc:`Energy Management documentation </explanation/energymanagement/index>`
for a detailed explanation of how to set up the energy management
subsystem.
Multiple connectors
===================
In order to support multiple charging ports, the charging subsystem will
need to be loaded multiple times (also duplicating all direct
dependencies), but Auth and Energy management subsystems are used only
once.
Here is an example for two charging ports (leaving out the dependencies
of each functional block / most connections for clarity):
.. figure:: images/multiple-connectors.png
:alt: Multiple Connectors
:width: 750px
Most drivers implement only a single instance. So e.g. drivers for
isolation monitors, SLAC, ISO protocol etc all need to be duplicated
when EvseManager is duplicated.
A few driver modules also have two implementations of one interface. A
good example is the PhyVersoBSP, which is the driver for a dual port
controller in one module - so it supplies two separate CP pins etc to
two EvseManagers (again removing most other modules for clarity):
.. figure:: images/phyverso-bsp.png
:alt: phyVERSO BSP
:width: 600px
----
**Authors**: Cornelius Claussen, Piet Gömpel