- 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
744 lines
26 KiB
ReStructuredText
744 lines
26 KiB
ReStructuredText
.. _exp-energymanagement:
|
|
|
|
############################
|
|
Energy Management in EVerest
|
|
############################
|
|
|
|
|
|
This section provides an in-depth explanation of the energy management concept
|
|
implemented in EVerest.
|
|
It covers the representation of energy systems as energy trees, the handling of
|
|
energy requests and distribution, and the configuration of energy trees within
|
|
EVerest. The central modules involved in this concept are the
|
|
:ref:`EnergyManager <everest_modules_EnergyManager>` and
|
|
:ref:`EnergyNode <everest_modules_EnergyNode>` modules.
|
|
|
|
One of its central ideas of EVerest's energymanagement to represent the energy
|
|
system for which power is distributed as an energy tree containing energy nodes.
|
|
This enables the representation of arbitrarily complex configurations of
|
|
physical and logical components within the targeted energy system.
|
|
|
|
The following sections present this concept in more detail.
|
|
|
|
Energy nodes
|
|
------------
|
|
|
|
An energy node can be either a logical or physical component within the energy
|
|
system.
|
|
|
|
Energy nodes can typically be classified into the following categories:
|
|
|
|
* **Physical Components**: Circuit breakers, electrical fuses
|
|
* **Logical Components**: Limits from OCPP, EEBus, or other external sources
|
|
* **Charging Stations**: Unidirectional or bidirectional charging stations
|
|
(or in general any sink or source of power)
|
|
|
|
An EVerest module becomes an energy node by implementing the
|
|
:doc:`energy </reference/interfaces/energy>` interface.
|
|
|
|
.. note::
|
|
|
|
At the time of writing, two EVerest modules are considered energy nodes as
|
|
per the above definition: **EnergyNode** and **EvseManager**.
|
|
More may be added in the future.
|
|
The **EnergyNode** module fulfills central aspects of the energy management
|
|
concept.
|
|
When the term **EnergyNode** is used, it refers to the actual module,
|
|
whereas **energy node** refers to the general definition above.
|
|
|
|
The **EnergyNode** module both requires and provides the
|
|
:doc:`energy </reference/interfaces/energy>` interface.
|
|
This design enables the representation of arbitrary energy tree configurations
|
|
within the EVerest configuration file as explained in detail in a later
|
|
section.
|
|
|
|
Energy trees
|
|
------------
|
|
|
|
Energy trees are used to model various energy system configurations.
|
|
Below are examples demonstrating how energy systems can be represented in
|
|
EVerest.
|
|
|
|
The simplest energy tree consists of a single leaf node representing an EVSE
|
|
with a physical hardware capability of 32 A on 3 phases.
|
|
|
|
.. image:: images/single_node.drawio.svg
|
|
:name: single-node-label
|
|
:align: center
|
|
|
|
Typically, the electrical connection of charging stations is protected by a
|
|
circuit breaker.
|
|
Adding this to the representation results in:
|
|
|
|
.. image:: images/single_node_with_circuit_breaker.drawio.svg
|
|
:name: single-node-with-circuit-breaker-label
|
|
:align: center
|
|
|
|
In this example, the circuit breaker limits the current to 16 A, even though
|
|
the EVSE supports 32 A.
|
|
The module managing power distribution must enforce this limitation.
|
|
|
|
For a more complex setup, consider the following example:
|
|
|
|
.. image:: images/energy_tree.drawio.svg
|
|
:name: energy-tree-label
|
|
:align: center
|
|
|
|
Here, a top-level circuit breaker limits the line to 63 A.
|
|
Two additional circuit breakers protect the lines to two EVSEs, each fused at
|
|
32 A.
|
|
EVSE1 can consume 16 A on three phases, while EVSE2 can consume 32 A on three
|
|
phases.
|
|
This module accounts for all existing limitations when distributing power to
|
|
energy nodes.
|
|
|
|
All the scenarios above can be represented within EVerest.
|
|
The power distribution to the EVSEs is managed by this module, considering the
|
|
limitations of each individual node.
|
|
How these setups above can be represented in EVerest is presented in section
|
|
:ref:`'Configuration of energy trees in EVerest' <configuration_of_energy_trees_in_everest>`.
|
|
|
|
Energy requests and distribution
|
|
--------------------------------
|
|
|
|
The EnergyManager module requires exactly one module implementing the
|
|
:doc:`energy </reference/interfaces/energy>` interface.
|
|
This interface defines:
|
|
|
|
* A single variable **energy_flow_request** of type **EnergyFlowRequest**
|
|
* A single command **enforce_limits**
|
|
|
|
The concept of the usage of this interface is further described in the
|
|
following sections.
|
|
|
|
Energy flow request variable
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
The **EnergyFlowRequest** type is recursive, containing a list of child
|
|
**EnergyFlowRequest**.
|
|
It defines the power and current requested by an energy node, along with its
|
|
limitations (e.g., hardware or software constraints).
|
|
In essence, a module specifies its requirements and limitations through this
|
|
type, which are then communicated to its parent node.
|
|
The parent node creates an aggregated **EnergyFlowRequest**, incorporating its
|
|
own limitations and the requests from its children.
|
|
|
|
Energy flow requests are constructed from the leaves to the root of the energy
|
|
tree, resulting in a single **EnergyFlowRequest** that contains all child
|
|
requests.
|
|
This final request serves as input for this module, which calculates the limits
|
|
to enforce down the tree.
|
|
|
|
The following diagram illustrates how energy nodes communicate requests, with
|
|
green arrows representing energy flow requests:
|
|
|
|
.. image:: images/energy_tree_request_and_distribution.drawio.svg
|
|
:name: energy-tree-request-and-distribution-label
|
|
:align: center
|
|
|
|
Enforcing limits
|
|
^^^^^^^^^^^^^^^^
|
|
|
|
The **enforce_limits** command propagates limits down the tree.
|
|
Each energy node calls this function on its child nodes to enforce calculated
|
|
limits.
|
|
|
|
Note that the EnergyManager itself does not represent an energy node.
|
|
It communicates the resulting **EnergyFlowRequest** to a single connected
|
|
energy node, which then propagates the limits further down the tree.
|
|
|
|
Details of the EnergyFlowRequest type
|
|
-------------------------------------
|
|
|
|
Energy nodes may have varying types of limits.
|
|
To understand this better, consider a zoomed-in view of an energy node:
|
|
|
|
.. image:: images/zoom_in_energy_node.drawio.svg
|
|
:name: zoom-in-energy-node-label
|
|
:align: center
|
|
|
|
In reality, an energy node may have different limits for charging (import) and
|
|
discharging (export).
|
|
The **EnergyFlowRequest** type accounts for this distinction:
|
|
|
|
* **Import**: Energy flow direction from the grid to the consumer/EV (charging)
|
|
* **Export**: Energy flow direction from the EV to the grid (discharging)
|
|
|
|
Additionally, each direction may have separate limits for the root and leaf
|
|
sides of the energy node.
|
|
For example, a DC power supply may have AC limits on the root side (facing the
|
|
grid) and DC limits on the leaf side (facing the EV).
|
|
|
|
Limits may also change over time, which is why the *schedule_import* and
|
|
*schedule_export* properties are lists containing multiple limit
|
|
specifications.
|
|
|
|
Besides the limiting schedules for import and export, it also contains
|
|
a *setpoint_schedule*. This is a list (time series) just like the limiting schedules
|
|
and it may contain setpoints for each timeslot, see below for a more detailed description.
|
|
|
|
Each value that is given for a limit or schedule has a source property (string).
|
|
It is used to track which value is the actual limiting factor for the result in the
|
|
optimization algorithm.
|
|
|
|
This is useful to understand how the result that is sent to the EvseManager is composed.
|
|
|
|
Below is an example JSON representation of an **EnergyFlowRequest** for a leaf node:
|
|
|
|
.. code-block:: json
|
|
|
|
{
|
|
"children": [],
|
|
"evse_state": "Charging",
|
|
"node_type": "Evse",
|
|
"priority_request": false,
|
|
"schedule_export": [
|
|
{
|
|
"limits_to_leaves": {
|
|
"ac_max_current_A": {
|
|
"value": 10.0,
|
|
"source": "EVSE1_leave"
|
|
}
|
|
},
|
|
"limits_to_root": {
|
|
"ac_max_current_A": {
|
|
"value": 16.0,
|
|
"source": "EVSE1_root"
|
|
},
|
|
"ac_max_phase_count": {
|
|
"value": 3,
|
|
"source": "EVSE1_phase"
|
|
},
|
|
"ac_min_current_A": {
|
|
"value": 0.0,
|
|
"source": "EVSE1_mincurrent"
|
|
},
|
|
"ac_min_phase_count": {
|
|
"value": 1,
|
|
"source": "EVSE1_minphase"
|
|
},
|
|
"ac_number_of_active_phases": 3,
|
|
"ac_supports_changing_phases_during_charging": true
|
|
},
|
|
"timestamp": "2024-12-17T13:08:36.479Z"
|
|
}
|
|
],
|
|
"schedule_import": [
|
|
{
|
|
"limits_to_leaves": {
|
|
"ac_max_current_A": {
|
|
"value": 32.0,
|
|
"source": "EVSE1_leave"
|
|
}
|
|
},
|
|
"limits_to_root": {
|
|
"ac_max_current_A": {
|
|
"value": 32.0,
|
|
"source": "EVSE1_root"
|
|
},
|
|
"ac_max_phase_count": {
|
|
"value": 3,
|
|
"source": "EVSE1_phase"
|
|
},
|
|
"ac_min_current_A": {
|
|
"value": 6.0,
|
|
"source": "EVSE1_mincurrent"
|
|
},
|
|
"ac_min_phase_count": {
|
|
"value": 1,
|
|
"source": "EVSE1_minphase"
|
|
},
|
|
"ac_number_of_active_phases": 3,
|
|
"ac_supports_changing_phases_during_charging": true
|
|
},
|
|
"timestamp": "2024-12-17T13:08:36.479Z"
|
|
}
|
|
],
|
|
"schedule_setpoints": [],
|
|
"uuid": "evse1"
|
|
}
|
|
|
|
Setpoints
|
|
---------
|
|
|
|
Setpoints can optionally be specified for each time slot. Note that the schedule_setpoints list
|
|
may have different timestamp entries then the limiting schedules.
|
|
|
|
A setpoint entry may have an ampere or watt limit or specify a Watt-Grid Frequency table as setpoint.
|
|
Only one of those three options may be set in each timeslot, but they may be different for each timeslot.
|
|
|
|
The priority property is intended to be used if multiple conflicting setpoints exist in the energy tree.
|
|
This is not implemented for now, the priority property will be ignored for now.
|
|
|
|
In most cases a setpoint is not neccessary as the same functionality can also be implemented by setting the
|
|
limits at the node appropriately.
|
|
It is especially useful for the bidirectional use case, as it selects whether charging or discharging should be performed:
|
|
|
|
E.g. with watt limits of -10kW to +10kW and a setpoint of -2kW, it will discharge at 2kW.
|
|
A setpoint of +3kW will switch to charging without changing the limits.
|
|
|
|
The Frequency based watt limit table can be set through e.g. OCPP 2.1 smart charging. It is intended to
|
|
specifiy a grid stabilizing mode, in which the charger charges when the grid frequency is too high and discharges
|
|
to support the grid if the frequency is too low.
|
|
|
|
External limits
|
|
---------------
|
|
|
|
External limits can be added to the energy system using EVerest modules
|
|
implementing the
|
|
:doc:`external_energy_limits </reference/interfaces/external_energy_limits>`
|
|
interface.
|
|
At the time of writing, the **EnergyNode** module is the sole module that
|
|
provides this functionality.
|
|
|
|
The `external_energy_limits` interface defines the **set_external_limits**
|
|
command, which modules like OCPP or API can use to specify external energy
|
|
limits.
|
|
These limits are then considered by the **EnergyNode** module when creating
|
|
its energy flow request.
|
|
|
|
To apply external limits, a module must require the `external_energy_limits`
|
|
interface and invoke the **set_external_limits** command.
|
|
The next section details how to configure these limits in EVerest.
|
|
|
|
.. _configuration_of_energy_trees_in_everest:
|
|
|
|
Configuration of energy trees in EVerest
|
|
----------------------------------------
|
|
|
|
The following section describes how to configure the EVerest configuration file
|
|
in order to represent the targeted energy tree.
|
|
In order to do that we are using a complex energy tree example and implement
|
|
this in the configuration step by step.
|
|
|
|
This is the energy tree that we are going to represent in the EVerest
|
|
configuration:
|
|
|
|
.. _energy_tree_complex_label:
|
|
|
|
.. image:: images/energy_tree_complex.drawio.svg
|
|
:alt: Example of a complex energy tree
|
|
:align: center
|
|
|
|
This energy tree represents a setup with two EVSEs.
|
|
There are two external sources that are able to provide external energy limits:
|
|
OCPP and the API module.
|
|
|
|
OCPP is able to set external limits for each EVSE as well as for the whole
|
|
charging station.
|
|
This is indicated by the three arrows labeled with OCPP.
|
|
The API module is only able to set the limits for the two EVSEs, but not for
|
|
the whole charging station.
|
|
|
|
.. note::
|
|
|
|
To improve readability, unrelated module configurations and connections are
|
|
omitted in the examples below.
|
|
|
|
First, we add two EvseManager modules to the config file representing our
|
|
energy leaf nodes.
|
|
|
|
.. code-block:: yaml
|
|
|
|
active_modules:
|
|
evse_manager_1:
|
|
module: EvseManager
|
|
evse_manager_2:
|
|
module: EvseManager
|
|
|
|
The two EVSEs can receive limits from OCPP.
|
|
Therefore, we add two **EnergyNode** modules that represent the sinks for the
|
|
external limits.
|
|
The **EnergyNode** module requires a connection to a module implementing the
|
|
:doc:`energy </reference/interfaces/energy>` interface.
|
|
This is implemented by connecting the previously added EvseManager modules to it.
|
|
|
|
Any external limit applied to the added EnergyNode modules will be applied to
|
|
its energy child nodes (the EvseManager modules) now.
|
|
|
|
.. code-block:: yaml
|
|
|
|
active_modules:
|
|
evse_manager_1:
|
|
module: EvseManager
|
|
evse_manager_2:
|
|
module: EvseManager
|
|
ocpp_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_1
|
|
implementation_id: energy_grid
|
|
ocpp_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_2
|
|
implementation_id: energy_grid
|
|
|
|
We continue with adding **EnergyNode** modules that represent the sinks for the
|
|
limits received by the API module.
|
|
Note that the **EnergyNode** module provides and requires the
|
|
:doc:`energy </reference/interfaces/energy>` interface at the same time.
|
|
This allows us to connect **EnergyNode** modules and therefore fullfill the
|
|
requirement of others.
|
|
|
|
Note that the modules **ocpp_sink_1** and **ocpp_sink_2** are connected to the
|
|
**api_sink_1** and **api_sink_2**.
|
|
This means that both limits can be considered by this module without
|
|
overriding each other.
|
|
|
|
.. code-block:: yaml
|
|
|
|
active_modules:
|
|
evse_manager_1:
|
|
module: EvseManager
|
|
evse_manager_2:
|
|
module: EvseManager
|
|
ocpp_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_1
|
|
implementation_id: energy_grid
|
|
ocpp_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_2
|
|
implementation_id: energy_grid
|
|
api_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_1
|
|
implementation_id: energy_grid
|
|
api_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_2
|
|
implementation_id: energy_grid
|
|
|
|
We are now only missing a represention for the complete charging station.
|
|
Therefore, we add another **EnergyNode** module with a fuse limit of 63 A and
|
|
we name it **grid_connection_point**.
|
|
We connect **api_sink_1** and **api_sink_2** to it.
|
|
|
|
.. code-block:: yaml
|
|
|
|
active_modules:
|
|
evse_manager_1:
|
|
module: EvseManager
|
|
evse_manager_2:
|
|
module: EvseManager
|
|
ocpp_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_1
|
|
implementation_id: energy_grid
|
|
ocpp_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_2
|
|
implementation_id: energy_grid
|
|
api_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_1
|
|
implementation_id: energy_grid
|
|
api_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_2
|
|
implementation_id: energy_grid
|
|
grid_connection_point:
|
|
module: EnergyNode
|
|
config_module:
|
|
fuse_limit_A: 63
|
|
phase_count: 3
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: api_sink_1
|
|
implementation_id: energy_grid
|
|
- module_id: api_sink_2
|
|
implementation_id: energy_grid
|
|
|
|
|
|
Now we have the complete energy tree represented, but we're still missing to
|
|
include the modules that set the external energy limits, so the OCPP and API
|
|
module.
|
|
Since these modules require (optionally multiple) connections to modules
|
|
implementing the
|
|
:doc:`external_energy_limits </reference/interfaces/external_energy_limits>`
|
|
interface, we need to also add the connections to the **EnergyNode** modules we
|
|
have added previously.
|
|
Finally, we also add the **EnergyManager** module and connect the
|
|
**grid_connection_point** to it.
|
|
|
|
.. code-block:: yaml
|
|
|
|
active_modules:
|
|
evse_manager_1:
|
|
module: EvseManager
|
|
evse_manager_2:
|
|
module: EvseManager
|
|
ocpp_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_1
|
|
implementation_id: energy_grid
|
|
ocpp_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_2
|
|
implementation_id: energy_grid
|
|
api_sink_1:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_1
|
|
implementation_id: energy_grid
|
|
api_sink_2:
|
|
module: EnergyNode
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_2
|
|
implementation_id: energy_grid
|
|
grid_connection_point:
|
|
module: EnergyNode
|
|
config_module:
|
|
fuse_limit_A: 63
|
|
phase_count: 3
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: api_sink_1
|
|
implementation_id: energy_grid
|
|
- module_id: api_sink_2
|
|
implementation_id: energy_grid
|
|
ocpp:
|
|
module: OCPP
|
|
connections:
|
|
evse_energy_sink:
|
|
- module_id: grid_connection_point
|
|
implementation_id: external_limits
|
|
- module_id: ocpp_sink_1
|
|
implementation_id: external_limits
|
|
- module_id: ocpp_sink_2
|
|
implementation_id: external_limits
|
|
api:
|
|
module: API
|
|
connections:
|
|
evse_energy_sink:
|
|
- module_id: api_sink_1
|
|
implementation_id: external_limits
|
|
- module_id: api_sink_2
|
|
implementation_id: external_limits
|
|
energy_manager:
|
|
module: EnergyManager
|
|
connections:
|
|
energy_trunk:
|
|
- module_id: grid_connection_point
|
|
implementation_id: energy_grid
|
|
|
|
|
|
We have now added all the required modules and connections to represent the
|
|
energy tree example :ref:`shown above <energy_tree_complex_label>`.
|
|
One important detail is still missing, which is the module mapping.
|
|
For detailed information about the module mapping please see
|
|
:doc:`3-tier module mappings </explanation/tier-module-mappings>`.
|
|
|
|
Since the connections of a module in the EVerest config does not automatically
|
|
map to a specific EVSE (or the whole charging station, represented by EVSE#0),
|
|
the **EnergyNode** modules must have a module mapping.
|
|
This allows the modules that make use of the **set_external_limits** command to
|
|
call it for the correct node.
|
|
|
|
Modules like OCPP and API can only know at which requirement the command
|
|
**set_external_limit** shall be called in case the energy node that is
|
|
connected to it has a specified module mapping in the EVerest config.
|
|
|
|
This is a full example including the module mappings:
|
|
|
|
.. code-block:: yaml
|
|
|
|
active_modules:
|
|
evse_manager_1:
|
|
module: EvseManager
|
|
mapping:
|
|
module:
|
|
evse: 1
|
|
evse_manager_2:
|
|
module: EvseManager
|
|
mapping:
|
|
module:
|
|
evse: 2
|
|
ocpp_sink_1:
|
|
module: EnergyNode
|
|
mapping:
|
|
module:
|
|
evse: 1
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_1
|
|
implementation_id: energy_grid
|
|
ocpp_sink_2:
|
|
module: EnergyNode
|
|
mapping:
|
|
module:
|
|
evse: 2
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: evse_manager_2
|
|
implementation_id: energy_grid
|
|
api_sink_1:
|
|
module: EnergyNode
|
|
mapping:
|
|
module:
|
|
evse: 1
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_1
|
|
implementation_id: energy_grid
|
|
api_sink_2:
|
|
module: EnergyNode
|
|
mapping:
|
|
module:
|
|
evse: 2
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: ocpp_sink_2
|
|
implementation_id: energy_grid
|
|
grid_connection_point:
|
|
module: EnergyNode
|
|
mapping:
|
|
module:
|
|
evse: 0
|
|
config_module:
|
|
fuse_limit_A: 63
|
|
phase_count: 3
|
|
connections:
|
|
energy_consumer:
|
|
- module_id: api_sink_1
|
|
implementation_id: energy_grid
|
|
- module_id: api_sink_2
|
|
implementation_id: energy_grid
|
|
ocpp:
|
|
module: OCPP
|
|
connections:
|
|
evse_energy_sink:
|
|
- module_id: grid_connection_point
|
|
implementation_id: external_limits
|
|
- module_id: ocpp_sink_1
|
|
implementation_id: external_limits
|
|
- module_id: ocpp_sink_2
|
|
implementation_id: external_limits
|
|
api:
|
|
module: API
|
|
connections:
|
|
evse_energy_sink:
|
|
- module_id: api_sink_1
|
|
implementation_id: external_limits
|
|
- module_id: api_sink_2
|
|
implementation_id: external_limits
|
|
energy_manager:
|
|
module: EnergyManager
|
|
connections:
|
|
energy_trunk:
|
|
- module_id: grid_connection_point
|
|
implementation_id: energy_grid
|
|
|
|
Energy distribution
|
|
-------------------
|
|
|
|
The EnergyManager module implements an algorithm to distribute available power
|
|
to energy leaf nodes:
|
|
|
|
* It calculates and enforces limits for each energy leaf node in the tree.
|
|
* It ensures that no node exceeds its specified limits for current, power, or
|
|
phase count.
|
|
* It distributes power equally among child nodes, if their collective request
|
|
exceeds the parent node's limits.
|
|
* The algorithm prefers charging over discharging if the specified limits allow
|
|
for both.
|
|
* It supports phase switching between single-phase and three-phase modes,
|
|
optimizing power usage for low-demand scenarios if
|
|
**switch_3ph1ph_while_charging_mode** is enabled.
|
|
|
|
Phase switching
|
|
---------------
|
|
|
|
This module supports switching between single-phase (1ph) and three-phase (3ph)
|
|
configurations during AC charging.
|
|
|
|
.. warning::
|
|
|
|
Some vehicles (such as the first generation of Renault Zoe) may be
|
|
permanently damaged when switching from 1ph to 3ph during charging.
|
|
Use at your own risk!
|
|
|
|
To use this feature, several configurations must be enabled across different
|
|
EVerest modules:
|
|
|
|
- **EvseManager**: Adjust the following configuration options to your needs:
|
|
- ``switch_3ph1ph_delay_s``
|
|
- ``switch_3ph1ph_cp_state``
|
|
- **Module implementing the `evse_board_support </reference/interfaces/evse_board_support>` interface:**
|
|
- Set ``supports_changing_phases_during_charging`` to ``true`` in the reported capabilities.
|
|
- Define the minimum number of phases as 1 and the maximum as 3.
|
|
- Ensure the ``ac_switch_three_phases_while_charging`` command is implemented.
|
|
- **EnergyManager**: Adjust the following config options to your needs:
|
|
- switch_3ph1ph_while_charging_mode
|
|
- switch_3ph1ph_max_nr_of_switches_per_session
|
|
- switch_3ph1ph_switch_limit_stickyness
|
|
- switch_3ph1ph_power_hysteresis_W
|
|
- switch_3ph1ph_time_hysteresis_s
|
|
|
|
Refer to the manifest.yaml for documentation of these configuration options.
|
|
|
|
If all of these are properly configured, the EnergyManager will handle the
|
|
1ph/3ph switching.
|
|
To enable this, an external limit must be set.
|
|
There are two ways to configure the limit:
|
|
|
|
1. **Watt-based limit (preferred option):** The limit is set in Watts (not
|
|
Amperes), even though this involves AC charging.
|
|
This provides the EnergyManager with the flexibility to decide when to
|
|
switch.
|
|
The limit can be defined by an OCPP schedule or through an additional
|
|
EnergyNode.
|
|
2. **Ampere-based limit:** The limit is defined in Amperes, along with a
|
|
restriction on the number of phases (e.g., ``min_phase=1`` and
|
|
``max_phase=1``).
|
|
This enforces switching and allows external control over the switching time,
|
|
but the EnergyManager loses its ability to choose when to switch.
|
|
|
|
Best practices
|
|
^^^^^^^^^^^^^^
|
|
|
|
In general, this feature works best in a configuration with 32 A per phase and
|
|
a Watt-based limit.
|
|
In this setup, there is an overlap between the single phase and three phase
|
|
domain:
|
|
|
|
- Single-phase charging: 1.3 kW to 7.4 kW
|
|
- Three-phase charging: 4.2 kW to 22 kW (or 11 kW)
|
|
|
|
This avoids switching too often in the most elegant way.
|
|
Other methods to reduce the number of switch cycles can be configured in the
|
|
EnergyManager, see config options above.
|
|
|
|
Current limitations
|
|
-------------------
|
|
|
|
* The algorithm does not account for real-time power meter readings from
|
|
individual nodes.
|
|
* It does not redistribute unused power when the actual consumption is below
|
|
the assigned target value.
|