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:
210
tools/EVerest-main/docs/source/tutorials/bazel.rst
Normal file
210
tools/EVerest-main/docs/source/tutorials/bazel.rst
Normal file
@@ -0,0 +1,210 @@
|
||||
.. _tutorial_bazel:
|
||||
|
||||
==========================
|
||||
Experimental Bazel Support
|
||||
==========================
|
||||
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
EVerest offers support for `Bazel <https://bazel.build/>`.
|
||||
With Bazel, you can efficiently build, test and deploy software projects of any
|
||||
size.
|
||||
|
||||
For EVerest developers, Bazel offers a couple advantages:
|
||||
|
||||
* While developing features, that span multiple modules, Bazel can swiftly
|
||||
rebuild only the necessary parts of the project.
|
||||
* If you have already setup Bazel in your project, EVerest framework can be
|
||||
integrated with it.
|
||||
|
||||
This tutorial will guide you through the process of setting up and using
|
||||
Bazel in your EVerest projects.
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
To install Bazel, it's recommended to use bazelisk, which is a tool that
|
||||
downloads and runs the correct version of Bazel for your project.
|
||||
You can install bazelisk by following the
|
||||
`instructions on the official GitHub repository <https://github.com/bazelbuild/bazelisk?tab=readme-ov-file#installation>`.
|
||||
|
||||
.. note::
|
||||
Bazelisk provides a `bazel` command, and the rest of this tutorial will
|
||||
refer to it as `bazel`.
|
||||
|
||||
C/C++ Compilers:
|
||||
At the moment, Bazel will use the default C/C++ compilers on your system.
|
||||
If it is not the desired compiler to build EVerest, you can set the environment
|
||||
variables `CC` and `CXX` to the desired compiler.
|
||||
|
||||
All other dependencies are fetched by Bazel as needed.
|
||||
|
||||
Using Bazel Commands
|
||||
--------------------
|
||||
|
||||
Once Bazel is configured, you can use various Bazel commands to build, test
|
||||
and run.
|
||||
|
||||
Most useful commands are:
|
||||
|
||||
* `bazel build //...` - Build all targets in the project.
|
||||
* `bazel test //...` - Run all tests in the project.
|
||||
|
||||
Dependency Management
|
||||
---------------------
|
||||
|
||||
There are a few different ways of managing dependencies in EVerest.
|
||||
|
||||
* Dependencies that CMake takes from the system (e.g. boost).
|
||||
These dependencies are configured in the `third_party/bazel/repos.bzl` file.
|
||||
* Dependencies that are described in the `./dependencies.yaml` file. These
|
||||
dependencies are pulled automatically by Bazel with help of `edm` tool.
|
||||
* Rust dependencies are managed by cargo, and are described in the `Cargo.toml`
|
||||
file. Cargo dependencies are automatically picked up by Bazel.
|
||||
|
||||
Defining C++ EVerest Modules
|
||||
----------------------------
|
||||
|
||||
Let's assume, you have a module named `Example` with a single interface
|
||||
implementation named `example`. This module depends on the `sigslot` library.
|
||||
For a more realistic scenario, the module has two extra files `utils.cpp` and
|
||||
`utils.hpp`.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
modules/
|
||||
└── Example
|
||||
├── BUILD.bazel
|
||||
├── CMakeLists.txt
|
||||
├── Example.cpp
|
||||
├── Example.hpp
|
||||
├── manifest.yaml
|
||||
├── utils.cpp
|
||||
├── utils.hpp
|
||||
└── example/
|
||||
├── exampleImpl.cpp
|
||||
└── exampleImpl.hpp
|
||||
|
||||
The `manifest.yaml` file for the module looks like this:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
description: Simple example module written in C++
|
||||
provides:
|
||||
example:
|
||||
interface: example
|
||||
description: This implements an example interface that uses multiple framework features
|
||||
...
|
||||
requires:
|
||||
kvs:
|
||||
interface: kvs
|
||||
enable_external_mqtt: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Example Authors
|
||||
|
||||
To build this module with Bazel, you need to create a `BUILD.bazel` file in the
|
||||
module directory, next to the `manifest.yaml` file.
|
||||
|
||||
In the `BUILD.bazel`, use predefined macros to define the module:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
load("//modules:module.bzl", "cc_everest_module")
|
||||
|
||||
cc_everest_module(
|
||||
# Name of the module, must be the same as the directory name.
|
||||
name = "Example",
|
||||
deps = [
|
||||
# List of libraries, that module depends on.
|
||||
# In CMakeLists.txt these are typically added as `target_link_libraries`.
|
||||
# The should be listed in the `third_party/bazel/repos.bzl` file.
|
||||
# Note that header-only libraries should be added here as well.
|
||||
"@sigslot//:sigslot",
|
||||
],
|
||||
impls = [
|
||||
# List of implementations in the module.
|
||||
# This should correspond to the list of keys in the
|
||||
# `provides` section of the manifest.yaml file.
|
||||
"example",
|
||||
],
|
||||
# List of additional source files of the module.
|
||||
#
|
||||
# Here you only have to list the files that are not autogenerated.
|
||||
# The mandatory module files are added automatically.
|
||||
srcs = [
|
||||
"utils.cpp",
|
||||
"utils.hpp",
|
||||
],
|
||||
# Alternatively, you can use `glob` function to list files.
|
||||
# srcs = glob(
|
||||
# [
|
||||
# "*.cpp",
|
||||
# "*.hpp",
|
||||
# ],
|
||||
# ),
|
||||
)
|
||||
|
||||
|
||||
Defining Rust EVerest Modules
|
||||
-----------------------------
|
||||
|
||||
To define a Rust module in EVerest, you need to create a BUILD.bazel file in
|
||||
the module directory.
|
||||
Generic `rust_binary` and `rust_test` are used at the moment.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_test")
|
||||
load("@everest_core_crate_index//:defs.bzl", "all_crate_deps")
|
||||
load("@rules_rust//cargo:defs.bzl", "cargo_build_script")
|
||||
|
||||
# cargo_build_script describes to Bazel how to run autogeneration of the code.
|
||||
# This should be pretty-much the same for every module
|
||||
cargo_build_script(
|
||||
name = "build_script",
|
||||
srcs = ["build.rs"],
|
||||
edition="2021",
|
||||
build_script_env = {
|
||||
# This is the path relative to the module directory.
|
||||
"EVEREST_CORE_ROOT": "../..",
|
||||
},
|
||||
data = [
|
||||
"manifest.yaml",
|
||||
"@everest-core//interfaces",
|
||||
"@everest-core//types",
|
||||
],
|
||||
deps = all_crate_deps(build = True),
|
||||
)
|
||||
|
||||
# The module is described as a rust_binary at the moment.
|
||||
rust_binary(
|
||||
# Name of the module, must be the same as the directory name.
|
||||
name = "RsIskraMeterBinary",
|
||||
# List of source files of the module.
|
||||
# In most cases this glob should be enough.
|
||||
srcs = glob(["src/*.rs"]),
|
||||
# Rust language edition, used in this module.
|
||||
edition="2021",
|
||||
# Bazel makes distinctions between dependencies needed on different
|
||||
# stages of the build. This is the list of proc_macro dependencies.
|
||||
# In most cases this is enough
|
||||
proc_macro_deps = all_crate_deps(proc_macro = True),
|
||||
visibility = ["//visibility:public"],
|
||||
# List of "normal" dependencies.
|
||||
# all_crate_deps will add all the dependencies from the Cargo.toml file.
|
||||
# We need as well to add framework, bridge, and the result of the build_script.
|
||||
# Typically this is enough.
|
||||
deps = all_crate_deps(normal = True) + [
|
||||
":build_script",
|
||||
"//lib/everest/framework/everestrs/everestrs:everestrs_sys",
|
||||
"//lib/everest/framework/everestrs/everestrs:everestrs_bridge",
|
||||
],
|
||||
)
|
||||
|
||||
----
|
||||
|
||||
**Authors**: Evgeny Petrov
|
||||
609
tools/EVerest-main/docs/source/tutorials/develop-new-module.rst
Normal file
609
tools/EVerest-main/docs/source/tutorials/develop-new-module.rst
Normal file
@@ -0,0 +1,609 @@
|
||||
.. _tutorial_develop_new_everest_module:
|
||||
|
||||
Develop New Modules
|
||||
*******************
|
||||
|
||||
.. hint::
|
||||
|
||||
The module concept will be improved in the next couple of months with
|
||||
new or changed features. We will reflect those changes in the documentation,
|
||||
but be aware that there might be some fragments that still show some "old
|
||||
style". We would be happy if you drop us a line via the
|
||||
`EVerest mailing list <https://lists.lfenergy.org/g/everest>`_ in this case.
|
||||
|
||||
This tutorial is meant to show how to develop your own module for the EVerest
|
||||
framework. This tutorial builds on knowledge that is explained in the
|
||||
:ref:`Quick Start Guide <htg_getting_started_sw>`, which is a good starting
|
||||
point for understanding the central concepts of modules.
|
||||
|
||||
Goal Of This Tutorial
|
||||
=====================
|
||||
|
||||
In this tutorial, we will keep everything as simple as possible. You will
|
||||
learn the following:
|
||||
|
||||
1. Create an EVerest module that implements an interface.
|
||||
2. Define an interface containing a simple command with parameter and return
|
||||
value.
|
||||
3. Define a configuration parameter for the new module.
|
||||
4. Configure required dependencies of the EVerest framework and modules.
|
||||
5. Build and run.
|
||||
|
||||
Install Prerequisites
|
||||
=====================
|
||||
|
||||
Please follow the :ref:`Quick Start Guide <htg_getting_started_sw>` to install
|
||||
all prerequisites into your environment.
|
||||
|
||||
After that, you should in particular have:
|
||||
|
||||
- *optional:* The EVerest dependency manager (check via ``edm --version``)
|
||||
- The EVerest cli utility (check via ``ev-cli --version``)
|
||||
- A running MQTT broker (e.g. started as container as described in the setup
|
||||
guide; per default expected on localhost on port 1883)
|
||||
|
||||
Workspace Setup
|
||||
===============
|
||||
|
||||
This section describes how to setup an EVerest workspace (or at least the
|
||||
necessary parts of it) to develop EVerest modules.
|
||||
|
||||
First, create a directory for your workspace. In the following, we will assume
|
||||
the environment variable ``EVEREST_WORKSPACE`` to hold this directory::
|
||||
|
||||
export EVEREST_WORKSPACE=~/ev-workspace
|
||||
mkdir -p $EVEREST_WORKSPACE
|
||||
|
||||
|
||||
Now you have two options:
|
||||
|
||||
Alternative 1: Clone required repositories (recommended for recent versions)
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Just clone this, to get the required dependencies::
|
||||
|
||||
git clone https://github.com/EVerest/everest-cmake.git ${EVEREST_WORKSPACE}/everest-cmake
|
||||
git clone https://github.com/EVerest/EVerest.git ${EVEREST_WORKSPACE}/EVerest
|
||||
|
||||
Alternative 2: Setup Workspace via EVerest Dependency Manager (recommended for pre-2026 version)
|
||||
------------------------------------------------------------------------------------------------
|
||||
|
||||
Use the EVerest dependency manager to setup your workspace. This has the
|
||||
benefit of allowing your to select a specific snapshot (see the corresponding
|
||||
:ref:`docs <exp_dev_tools_edm>` for details), as well as it is a single command::
|
||||
|
||||
edm init --workspace $EVEREST_WORKSPACE
|
||||
cd $EVEREST_WORKSPACE
|
||||
|
||||
As of 2026 the EVerest dependency manager layouts the workspace to be compatible with
|
||||
older non-mono-repository versions of EVerest (or, as formerly called, `everest-core`). Assuming you want to build a recent
|
||||
version of everest, you can delete the dependencies which are part of the mono-repo today.
|
||||
|
||||
**Remove everything except** ``EVerest/`` **and** ``everest-cmake/`` **.**
|
||||
|
||||
The result should look like::
|
||||
|
||||
$ ls
|
||||
EVerest everest-cmake
|
||||
|
||||
|
||||
Create Module Skeleton
|
||||
======================
|
||||
|
||||
The following describes how to define the fundamental skeleton of a module.
|
||||
This includes configuration files and the auto-generation of source files.
|
||||
|
||||
First, create an empty folder that is to contain your module. In the
|
||||
following, we assume the environment variable ``EVEREST_TUTORIAL_DIR`` to hold
|
||||
this directory, for example::
|
||||
|
||||
export EVEREST_TUTORIAL_DIR=~/everest-tutorial-module
|
||||
git clone https://github.com/EVerest/everest-template.git $EVEREST_TUTORIAL_DIR
|
||||
|
||||
This provides you in particular with the ``.clang-format`` and ``.eslintrc.json``
|
||||
files.
|
||||
|
||||
.. note::
|
||||
|
||||
You may want to change the origin remote in this git repository if you are
|
||||
going to use it further on. See suitable Git documentation how to do that.
|
||||
You might also want to check that you do not take the Git history of the
|
||||
`everest-template` repository with you.
|
||||
|
||||
|
||||
Interface Configuration
|
||||
-----------------------
|
||||
|
||||
First, we define an interface that the module provides.
|
||||
In this very first minimal version, the interface shall provide a single
|
||||
command `command_tutorial` that can be called by another module and will
|
||||
just always return the string "everest" as result. We will later give some
|
||||
ideas how to extend this minimal example.
|
||||
|
||||
We store the following interface configuration in form of a .yaml file in
|
||||
``$EVEREST_TUTORIAL_DIR/interfaces/interface_tutorial_module.yaml``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
description: The interface of the tutorial module.
|
||||
cmds:
|
||||
command_tutorial:
|
||||
description: A command the tutorial module's interface provides. It receives a simple string.
|
||||
arguments:
|
||||
payload:
|
||||
description: An arbitrary string that can be sent to the module.
|
||||
type: string
|
||||
result:
|
||||
description: The answer of the module (which per default will just be "everest").
|
||||
type: string
|
||||
|
||||
Second, we use the ``ev-cli`` tool to auto-generate header files for this
|
||||
interface::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR && ev-cli interface generate-headers --everest-dir . --schemas-dir $EVEREST_WORKSPACE/EVerest/lib/everest/framework/schemas interface_tutorial_module
|
||||
|
||||
|
||||
After this, you should find the following file tree structure in your module::
|
||||
|
||||
.
|
||||
├── build
|
||||
│ └── generated
|
||||
│ └── include
|
||||
│ └── generated
|
||||
│ └── interfaces
|
||||
│ └── interface_tutorial_module
|
||||
│ ├── Implementation.hpp
|
||||
│ ├── Interface.hpp
|
||||
│ └── Types.hpp
|
||||
└── interfaces
|
||||
└── interface_tutorial_module.yaml
|
||||
|
||||
|
||||
These auto-generated header files in particular provide you with static type
|
||||
checks when developing against your individual interface.
|
||||
|
||||
.. hint::
|
||||
It is also possible to work with Python or Rust. At this point
|
||||
we will focus on C++.
|
||||
|
||||
|
||||
Module Configuration
|
||||
--------------------
|
||||
|
||||
Next, we will define our module's manifest.
|
||||
|
||||
For this, we create a module directory::
|
||||
|
||||
mkdir -p $EVEREST_TUTORIAL_DIR/modules/TutorialModule
|
||||
|
||||
and in it, create file
|
||||
``$EVEREST_TUTORIAL_DIR/modules/TutorialModule/manifest.yaml`` with the
|
||||
following content:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
description: The EVerest Tutorial Module
|
||||
config:
|
||||
config_tutorial_switch:
|
||||
description: A boolean configuration parameter.
|
||||
type: boolean
|
||||
default: false
|
||||
provides:
|
||||
interface_impl_tutorial_module:
|
||||
interface: interface_tutorial_module
|
||||
description: An actual implementation in your module of "interface_tutorial_module" interface.
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- <Your Name>, <Your Organization>
|
||||
|
||||
|
||||
In particular, this manifest declares the following:
|
||||
|
||||
- A boolean configuration parameter `config_tutorial_switch` of the module we
|
||||
can define later at runtime.
|
||||
- The module will implement the `interface_tutorial_module` interface (that
|
||||
we have defined before). We give this implementation the name `interface_impl_tutorial_module`.
|
||||
|
||||
|
||||
Again, we use the EVerest cli tool to auto-generate code from this
|
||||
configuration::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR && ev-cli module create --everest-dir . --schemas-dir $EVEREST_WORKSPACE/EVerest/lib/everest/framework/schemas TutorialModule --licenses $EVEREST_WORKSPACE/EVerest/applications/utils/ev-dev-tools/src/ev_cli/licenses
|
||||
|
||||
|
||||
After that, you should have the following file structure::
|
||||
|
||||
.
|
||||
├── build
|
||||
│ └── generated
|
||||
│ (...)
|
||||
├── config
|
||||
├── interfaces
|
||||
│ └── interface_tutorial_module.yaml
|
||||
└── modules
|
||||
└── TutorialModule
|
||||
├── CMakeLists.txt
|
||||
├── TutorialModule.cpp
|
||||
├── TutorialModule.hpp
|
||||
├── doc.rst
|
||||
├── docs
|
||||
│ └── index.rst
|
||||
├── interface_impl_tutorial_module
|
||||
│ ├── interface_tutorial_moduleImpl.cpp
|
||||
│ └── interface_tutorial_moduleImpl.hpp
|
||||
└── manifest.yaml
|
||||
|
||||
|
||||
Let us point out a few particularly important files:
|
||||
|
||||
**TutorialModule{.hpp,.cpp}:**
|
||||
|
||||
This provides the module's callbacks called by the EVerest framework at
|
||||
startup, more precisely in initialization and system-ready state. Here,
|
||||
the auto-generated implementation already calls the respective callbacks of
|
||||
its interface implementations.
|
||||
|
||||
Among others, you'll furthermore find the module's configuration and a pointer
|
||||
to the interface implementations.
|
||||
|
||||
**interface_impl_tutorial_module/interface_tutorial_moduleImpl{.hpp,.cpp}:**
|
||||
For each interface implementation (here, only a single one is defined), the
|
||||
respective header and source files are generated.
|
||||
|
||||
The header file declares particular spots for non-auto-generated code.
|
||||
|
||||
Observe that the default implementation of the handler of the
|
||||
`command_tutorial` coincidentally already satisfies this tutorial's needs:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
std::string interface_tutorial_moduleImpl::handle_command_tutorial(std::string& payload) {
|
||||
// your code for cmd command_tutorial goes here
|
||||
return "everest";
|
||||
}
|
||||
|
||||
|
||||
Build Configuration & Build
|
||||
===========================
|
||||
|
||||
This section describes the additional steps needed to build your project and
|
||||
install it.
|
||||
|
||||
Adding CMakeLists.txt in the root directory
|
||||
-------------------------------------------
|
||||
The ``$EVEREST_TUTORIAL_DIR/CMakeLists.txt`` file in the root of your project
|
||||
repository will need to import some build commands from the framework, as well
|
||||
as link to its dependencies. A fairly simple file that includes
|
||||
``everest-core`` into the build would look as follows::
|
||||
|
||||
cmake_minimum_required(VERSION 3.14.7)
|
||||
project(everest-tutorial VERSION 0.1
|
||||
DESCRIPTION "EVerest tutorial modules"
|
||||
LANGUAGES CXX C)
|
||||
find_package(everest-cmake 0.1 REQUIRED
|
||||
COMPONENTS bundling
|
||||
PATHS ../everest-cmake
|
||||
)
|
||||
# options
|
||||
option(BUILD_TESTING "Run unit tests" OFF)
|
||||
option(CMAKE_RUN_CLANG_TIDY "Run clang-tidy" OFF)
|
||||
# dependencies
|
||||
if (NOT DISABLE_EDM)
|
||||
evc_setup_edm()
|
||||
else()
|
||||
find_package(everest-core)
|
||||
# InfyPowerACDC uses pal-sigslot
|
||||
find_package(PalSigslot REQUIRED)
|
||||
endif()
|
||||
ev_add_project()
|
||||
|
||||
# config (not needed if you do not need a run script for your configuration)
|
||||
# add_subdirectory(config)
|
||||
|
||||
# configure clang-tidy if requested
|
||||
if(CMAKE_RUN_CLANG_TIDY)
|
||||
message("Enabling clang-tidy")
|
||||
set(CMAKE_CXX_CLANG_TIDY clang-tidy)
|
||||
endif()
|
||||
# testing
|
||||
if(BUILD_TESTING)
|
||||
include(CTest)
|
||||
set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type" FORCE)
|
||||
evc_include(CodeCoverage)
|
||||
append_coverage_compiler_flags()
|
||||
add_subdirectory(tests)
|
||||
setup_target_for_coverage_gcovr_html(
|
||||
NAME gcovr_coverage
|
||||
EXECUTABLE test_config
|
||||
DEPENDENCIES test_config everest
|
||||
)
|
||||
setup_target_for_coverage_lcov(
|
||||
NAME lcov_coverage
|
||||
EXECUTABLE test_config
|
||||
DEPENDENCIES test_config everest
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
Adding ``modules/CMakeLists.txt``
|
||||
---------------------------------
|
||||
|
||||
Next, ``$EVEREST_TUTORIAL_DIR/modules/CMakeLists.txt`` essentially tells CMake
|
||||
where to look for modules, in order to add them to the build.
|
||||
|
||||
It contains a single line per module. To proceed, create the file and then add the following line, as per our example::
|
||||
|
||||
ev_add_module(TutorialModule)
|
||||
|
||||
|
||||
Note that you could also develop several modules at once in your repository.
|
||||
In that case you would add a respective ``ev_add_module(<MODULE_NAME>)`` line
|
||||
for each of those.
|
||||
|
||||
|
||||
Adding ``dependencies.yaml``
|
||||
----------------------------
|
||||
|
||||
The ``find-package()`` CMake directive found in the previous sections is
|
||||
handled by EDM.
|
||||
|
||||
In order for this to work, you need to add a dependency file for EDM, called
|
||||
``dependencies.yaml``, in the project root directory. For example, listing
|
||||
only ``EVerest`` as a dependency looks like this::
|
||||
|
||||
---
|
||||
EVerest:
|
||||
git: https://github.com/EVerest/EVerest.git
|
||||
git_tag: main
|
||||
|
||||
With the above setup taken care of, you are now ready to build the project.
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
When you auto-generated the code for the interfaces and modules, a ``build/``
|
||||
directory should have appeared.
|
||||
|
||||
You can also build the project there - go to it, and configure the build::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR/build
|
||||
CMAKE_PREFIX_PATH=$EVEREST_WORKSPACE cmake --install-prefix $EVEREST_TUTORIAL_DIR/dist ..
|
||||
|
||||
Here, we added two instructions to cmake:
|
||||
|
||||
- Setting ``CMAKE_PREFIX_PATH=$EVEREST_WORKSPACE`` allows cmake to find the
|
||||
``everest-cmake`` repository in the workspace.
|
||||
- Specifying the ``--install-prefix`` allows you to specify where the finished
|
||||
binaries will be placed, e.g. into the ``dist/`` folder in the modules repository.
|
||||
EVerest can be installed system wide (e.g. into ``users/local/bin``), but this
|
||||
usually requires ``sudo`` permissions.
|
||||
|
||||
|
||||
Then, build and install the project::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR/build
|
||||
make -j <number of parallel jobs>
|
||||
|
||||
And finally, install the binaries::
|
||||
|
||||
make install -j <number of parallel jobs>
|
||||
|
||||
|
||||
If everything worked smoothly so far, your modules are installed and ready to
|
||||
run.
|
||||
|
||||
Run Configuration & Run
|
||||
=======================
|
||||
|
||||
EVerest configuration
|
||||
---------------------
|
||||
|
||||
The final step to run EVerest and testing the new module is to define an
|
||||
EVerest run configuration. For this, create a file
|
||||
``$EVEREST_TUTORIAL_DIR/config/config-modules-tutorial.yaml`` with the following
|
||||
content:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
active_modules:
|
||||
tutorial_module_instance:
|
||||
module: TutorialModule
|
||||
|
||||
This provides a very minimalistic run configuration for EVerest telling to run
|
||||
with a single module, namely the newly created one.
|
||||
|
||||
|
||||
Adding and activating ``config/CMakeLists.txt``
|
||||
-----------------------------------------------
|
||||
|
||||
The EVerest cmake utils provide a function to auto-generate run scripts for
|
||||
your configurations.
|
||||
|
||||
In order to achieve this, create the file ``$EVEREST_TUTORIAL_DIR/config/CMakeLists.txt`` with content::
|
||||
|
||||
generate_config_run_script(CONFIG modules-tutorial)
|
||||
|
||||
|
||||
Here, the ``generate_config_run_script(<CONFIG_NAME>)`` expects the existence of
|
||||
a file ``config-<CONFIG_NAME>.yaml``.
|
||||
|
||||
It will then generate a run script for this configuration.
|
||||
|
||||
You must then "activate" this configuraton by adapting the
|
||||
``$EVEREST_TUTORIAL_DIR/CMakeLists.txt`` file removing the commenting ``#``
|
||||
before the ``add_subdirectory(config)`` instruction, i.e.::
|
||||
|
||||
# config
|
||||
# (not needed if you do not need a run script for your configuration)
|
||||
add_subdirectory(config)
|
||||
|
||||
After that, once more run cmake::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR/build
|
||||
CMAKE_PREFIX_PATH=$EVEREST_WORKSPACE cmake --install-prefix $EVEREST_TUTORIAL_DIR/dist ..
|
||||
make
|
||||
make install
|
||||
|
||||
|
||||
Running EVerest
|
||||
---------------
|
||||
|
||||
The step before should have created a file
|
||||
``$EVEREST_TUTORIAL_DIR/build/run-scripts/run-modules-tutorial.sh``.
|
||||
|
||||
Up to path substitution this will have the following content::
|
||||
|
||||
LD_LIBRARY_PATH=$EVEREST_TUTORIAL_DIR/dist/lib:$LD_LIBRARY_PATH \
|
||||
PATH=$EVEREST_TUTORIAL_DIR/dist/bin:$PATH \
|
||||
manager \
|
||||
--prefix $EVEREST_TUTORIAL_DIR/dist \
|
||||
--conf $EVEREST_TUTORIAL_DIR/config/config-modules-tutorial.yaml
|
||||
|
||||
It puts the compiled libraries and binaries into the respective paths, and
|
||||
then runs EVerest by calling the `manager` binary with the respective
|
||||
configuration.
|
||||
|
||||
Importantly, the configuration must not be known before runtime (since also in
|
||||
our example it was only used to generate the run script, not to build the
|
||||
project!).
|
||||
|
||||
Executing ``run-modules-tutorial.sh`` then should start EVerest, and provide
|
||||
an output similar to::
|
||||
|
||||
YYYY-MM-DD 00:00:12.500139 [INFO] manager :: 8< 8< 8< ------------------------------------------------------------------------------ 8< 8< 8<
|
||||
YYYY-MM-DD 00:00:12.500327 [INFO] manager :: EVerest manager starting using /home/everest/everest-module-tutorial/config/config-modules-tutorial.yaml
|
||||
YYYY-MM-DD 00:00:12.500354 [INFO] manager :: EVerest using MQTT broker localhost:1883
|
||||
YYYY-MM-DD 00:00:12.799618 [INFO] everest_ctrl :: everest controller process started ...
|
||||
YYYY-MM-DD 00:00:12.799822 [INFO] everest_ctrl :: Launching controller service on port 8849
|
||||
YYYY-MM-DD 00:00:13.120267 [INFO] tutorial_module :: Module tutorial_module_instance initialized.
|
||||
YYYY-MM-DD 00:00:13.149934 [INFO] manager :: >>> All modules are initialized. EVerest up and running <<<
|
||||
|
||||
If your socket can't be connected, make sure that your MQTT brocker is running.
|
||||
|
||||
|
||||
Observing the System
|
||||
====================
|
||||
|
||||
In this final section we describe how to observe the behavior of your module
|
||||
and debug it.
|
||||
|
||||
Exploring with MQTT Explorer
|
||||
----------------------------
|
||||
The open-source tool `MQTT Explorer <https://github.com/thomasnordquist/MQTT-Explorer>`_ can be utilized to
|
||||
observe the module communication in EVerest.
|
||||
|
||||
With your MQTT broker running on localhost:1883, you should be able to connect
|
||||
right away when opening MQTT explorer.
|
||||
|
||||
Then start (or re-start) the EVerest manager (as described above). You should
|
||||
notice an `everest` topic popping up.
|
||||
|
||||
We can now publish a command to our self-written module. For this, choose the topic::
|
||||
|
||||
everest/modules/tutorial_module_instance/impl/interface_impl_tutorial_module/cmd/command_tutorial
|
||||
|
||||
and publish the JSON::
|
||||
|
||||
{
|
||||
"msg_type": "Cmd",
|
||||
"data": {
|
||||
"args": {
|
||||
"payload": "Hello World!"
|
||||
},
|
||||
"id": "00000000-0000-0000-0000-000000000042",
|
||||
"origin": "manual_test"
|
||||
}
|
||||
}
|
||||
|
||||
Our module should return with a "everest" response (you may have to reselect
|
||||
the ``everest/tutorial_module_instance/interface_impl_tutorial_module/cmd``
|
||||
on the left to refresh this view.
|
||||
|
||||
The response should be on topic::
|
||||
|
||||
everest/modules/tutorial_module_instance/impl/interface_impl_tutorial_module/cmd/command_tutorial/response/manual_test
|
||||
|
||||
.. image:: images/mqtt_explorer_example.png
|
||||
|
||||
.. _tutorials_develop_new_module_debugging:
|
||||
|
||||
Debugging
|
||||
---------
|
||||
|
||||
At the latest when you start developing an actual module, it might come handy
|
||||
to be able to debug your code. Thus, the following shall provide some
|
||||
rudimentary steps to do so.
|
||||
|
||||
*1) Rebuild with debug flags enabled*
|
||||
|
||||
Rerun Cmake, this time with `-DCMAKE_BUILD_TYPE=Debug`, and rebuild::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR/build
|
||||
CMAKE_PREFIX_PATH=$EVEREST_WORKSPACE cmake --install-prefix $EVEREST_TUTORIAL_DIR/dist -DCMAKE_BUILD_TYPE=Debug ..
|
||||
make -j <number of parallel jobs>
|
||||
|
||||
*2) Start EVerest with your module with your module marked as "standalone"*
|
||||
|
||||
With EVerest built as described before, but with the additonal option
|
||||
``--standalone tutorial_module_instance``::
|
||||
|
||||
LD_LIBRARY_PATH=$EVEREST_TUTORIAL_DIR/dist/lib:$LD_LIBRARY_PATH \
|
||||
PATH=$EVEREST_TUTORIAL_DIR/dist/bin:$PATH \
|
||||
manager --prefix $EVEREST_TUTORIAL_DIR/dist --conf $EVEREST_TUTORIAL_DIR/config/config-modules-tutorial.yaml --standalone tutorial_module_instance
|
||||
|
||||
This starts EVerest, but without your module. Instead, the output contains a
|
||||
line::
|
||||
|
||||
manager :: Not starting standalone module: tutorial_module_instance
|
||||
|
||||
Also, so far the output should be missing the ``All modules are initialized. EVerest up and running``
|
||||
notification, since it keeps waiting for your module
|
||||
to spin up.
|
||||
|
||||
*3) Start your module with a debugger*:
|
||||
|
||||
Now open a second terminal (while keeping EVerest running in the frist
|
||||
terminal), and start your module via ``gdb``::
|
||||
|
||||
cd $EVEREST_TUTORIAL_DIR/build
|
||||
gdb --args ./modules/TutorialModule/TutorialModule --module tutorial_module_instance --conf $EVEREST_TUTORIAL_DIR/config/config-modules-tutorial.yaml --prefix $EVEREST_TUTORIAL_DIR/dist
|
||||
|
||||
|
||||
In gdb, we set a break in the line that returns the payload when your test
|
||||
command is hit.
|
||||
We then run the program (you might need to adjust the line number)::
|
||||
|
||||
break modules/TutorialModule/interface_impl_tutorial_module/interface_tutorial_moduleImpl.cpp:17
|
||||
run
|
||||
|
||||
After the ``run`` command, you should notify in your EVerest terminal that all
|
||||
modules have now started. You may now again use MQTT Explorer as before and
|
||||
send a command call via MQTT, this should hit your set breakpoint with a
|
||||
output similar to::
|
||||
|
||||
Thread 4 "tutorial_module" hit Breakpoint 1, module::interface_impl_tutorial_module::interface_tutorial_moduleImpl::handle_command_tutorial (this=0xaaaaaad24fc0, payload="mock_transaction_id") at /tmp/everest-tutorial-verify/modules/TutorialModule/interface_impl_tutorial_module/interface_tutorial_moduleImpl.cpp:17
|
||||
17 return "everest";
|
||||
|
||||
|
||||
Of course, you might setup your favorite IDE in a similar way for a nicer
|
||||
debugging experience.
|
||||
|
||||
Exemplary Module Customizations
|
||||
===============================
|
||||
|
||||
Having prepared a buildable and runnable module, we can now extend the logic
|
||||
of our implementation:
|
||||
|
||||
- Add a variable to your interface, and publish it;
|
||||
- Add a second module which requires the ``interface_tutorial_module`` interface and sends commands or subscribes to variables.
|
||||
- ...
|
||||
|
||||
.. hint::
|
||||
This section is yet to come. Want to help us with that? Feel free and create
|
||||
a suggestion for this.
|
||||
|
||||
--------------------------------
|
||||
|
||||
**Authors**: Valentin Dimov, Manuel Ziegler, Andreas Heinrich, Lukas Mertens, Martin Litre, Piet Gömpel, Christoph Burandt
|
||||
|
||||
219
tools/EVerest-main/docs/source/tutorials/everest_api.rst
Normal file
219
tools/EVerest-main/docs/source/tutorials/everest_api.rst
Normal file
@@ -0,0 +1,219 @@
|
||||
.. _tutorial_everest_api:
|
||||
|
||||
********************
|
||||
Using the EVerestAPI
|
||||
********************
|
||||
|
||||
.. note::
|
||||
|
||||
Find in-depth explanations about the EVerestAPI :doc:`here <../explanation/adapt-everest/apis>`.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The EVerestAPI is designed to remain as stable as possible across different releases of EVerest.
|
||||
It provides JSON-encoded data access via MQTT. The API serves as a stable extension point for applications
|
||||
developed outside the EVerest framework that need to exchange data with it.
|
||||
|
||||
Architecture
|
||||
============
|
||||
|
||||
The EVerestAPI is specified using AsyncAPI 3.0 documents: :doc:`EVerestAPI Reference </reference/api/autogenerated_api_index>`.
|
||||
The individual APIs generally match the internal EVerest interfaces and are implemented as standard EVerest modules.
|
||||
For more details, see the :doc:`EVerestAPI modules reference documentation </reference/modules/API/EVerestAPI/autogenerated>`.
|
||||
|
||||
As a rule of thumb, each internal interface is typically provided by one module.
|
||||
Configuring the required APIs is done by adding the corresponding modules to your EVerest configuration;
|
||||
they connect to other modules using the standard EVerest logic.
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
The ``config/bringup/config-bringup-EVerestAPI-entrypoint.yaml`` configuration file demonstrates the API in action.
|
||||
It does not implement internal functionality, but provides several API and BringUp modules for manual interaction.
|
||||
|
||||
.. hint::
|
||||
|
||||
It is advisable to set the access specification in the configuration to ``allow_global_read: true`` for EVerestAPI modules.
|
||||
This allows the modules to determine if multiple EVerestAPI modules are active, preventing the initial ``ready_beacon``
|
||||
from being sent multiple times.
|
||||
|
||||
Example
|
||||
=======
|
||||
|
||||
First, start an MQTT monitoring tool and subscribe to the ``everest_api/#`` topic.
|
||||
|
||||
Start the example configuration:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
build $ ./run-scripts/run-bringup-EVerestAPI-entrypoint.sh
|
||||
|
||||
You will see the EVerest log alongside two panes showing power supply control UIs.
|
||||
|
||||
A ``everest_api/ready_beacon`` with an empty JSON payload indicates that an EVerestAPI is available.
|
||||
Following this, messages will be periodically published to topics such as:
|
||||
``everest_api/1/power_supply_DC/ps_dc_1/e2m/heartbeat``.
|
||||
|
||||
.. note::
|
||||
|
||||
To exit the tmux session, press ``Ctrl+B`` and then ``d``.
|
||||
|
||||
MQTT Topic Structure
|
||||
====================
|
||||
|
||||
Topics follow the structure: ``everest_api/{api-version}/{api-type}/{instance-id}/{direction}/{api-subtopic}``.
|
||||
|
||||
- **api-version**: Version of the API (e.g., *1*)
|
||||
- **api-type**: Type of the API (e.g., *power_supply_DC*)
|
||||
- **instance-id**: Name of the API instance, allowing multiple instances of the same type (typically the module_id, e.g., *ps_dc_1*)
|
||||
- **{e2m|m2e}**:
|
||||
|
||||
- **e2m**: everest-to-(api-client)-module — Published by EVerest, subscribed to by the client.
|
||||
- **m2e**: (api-client)-module-to-everest — Published by the client, subscribed to by the EVerestAPI.
|
||||
|
||||
- **api-subtopic**: The actual subject of the topic (e.g., *heartbeat*).
|
||||
|
||||
Communication Monitoring
|
||||
========================
|
||||
|
||||
To ensure system reliability, both ends of the communication must know if the other side is still active.
|
||||
Two distinct mechanisms serve this goal.
|
||||
|
||||
Monitoring EVerestAPI Endpoints
|
||||
-------------------------------
|
||||
|
||||
The EVerestAPI module periodically publishes to the topic:
|
||||
``everest_api/{api-version}/{api-type}/{instance-id}/e2m/heartbeat``
|
||||
|
||||
The payload is a periodically incrementing integer. An API client can use this heartbeat to detect
|
||||
if the API module (e.g., *ps_dc_1*) is still alive. The heartbeat interval is defined in the manifest
|
||||
or configuration file via ``cfg_heartbeat_interval_ms``.
|
||||
|
||||
.. tip::
|
||||
|
||||
Look for other heartbeat signals and compare the topic structure to the designators in the configuration file.
|
||||
Observe how different intervals affect the timing in the MQTT logs.
|
||||
|
||||
Monitoring API Clients
|
||||
----------------------
|
||||
|
||||
To enable the EVerestAPI module to detect if a client is still alive, set ``cfg_communication_check_to_s``
|
||||
to a value greater than 0. It is the client application's responsibility to periodically send ``true``
|
||||
(as a raw value, not enclosed in ``{}``) to the following topic:
|
||||
|
||||
``everest_api/{api-version}/{api-type}/{instance-id}/m2e/communication_check``
|
||||
|
||||
If a client fails to check in, the API modules will raise an error within EVerest
|
||||
(e.g., "Error raised, type: generic/CommunicationFault ..."), though they will continue to function on their side.
|
||||
|
||||
.. tip::
|
||||
|
||||
Try clearing errors by sending the appropriate communication check messages, and observe how they are
|
||||
raised again once the timeout expires.
|
||||
|
||||
Request-Reply-Timeout
|
||||
---------------------
|
||||
|
||||
Some modules offer a ``cfg_request_reply_to_s`` parameter. This is used when an EVerestAPI module
|
||||
implements an internal EVerest interface and provides commands to other modules.
|
||||
When another module calls a command on that interface, the following sequence occurs:
|
||||
|
||||
* The API module attempts to fulfill the call by writing to the respective API topic.
|
||||
* The API client (having subscribed to this topic) begins the actual work.
|
||||
* The API client reports completion via the reply topic.
|
||||
* The API module relays this reply back to the internal interface.
|
||||
|
||||
If no reply arrives within the specified timeout, the API module issues a default reply
|
||||
to the internal interface to unblock the calling module.
|
||||
|
||||
The Request-Reply Pattern
|
||||
=========================
|
||||
|
||||
API command calls are asynchronous. Triggering a command and receiving a result are separate events in time.
|
||||
To execute a command, the caller writes a message to the topic defined in the API specification using this JSON structure:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"headers": {
|
||||
"replyTo": "reply/to/address"
|
||||
},
|
||||
"payload": {}
|
||||
}
|
||||
|
||||
- ``payload``: Required only when calling commands that have non-empty arguments.
|
||||
- ``headers``: Required whenever the caller expects a result. The result is published to the replyTo topic provided by the caller.
|
||||
|
||||
.. note::
|
||||
|
||||
Callers may omit the headers key if they do not require a result and only wish to trigger the command.
|
||||
|
||||
This pattern applies to both directions (API module calling a client command and vice versa).
|
||||
|
||||
entrypoint_API
|
||||
==============
|
||||
|
||||
The **entrypoint_API** allows clients to discover available API endpoints dynamically.
|
||||
|
||||
ready_beacon
|
||||
------------
|
||||
|
||||
The ``everest_api/ready_beacon`` mentioned earlier is part of this discovery system.
|
||||
|
||||
Discovering the API
|
||||
-------------------
|
||||
|
||||
To perform a basic query, send the following JSON to ``everest_api/discover``:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"headers": {
|
||||
"replyTo": "reply/to/address"
|
||||
}
|
||||
}
|
||||
|
||||
In the example configuration, this results in four individual responses that the client must aggregate.
|
||||
Example response:
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"apis": [
|
||||
{
|
||||
"communication_monitoring": {
|
||||
"communication_check_period_s": 10,
|
||||
"heartbeat_period_ms": 10000
|
||||
},
|
||||
"module_id": "ps_dc_1",
|
||||
"type": "power_supply_DC",
|
||||
"version": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
The modules reply directly from memory; therefore, a 1-second timeout is generally sufficient to gather all replies.
|
||||
Note that the "apis" key contains an array. While usually containing one entry, an API module
|
||||
could implement multiple interfaces and report them all within this array.
|
||||
|
||||
Filtered Queries
|
||||
----------------
|
||||
|
||||
Alternatively, you can restrict responders to a specific type by sending the query to:
|
||||
``everest_api/query-modules/power_supply_DC``
|
||||
|
||||
.. code:: json
|
||||
|
||||
{
|
||||
"headers": {
|
||||
"replyTo": "reply/to/address"
|
||||
}
|
||||
}
|
||||
|
||||
The results will be filtered by the selected API type. Use the returned module_id, type,
|
||||
and version to construct topics as described in the MQTT Topic Structure section.
|
||||
|
||||
.. note::
|
||||
|
||||
Even when using this discovery mechanism, a client must have prior knowledge of the subtopics available for a given API type.
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
64
tools/EVerest-main/docs/source/tutorials/index.rst
Normal file
64
tools/EVerest-main/docs/source/tutorials/index.rst
Normal file
@@ -0,0 +1,64 @@
|
||||
#########
|
||||
Tutorials
|
||||
#########
|
||||
|
||||
Learn a new skill by following our step-by-step experiences.
|
||||
|
||||
Have a look at this categorized list of all EVerest tutorials:
|
||||
|
||||
.. grid:: 1 2 2 3
|
||||
:gutter: 2
|
||||
|
||||
.. grid-item-card:: Develop New EVerest Modules
|
||||
:link: develop-new-module
|
||||
:link-type: doc
|
||||
|
||||
Write an EVerest module from scratch.
|
||||
|
||||
.. grid-item-card:: OCPP 1.6
|
||||
:link: ocpp16
|
||||
:link-type: doc
|
||||
|
||||
Learn how to use OCPP 1.6J in EVerest; how to configure it; how to test it with SteVe as a local CSMS on your local PC
|
||||
|
||||
.. grid-item-card:: OCPP 2.0.1 & 2.1
|
||||
:link: ocpp2
|
||||
:link-type: doc
|
||||
|
||||
Learn how to use OCPP 2.x in EVerest; how to configure it; or to test it on your local PC
|
||||
|
||||
.. grid-item-card:: Plug & Charge
|
||||
:link: plug-and-charge
|
||||
:link-type: doc
|
||||
|
||||
Learn how to run a Plug-&-Charge simulation on your PC
|
||||
|
||||
.. grid-item-card:: Using the Bazel Build Tool
|
||||
:link: bazel
|
||||
:link-type: doc
|
||||
|
||||
Learn how to use the Experimental Bazel Support in EVerest
|
||||
|
||||
.. grid-item-card:: Setup the EVerest Development Container
|
||||
:link: setup-devcontainer/index
|
||||
:link-type: doc
|
||||
|
||||
Learn how to setup a development container for EVerest development.
|
||||
|
||||
.. grid-item-card:: Get to know the EVerestAPI
|
||||
:link: everest_api
|
||||
:link-type: doc
|
||||
|
||||
Learn how the EVerestAPI can be used in your setup
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
develop-new-module
|
||||
ocpp16
|
||||
ocpp2
|
||||
plug-and-charge
|
||||
bazel
|
||||
EVerest devcontainer <setup-devcontainer/index>
|
||||
everest_api
|
||||
367
tools/EVerest-main/docs/source/tutorials/ocpp16.rst
Normal file
367
tools/EVerest-main/docs/source/tutorials/ocpp16.rst
Normal file
@@ -0,0 +1,367 @@
|
||||
.. _tutorial-ocpp16:
|
||||
|
||||
###################
|
||||
OCPP 1.6 in EVerest
|
||||
###################
|
||||
|
||||
.. note::
|
||||
|
||||
EVerest has an implementation of OCPP 1.6J and 2.0.1 and 2.1. This tutorial is about
|
||||
the 1.6 implementation. To get documentation about all implemented versions,
|
||||
see `lib/ocpp in the EVerest repository <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp>`_.
|
||||
|
||||
EVerest provides a complete implementation of Open Charge Point Protocol
|
||||
(OCPP) 1.6J, supporting all feature profiles including Plug&Charge and the
|
||||
Security Extensions.
|
||||
|
||||
The source code of `libocpp` is hosted as part of the EVerest repository:
|
||||
`<https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp>`_.
|
||||
|
||||
This is a tutorial about how to set up and configure OCPP 1.6 in EVerest.
|
||||
|
||||
This tutorial includes:
|
||||
|
||||
- How to run EVerest SIL with the default OCPP 1.6J configuration connecting to
|
||||
SteVe
|
||||
- How to load the OCPP 1.6 module as part of the EVerest configuration
|
||||
- How to configure OCPP 1.6 configuration keys
|
||||
- How to connect to different CSMS
|
||||
|
||||
.. _tutorial_ocpp16_prerequisites:
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
If you're new to EVerest start with our :ref:`Quick Start Guide <htg_getting_started_sw>`
|
||||
to get a simulation in EVerest running for the first time.
|
||||
It is important that you have set up the required docker containers for
|
||||
Mosquitto and SteVe, which we will use as an example CSMS.
|
||||
If you have done that successfully, you can move on with this tutorial.
|
||||
|
||||
.. _tutorial_ocpp16_run_with_steve:
|
||||
|
||||
Run EVerest SIL with SteVe
|
||||
==========================
|
||||
|
||||
The EVerest repository provides a configuration that you can use to run EVerest with OCPP.
|
||||
By default this configuration is connecting to the Open Source CSMS
|
||||
`SteVe <https://github.com/steve-community/steve>`_.
|
||||
Make sure that SteVe is running on your machine as the CSMS we connect to.
|
||||
|
||||
You have to add the chargepoint id *cp001* in SteVe's webinterface to allow a
|
||||
charging station to connect.
|
||||
If you want to simulate charging sessions, you also need to add OCPP tags for
|
||||
the authorization in SteVe.
|
||||
|
||||
Simply run
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
${EVEREST_WORKSPACE:?}/EVerest/build/run-scripts/run-sil-ocpp.sh
|
||||
|
||||
to start EVerest with OCPP 1.6J. You can start playing around with central
|
||||
system-initiated messages and use the EVerest simulation to start charging
|
||||
sessions.
|
||||
|
||||
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.
|
||||
|
||||
.. _tutorial_ocpp16_configure_ocpp:
|
||||
|
||||
OCPP configuration file
|
||||
=======================
|
||||
|
||||
In addition to the EVerest configuration yaml file, OCPP 1.6 is configured
|
||||
using a JSON configuration file.
|
||||
This configuration file can contain all configuration keys from the OCPP 1.6
|
||||
specification.
|
||||
Examples for that can be found `here <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp/config/v16>`__.
|
||||
|
||||
This is the one we used to connect to SteVe:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"Internal": {
|
||||
"ChargePointId": "cp001",
|
||||
"CentralSystemURI": "127.0.0.1:8180/steve/websocket/CentralSystemService/",
|
||||
"ChargeBoxSerialNumber": "cp001",
|
||||
"ChargePointModel": "Yeti",
|
||||
"ChargePointVendor": "Pionix",
|
||||
"FirmwareVersion": "0.1",
|
||||
"AllowChargingProfileWithoutStartSchedule": true,
|
||||
"UseTPM" : false,
|
||||
"LogMessagesFormat": ["html","security"]
|
||||
},
|
||||
"Core": {
|
||||
"AuthorizeRemoteTxRequests": false,
|
||||
"ClockAlignedDataInterval": 900,
|
||||
"ConnectionTimeOut": 30,
|
||||
"ConnectorPhaseRotation": "0.RST,1.RST",
|
||||
"GetConfigurationMaxKeys": 100,
|
||||
"HeartbeatInterval": 86400,
|
||||
"LocalAuthorizeOffline": false,
|
||||
"LocalPreAuthorize": false,
|
||||
"MeterValuesAlignedData": "Energy.Active.Import.Register",
|
||||
"MeterValuesSampledData": "Energy.Active.Import.Register,SoC",
|
||||
"MeterValueSampleInterval": 60,
|
||||
"NumberOfConnectors": 1,
|
||||
"ResetRetries": 1,
|
||||
"StopTransactionOnEVSideDisconnect": true,
|
||||
"StopTransactionOnInvalidId": true,
|
||||
"StopTxnAlignedData": "Energy.Active.Import.Register",
|
||||
"StopTxnSampledData": "Energy.Active.Import.Register",
|
||||
"SupportedFeatureProfiles": "Core,FirmwareManagement,RemoteTrigger,Reservation,LocalAuthListManagement,SmartCharging",
|
||||
"TransactionMessageAttempts": 1,
|
||||
"TransactionMessageRetryInterval": 10,
|
||||
"UnlockConnectorOnEVSideDisconnect": true,
|
||||
"WebsocketPingInterval": 0
|
||||
},
|
||||
"FirmwareManagement": {
|
||||
"SupportedFileTransferProtocols": "FTP"
|
||||
},
|
||||
"Security": {
|
||||
"CpoName": "Pionix",
|
||||
"AuthorizationKey": "AABBCCDDEEFFGGHH",
|
||||
"SecurityProfile": 1
|
||||
},
|
||||
"LocalAuthListManagement": {
|
||||
"LocalAuthListEnabled": true,
|
||||
"LocalAuthListMaxLength": 42,
|
||||
"SendLocalListMaxLength": 42
|
||||
},
|
||||
"SmartCharging": {
|
||||
"ChargeProfileMaxStackLevel": 42,
|
||||
"ChargingScheduleAllowedChargingRateUnit": "Current,Power",
|
||||
"ChargingScheduleMaxPeriods": 42,
|
||||
"MaxChargingProfilesInstalled": 42
|
||||
},
|
||||
"PnC": {
|
||||
"ISO15118CertificateManagementEnabled": true,
|
||||
"ISO15118PnCEnabled": true,
|
||||
"ContractValidationOffline": true
|
||||
},
|
||||
"CostAndPrice": {
|
||||
"CustomDisplayCostAndPrice": false
|
||||
},
|
||||
"Custom": {
|
||||
"ExampleConfigurationKey": "example"
|
||||
}
|
||||
}
|
||||
|
||||
The configuration keys are split up into the feature profiles that are
|
||||
specified in OCPP 1.6 plus the extra profiles *Internal*, *Security*, *PnC* and
|
||||
*CostAndPrice*.
|
||||
Here's a short overview of the purpose of each profile in the configuration file:
|
||||
|
||||
- Internal: Used for internal configuration keys that are not specified in
|
||||
OCPP 1.6
|
||||
- Core: Includes Core configuration keys of OCPP 1.6
|
||||
- FirmwareManagement: Includes configuration keys that apply when the feature
|
||||
profile FirmwareManagement is implemented
|
||||
- Security: Includes configuration parameters that have been introduced within
|
||||
the OCPP 1.6J Security Whitepaper
|
||||
- LocalAuthListManagement: Includes configuration parameters that apply when
|
||||
the feature profile LocalAuthListManagement is implemented
|
||||
- SmartCharging: Includes configuration parameters that apply when the feature
|
||||
profile SmartCharging is implemented
|
||||
- PnC: Used for Plug&Charge and includes configuration parameters that have
|
||||
been introduced within the OCPP 1.6J Plug&Charge Whitepaper
|
||||
- CostAndPrice: Used for enabling support for the California Pricing Whitepaper
|
||||
|
||||
EVerest's `libocpp` supports almost all configuration parameters that are specified
|
||||
within OCPP 1.6. Despite that, it is possible to omit configuration parameters
|
||||
that are not required and it is even possible to omit a whole feature profile
|
||||
in the configuration file if it is not supported. This means that the
|
||||
configuration of the `libocpp` provides maximum flexibility and can be
|
||||
tailored to your specific charging station.
|
||||
|
||||
.. note::
|
||||
|
||||
There is a lot to configure with OCPP. Make sure to thoroughly read through
|
||||
the OCPP 1.6 specification and the
|
||||
`profile schemas <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp/config/v16/profile_schemas>`_
|
||||
and configure OCPP according to your needs.
|
||||
|
||||
.. _tutorial_ocpp16_connect_different_csms:
|
||||
|
||||
Connect to a different CSMS
|
||||
===========================
|
||||
|
||||
In order to connect to a different CSMS, you have to modify the connection
|
||||
details within the OCPP configuration file. The OCPP config is a separate
|
||||
JSON file in which all configuration keys of OCPP 1.6 plus some internal parameters
|
||||
can be configured.
|
||||
|
||||
You can specify the path to this configuration file inside the ``EVerest``
|
||||
configuration file using the configuration parameter ``ChargePointConfigPath``
|
||||
of the OCPP module within EVerest. This defaults to *ocpp-config.json*.
|
||||
If this path is relative, the default path for the OCPP configuration
|
||||
*dist/share/everest/modules/OCPP* will be prepended.
|
||||
|
||||
To connect to a different CSMS, you have to modify the connection details of
|
||||
the ocpp configuration file. This includes the parameter ``CentralSystemURI``
|
||||
and it might also include to change the parameters ``AuthorizationKey`` and
|
||||
``SecurityProfile``. Here's a short overview of the purpose of the parameters:
|
||||
|
||||
- ChargePointId: Identity of the charging station
|
||||
- CentralSystemURI: Specifies the endpoint of the CSMS
|
||||
- Can optionally include the ChargePointId after the last back-slash of the URI
|
||||
|
||||
- SecurityProfile: Specifies the SecurityProfile which defines type of
|
||||
transport layer connection between ChargePoint and CSMS
|
||||
|
||||
- Can have the value 0, 1, 2 or 3
|
||||
- SecurityProfile 0: Unsecure transport without Basic Authentication (ws://)
|
||||
- SecurityProfile 1: Unsecure transport with Basic Authentication (ws://)
|
||||
- SecurityProfile 2: TLS with Basic authentication (wss://)
|
||||
- SecurityProfile 3: TLS with client side certificates (wss://)
|
||||
|
||||
- AuthorizationKey: Specifies the password used for HTTP Basic Authentication
|
||||
|
||||
- Must be set if SecurityProfile is 1 or 2, can be omitted if
|
||||
SecurityProfile is 0 or 3
|
||||
- Minimal length: 16 bytes
|
||||
|
||||
Modify these parameters according to the connection requirements of the CSMS. Find all available configuration keys
|
||||
and their descriptions in `here <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp/config/v16/profile_schemas>`_
|
||||
|
||||
.. note::
|
||||
|
||||
For TLS, it might be required to prepare the required certificates and
|
||||
private keys. Please see the documentation of the
|
||||
:ref:`EvseSecurity module <everest_modules_EvseSecurity>`
|
||||
for more information on how to set up the TLS connection for OCPP.
|
||||
|
||||
.. _tutorial_ocpp16_configure_ocpp_everest:
|
||||
|
||||
Configuring OCPP 1.6 within EVerest
|
||||
===================================
|
||||
|
||||
To be able to follow the further explanations, you should be familiar with the configuration of EVerest modules.
|
||||
Take a look into :doc:`EVerest Module Concept </explanation/detail-module-concept>` for that.
|
||||
|
||||
To configure the OCPP module of EVerest, find the available configuration parameters
|
||||
in the :ref:`module documentation <everest_modules_OCPP>`, and read through them
|
||||
carefully in order to configure it according to your needs.
|
||||
|
||||
In order to enable OCPP 1.6 in EVerest, you need to load the module in the
|
||||
EVerest configuration file and set up the module connections.
|
||||
The interfaces provided and required by the OCPP module and its purposes are
|
||||
described in the
|
||||
:ref:`module documentation <everest_modules_OCPP>`.
|
||||
|
||||
The EVerest configuration file
|
||||
`config-sil-ocpp.yaml <https://github.com/EVerest/EVerest/blob/main/config/config-sil-ocpp.yaml>`_
|
||||
which was used previously serves as a good example for how the connections of
|
||||
the module could be set up.
|
||||
|
||||
Here is a quick list of things you should remember when adding OCPP to your
|
||||
EVerest configuration file:
|
||||
|
||||
1. **Load the OCPP module** by including it in the configuration file.
|
||||
|
||||
2. **Add and connect the required modules:**
|
||||
|
||||
- **evse_manager** (interface: ``energy_manager``, 1 to 128 connections):
|
||||
|
||||
OCPP requires this connection to integrate with the charge control logic of EVerest.
|
||||
One connection represents one EVSE.
|
||||
To manage multiple EVSEs via one OCPP connection, multiple connections must be configured
|
||||
in the EVerest configuration file.
|
||||
|
||||
*Module implementation typically used to fulfill this requirement:*
|
||||
``EvseManager``, ``implementation_id: evse``
|
||||
|
||||
- **evse_energy_sink** (interface: ``external_energy_limits``, 0 to 128):
|
||||
|
||||
OCPP optionally requires this connection to communicate smart charging limits received
|
||||
from the CSMS within EVerest.
|
||||
|
||||
Typically, ``EnergyNode`` modules are used to fulfill this requirement.
|
||||
Configure one ``EnergyNode`` module per EVSE and one extra for *evse id* zero.
|
||||
The ``EnergyNode`` for *evse id* zero represents the energy sink for the
|
||||
complete charging station.
|
||||
|
||||
*Module typically used to fulfill this requirement:*
|
||||
:ref:`EnergyNode <everest_modules_EnergyNode>`
|
||||
|
||||
More information about the energy management setup can be found in the
|
||||
:doc:`EnergyManager module documentation </explanation/energymanagement/index>`.
|
||||
|
||||
- **auth** (interface: ``auth``, 1):
|
||||
|
||||
This connection is used to set the standardized ``ConnectionTimeout`` configuration key
|
||||
if configured and/or changed by the CSMS.
|
||||
|
||||
*Module typically used to fulfill this requirement:*
|
||||
:ref:`Auth module <everest_modules_Auth>`, ``implementation_id: main``
|
||||
|
||||
- **reservation** (interface: ``reservation``, 1):
|
||||
|
||||
This connection is used to apply reservation requests from the CSMS.
|
||||
|
||||
*Module typically used to fulfill this requirement:*
|
||||
:ref:`Auth module <everest_modules_Auth>`, ``implementation_id: reservation``
|
||||
|
||||
- **system** (interface: ``system``, 1):
|
||||
|
||||
This connection is used to execute and control system-wide operations that
|
||||
can be triggered by the CSMS, like log uploads, firmware updates, and resets.
|
||||
|
||||
*Modules fulfilling this requirement:*
|
||||
|
||||
- :ref:`Linux_Systemd_Rauc module <everest_modules_Linux_Systemd_Rauc>` (``implementation_id: main``)
|
||||
- For simulation purposes: :ref:`System module <everest_modules_System>` (``implementation_id: main``)
|
||||
|
||||
.. note::
|
||||
The System module is **not meant to be used in production systems**.
|
||||
|
||||
- **security** (interface: ``evse_security``, 1):
|
||||
|
||||
This connection is used to execute security-related operations and to manage
|
||||
certificates and private keys.
|
||||
|
||||
*Module typically used to fulfill this requirement:*
|
||||
:ref:`EvseSecurity module <everest_modules_EvseSecurity>`, ``implementation_id: main``
|
||||
|
||||
- **data_transfer** (interface: ``ocpp_data_transfer``, 0 to 1):
|
||||
|
||||
This connection is used to handle **DataTransfer.req** messages from the CSMS.
|
||||
A module implementing this interface can contain custom logic to handle such requests.
|
||||
A custom implementation is required to add custom handling.
|
||||
|
||||
- **display_message** (interface: ``display_message``, 0 to 1):
|
||||
|
||||
This connection is used to allow the CSMS to display pricing or other information
|
||||
on the display of the charging station.
|
||||
|
||||
To fulfill the requirements of the California Pricing whitepaper, it is required
|
||||
to connect a module implementing this interface.
|
||||
|
||||
.. note::
|
||||
EVerest currently does **not** provide a display module that implements this interface.
|
||||
|
||||
3. **Configure OCPP with the Auth module:**
|
||||
|
||||
Make sure to configure the OCPP module as part of the ``token_provider``
|
||||
(``implementation_id: auth_provider``) and ``token_validator``
|
||||
(``implementation_id: auth_validator``) connections of the Auth module (if you use it).
|
||||
|
||||
Please see the documentation of the :ref:`Auth module <everest_modules_Auth>` for more information.
|
||||
|
||||
4. **Enable Plug & Charge (optional):**
|
||||
|
||||
If you want to use the Plug&Charge feature, you must also add the
|
||||
``EvseManager`` (``implementation_id: token_provider``) module to the connections
|
||||
of the Auth module.
|
||||
|
||||
See :doc:`Configure Plug&Charge in EVerest </how-to-guides/configure-pnc>` for more
|
||||
information about how to set this up.
|
||||
|
||||
You can also use the existing configuration examples as a guide.
|
||||
|
||||
----
|
||||
|
||||
**Authors:** Piet Gömpel
|
||||
540
tools/EVerest-main/docs/source/tutorials/ocpp2.rst
Normal file
540
tools/EVerest-main/docs/source/tutorials/ocpp2.rst
Normal file
@@ -0,0 +1,540 @@
|
||||
.. _tutorial-ocpp2:
|
||||
|
||||
*****************************
|
||||
OCPP 2.0.1 and 2.1 in EVerest
|
||||
*****************************
|
||||
|
||||
.. note::
|
||||
|
||||
EVerest has an implementation of OCPP 1.6J and 2.0.1 and 2.1. This tutorial is about
|
||||
the 2.0.1 and 2.1 implementation. To get documentation about all implemented versions,
|
||||
see `lib/ocpp in the EVerest repository <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp>`_.
|
||||
|
||||
OCPP2.0.1 and OCPP2.1 in EVerest
|
||||
=================================
|
||||
|
||||
EVerest provides an implementation of OCPP 2.0.1 and 2.1 based on
|
||||
`libocpp` which is hosted as part of the `EVerest repository <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp>`_. Since OCPP 2.0.1 and 2.1
|
||||
is mostly backwards compatible, the implementation of OCPP 2.1 is based on the
|
||||
2.0.1 implementation. Every functionality that is provided as part of OCPP 2.0.1
|
||||
is also available in OCPP 2.1.
|
||||
|
||||
In EVerest, the :ref:`OCPP201 module <everest_modules_OCPP>`
|
||||
provides the OCPP 2.0.1 and 2.1 functionality.
|
||||
|
||||
Where applicable the following documentation uses "2.x" to refer to both versions.
|
||||
|
||||
.. note::
|
||||
|
||||
Which OCPP2.x version are supported can be controlled using the ``SupportedOcppVersions`` variable
|
||||
of the ``InternalCtrlr`` component of the device model. Please see the
|
||||
:ref:`Device Model Configuration <tutorial-ocpp2-configure-ocpp>` section for more information.
|
||||
By default, both versions are supported. It still depends on the CSMS which version is actually used.
|
||||
For more information about the version negotiation, please refer to the
|
||||
**OCPP 2.1 Part 4 - JSON over WebSockets implementation guide**
|
||||
|
||||
-----------------------------------------------
|
||||
|
||||
This tutorial includes:
|
||||
|
||||
- How to run EVerest SIL with a `simple CSMS <https://github.com/EVerest/ocpp-csms>`_
|
||||
- How to configure the OCPP 2.x device model
|
||||
- How to connect to different CSMS
|
||||
- How to load the OCPP 2.x module as part of the EVerest configuration
|
||||
|
||||
.. _tutorial-ocpp2-prerequisites:
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
If you're new to EVerest, start with our
|
||||
:ref:`Quick Start Guide <htg_getting_started_sw>`
|
||||
to get a simulation in EVerest running for the first time.
|
||||
If you have done that successfully, you can move on with this tutorial.
|
||||
|
||||
.. _tutorial-ocpp2-run-with-csms:
|
||||
|
||||
Run EVerest SIL with OCPP 2.x and a simple CSMS
|
||||
=================================================
|
||||
|
||||
EVerest provides a `simple CSMS <https://github.com/EVerest/ocpp-csms>`_ that
|
||||
can be used for testing. It works with both OCPP 2.0.1 and 2.1.
|
||||
It responds "friendly" to all OCPP messages initiated by the charging station.
|
||||
Follow the instruction of its README to start up the CSMS locally.
|
||||
|
||||
The EVerest repository provides a configuration that you can use
|
||||
to run EVerest with OCPP 2.x.
|
||||
By default, this configuration is connecting to `localhost:9000` which is also
|
||||
the default address and port of our simple CSMS.
|
||||
|
||||
Simply run
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
${EVEREST_WORKSPACE:?}/EVerest/build/run-scripts/run-sil-ocpp201-pnc.sh
|
||||
|
||||
to start EVerest with OCPP 2.x support and Plug&Charge enabled. You can start playing around with the EVerest
|
||||
simulation to start charging sessions.
|
||||
|
||||
You can find the OCPP message log in different formats in the
|
||||
`/tmp/everest_ocpp_logs` directory.
|
||||
|
||||
.. _tutorial-ocpp2-configure-ocpp:
|
||||
|
||||
Device Model Configuration
|
||||
==========================
|
||||
|
||||
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 terms OCPP 2.x terms **Component**,
|
||||
**Variable**, **VariabeCharacteristics** and **VariableAttributes**,
|
||||
**VariableMonitoring** to be able to follow the further explanations.
|
||||
|
||||
OCPP 2.x does not differentiate between configuration and telemetry
|
||||
variables. This provides a lot of flexibility, but it also adds some overhead
|
||||
to the definition of configuration variables (e.g. for configuration variables
|
||||
only the ``actual`` attribute is actually relevant, but ``target``, ``minSet``,
|
||||
and ``maxSet`` attribute types are never used and not needed for simple
|
||||
configuration variables).
|
||||
|
||||
Device Model definition and configuration structure
|
||||
---------------------------------------------------
|
||||
|
||||
In libocpp, 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:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"description": "Schema for LocalAuthListCtrlr",
|
||||
"name": "LocalAuthListCtrlr",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"LocalAuthListCtrlrAvailable": {
|
||||
"variable_name": "Available",
|
||||
"characteristics": {
|
||||
"supportsMonitoring": true,
|
||||
"dataType": "boolean"
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "Actual",
|
||||
"mutability": "ReadOnly",
|
||||
"value": true
|
||||
}
|
||||
],
|
||||
"description": "Local Authorization List is available.",
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"ItemsPerMessageSendLocalList": {
|
||||
"variable_name": "ItemsPerMessage",
|
||||
"characteristics": {
|
||||
"supportsMonitoring": true,
|
||||
"dataType": "integer"
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "Actual",
|
||||
"mutability": "ReadOnly",
|
||||
"value": 250
|
||||
}
|
||||
],
|
||||
"description": "Maximum number of records in SendLocalList",
|
||||
"type": "integer"
|
||||
},
|
||||
"LocalAuthListCtrlrStorage": {
|
||||
"variable_name": "Storage",
|
||||
"characteristics": {
|
||||
"unit": "B",
|
||||
"supportsMonitoring": true,
|
||||
"dataType": "integer"
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "Actual",
|
||||
"mutability": "ReadOnly"
|
||||
}
|
||||
],
|
||||
"description": "Indicates the number of bytes currently used by the Local Authorization List. MaxLimit indicates the maximum number of bytes that can be used by the Local Authorization List.",
|
||||
"type": "integer"
|
||||
},
|
||||
"LocalAuthListCtrlrDisablePostAuthorize": {
|
||||
"variable_name": "DisablePostAuthorize",
|
||||
"characteristics": {
|
||||
"supportsMonitoring": true,
|
||||
"dataType": "boolean"
|
||||
},
|
||||
"attributes": [
|
||||
{
|
||||
"type": "Actual",
|
||||
"mutability": "ReadWrite"
|
||||
}
|
||||
],
|
||||
"description": "When set to true this variable disables the behavior to request authorization for an idToken that is stored in the local authorization list with a status other than Accepted, as stated in C14.FR.03.",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"BytesPerMessageSendLocalList",
|
||||
"ItemsPerMessageSendLocalList",
|
||||
"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. ``LocalAuthListCtrlrEntries`` is rather a telemetry than configuration,
|
||||
so libocpp will set the value for this at runtime and therefore it is not
|
||||
required to configure a value for it.
|
||||
It's an example for a variable that is only defined, but not configured.
|
||||
|
||||
.. _tutorial-ocpp2-device-model-init:
|
||||
|
||||
Device Model initialization
|
||||
---------------------------
|
||||
|
||||
The config files are parsed at startup and used to initialize an SQLite
|
||||
database. Please see
|
||||
`the documentation about the device model initialization <https://github.com/EVerest/EVerest/blob/main/lib/everest/ocpp/doc/v2/ocpp_201_device_model_initialization.md>`_
|
||||
for detailed information about this process.
|
||||
|
||||
You should specify the path to the directory of your device model definitions
|
||||
using the configuration parameter ``DeviceModelConfigPath``
|
||||
of the OCPP201 module within EVerest.
|
||||
It shall point to the directory where the component files are located in these
|
||||
two subdirectories:
|
||||
|
||||
* standardized
|
||||
* custom
|
||||
|
||||
By default, the default value for ``DeviceModelConfigPath`` is pointing to the
|
||||
installation directory of the component files.
|
||||
You can modify the component according to your specific needs and the design of
|
||||
your charging station.
|
||||
|
||||
Libocpp provides a device model configuration as a starting point
|
||||
-----------------------------------------------------------------
|
||||
|
||||
You can define custom components and variables according to the requirements
|
||||
and setup of your charging station. There are a lot of
|
||||
standardized components and variables in OCPP 2.x that are required and used
|
||||
in functional requirements of the specification. Please have
|
||||
a look at the OCPP 2.x specifications for more information about each of the
|
||||
standardized components and variables.
|
||||
For this reason, it is recommended to use the
|
||||
`device device model definitions of libocpp <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp/config/v2/component_config>`_
|
||||
as a starting point. This is an examplary device model configuration for two
|
||||
EVSEs.
|
||||
|
||||
The `device model setup from libocpp <https://github.com/EVerest/EVerest/tree/main/lib/everest/ocpp/config/v2/component_config>`_
|
||||
serves as a good example.
|
||||
|
||||
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.
|
||||
|
||||
The following sections explain important component and variables in order to
|
||||
connect to a different CSMS or to enable certain features.
|
||||
|
||||
.. _tutorial-ocpp2-network-configuration:
|
||||
|
||||
Network Configuration
|
||||
---------------------
|
||||
|
||||
OCPP 2.x uses **NetworkConfiguration** components in the device model to define
|
||||
how the charging station connects to a CSMS. 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.
|
||||
|
||||
.. _tutorial-ocpp2-different-csms:
|
||||
|
||||
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 :ref:`tutorial-ocpp2-adding-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://``
|
||||
|
||||
- ``OcppInterface``: The network interface to use (``Wired0``--``Wired3``, ``Wireless0``--``Wireless3``, or ``Any``)
|
||||
- ``OcppTransport``: The transport protocol (``JSON`` or ``SOAP``)
|
||||
- ``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
|
||||
:ref:`EvseSecurity module <everest_modules_EvseSecurity>` for more information
|
||||
on how to set up the TLS connection for OCPP.
|
||||
|
||||
.. _tutorial-ocpp2-adding-slots:
|
||||
|
||||
Adding more network configuration slots
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
By default, libocpp ships with two NetworkConfiguration slots. 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:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"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.
|
||||
|
||||
.. _tutorial-ocpp2-migration:
|
||||
|
||||
Migration from legacy NetworkConnectionProfiles
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Older versions of libocpp stored all connection profiles as a single JSON array
|
||||
blob in the ``InternalCtrlr.NetworkConnectionProfiles`` variable. The current
|
||||
implementation stores each profile as individual device model variables in
|
||||
per-slot ``NetworkConfiguration`` components.
|
||||
|
||||
**Automatic migration:** On startup, libocpp automatically detects and migrates
|
||||
the legacy format. No manual action is required for existing deployments.
|
||||
The migration works as follows:
|
||||
|
||||
1. If the ``NetworkConnectionProfiles`` blob is empty, no migration is needed.
|
||||
2. If any existing ``NetworkConfiguration`` slot already has a configured
|
||||
``OcppCsmsUrl``, migration is skipped (the new format is already in use).
|
||||
3. Otherwise, each profile in the JSON array is written to its corresponding
|
||||
slot using the ``configurationSlot`` field from the blob as the slot number.
|
||||
4. If a profile in the blob does not contain a ``basicAuthPassword``, the
|
||||
global ``SecurityCtrlr.BasicAuthPassword`` is used as a fallback.
|
||||
5. After successful import, the blob is cleared to prevent re-running the
|
||||
migration on subsequent startups.
|
||||
|
||||
If you are setting up a new deployment, you do not need the legacy blob format.
|
||||
Configure your connection profiles directly using the per-slot
|
||||
``NetworkConfiguration_N.json`` files as described above. Make sure the
|
||||
``InternalCtrlr.NetworkConnectionProfiles`` blob remains empty (its default)
|
||||
so the migration step is skipped on first boot.
|
||||
|
||||
.. _tutorial-ocpp2-enable-pnc:
|
||||
|
||||
Enable Plug&Charge
|
||||
------------------
|
||||
|
||||
In order to enable Plug&Charge, adjust your component files according to the
|
||||
:doc:`Plug&Charge configuration documentation </how-to-guides/configure-pnc>`.
|
||||
|
||||
.. _tutorial-configure-ocpp2-everest:
|
||||
|
||||
Configuring the OCPP201 module within EVerest
|
||||
=============================================
|
||||
|
||||
To be able to follow the further explanations, you should be familiar with the configuration of EVerest modules.
|
||||
Take a look into :doc:`EVerest Module Concept </explanation/detail-module-concept>` for that.
|
||||
|
||||
To configure the OCPP201 module of EVerest, find the available configuration parameters
|
||||
and carefully read the further explanations in the
|
||||
:ref:`OCPP201 module documentation <everest_modules_OCPP201>`
|
||||
in order to configure it according to your needs.
|
||||
|
||||
In order to enable OCPP2.x in EVerest, you need to load the module in the EVerest configuration file and set up the module connections. The interfaces
|
||||
provided and required by the OCPP module and its purposes are described in the :ref:`OCPP201 module documentation <everest_modules_OCPP201>`.
|
||||
|
||||
The EVerest configuration file `config-sil-ocpp201.yaml <https://github.com/EVerest/EVerest/blob/main/config/config-sil-ocpp201.yaml>`_
|
||||
which was used previously serves as a good example
|
||||
for how the connections of the module could be set up.
|
||||
|
||||
Here is a quick list of things you should remember when adding OCPP201 to your EVerest configuration file:
|
||||
|
||||
1. Load the OCPP201 module by including it in the the configuration file.
|
||||
|
||||
2. Make sure to add and connect the module requirements:
|
||||
|
||||
- evse_manager (interface: energy_manager, 1 to 128 connections):
|
||||
OCPP201 requires this connection in order to integrate with the charge control
|
||||
logic of EVerest.
|
||||
One connection represents one EVSE.
|
||||
In order to manage multiple EVSEs via one OCPP connection, multiple
|
||||
connections need to be configured in the EVerest config file.
|
||||
Module implementation typically used to fullfill this requirement:
|
||||
:ref:`EvseManager <everest_modules_EvseManager>`, implementation_id: evse
|
||||
- evse_energy_sink (interface: external_energy_limits, 0 to 128):
|
||||
OCPP optionally requires this connection to communicate smart charging
|
||||
limits received from the CSMS within EVerest.
|
||||
Typically EnergyNode modules are used to fullfill this requirement.
|
||||
Configure one EnergyNode module per EVSE and one extra for *evse id* zero.
|
||||
The EnergyNode for *evse id* zero represents the energy sink for the
|
||||
complete charging station.
|
||||
Module typically used to fullfill this requirement:
|
||||
:ref:`EnergyNode <everest_modules_EnergyNode>`, implementation_id: external_limits
|
||||
More information about the energy management setup can be found in the
|
||||
:ref:`EnergyManager module documentation <everest_modules_EnergyManager>`.
|
||||
- auth (interface: auth, 1): This connection is used to set the standardized
|
||||
``ConnectionTimeout`` configuration key if configured and/or changed by the
|
||||
CSMS.
|
||||
Module typically used to fullfill this requirement:
|
||||
:ref:`Auth <everest_modules_Auth>`, implementation_id: main
|
||||
- reservation (interface: reservation, 1):
|
||||
This connection is used to apply reservation requests from the CSMS.
|
||||
Module typically used to fullfill this requirement:
|
||||
:ref:`Auth <everest_modules_Auth>`, implementation_id: reservation
|
||||
- system (interface: system, 1):
|
||||
This connection is used to execute and control system-wide operations that
|
||||
can be triggered by the CSMS, like log uploads, firmware updates, and
|
||||
resets.
|
||||
The :ref:`Linux_Systemd_Rauc module <everest_modules_Linux_Systemd_Rauc>` (implementation_id: main)
|
||||
can be used to fullfill this requirement.
|
||||
For simulation purposes, the :ref:`System module <everest_modules_System>` (implementation_id: main)
|
||||
can be used. Note that the latter is not meant to be used in production systems!
|
||||
- security (interface: evse_security, 1):
|
||||
This connection is used to execute security-related operations and to
|
||||
manage certificates and private keys.
|
||||
Module typically used to fullfill this requirement:
|
||||
:ref:`EvseSecurity <everest_modules_EvseSecurity>`, implementation_id: main
|
||||
- data_transfer (interface: ocpp_data_transfer, 0 to 1):
|
||||
This connection is used to handle **DataTransfer.req** messages from the
|
||||
CSMS.
|
||||
A module implementing this interface can contain custom logic to handle the
|
||||
requests from the CSMS.
|
||||
A custom implementation for this interface is required to add custom
|
||||
handling.
|
||||
- display_message (interface: display_message, 0 to 1):
|
||||
This connection is used to allow the CSMS to display pricing or other
|
||||
information on the display of the charging station.
|
||||
In order to fulfill the requirements of the California Pricing whitepaper,
|
||||
it is required to connect a module implementing this interface.
|
||||
EVerest currently does not provide a display module that implements this
|
||||
interface.
|
||||
|
||||
3. Make sure to configure the OCPP201 module as part of the token_provider (implementation_id: auth_provider) and token_validator (implementation_id: auth_validator)
|
||||
connections of the Auth module (if you use it). Please see the documentation of the auth module for more information.
|
||||
|
||||
4. In case you want to use the Plug&Charge feature, you must also add the EvseManager (implementation_id: token_provider) module to the connections of the
|
||||
Auth module.
|
||||
|
||||
You can also use the existing config examples as a guide.
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Authors**: Piet Gömpel
|
||||
130
tools/EVerest-main/docs/source/tutorials/plug-and-charge.rst
Normal file
130
tools/EVerest-main/docs/source/tutorials/plug-and-charge.rst
Normal file
@@ -0,0 +1,130 @@
|
||||
.. _tutorial_plug_and_charge:
|
||||
|
||||
Plug&Charge with EVerest Software in the Loop
|
||||
=============================================
|
||||
|
||||
EVerest provides support for Plug&Charge within ISO15118-2 and OCPP1.6 and
|
||||
OCPP2.0.1. This tutorial explains how you can set up and configure EVerest
|
||||
for Plug&Charge with the software in the loop.
|
||||
|
||||
.. _prerequisites:
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
If you're new to EVerest, start with our
|
||||
`Quick Start Guide <02_quick_start_guide.html>`_ to get a simulation in
|
||||
EVerest running for the first time.
|
||||
If you have done that successfully, you can move on with this tutorial.
|
||||
|
||||
If you are interested in more in-depth information about how Plug&Charge is
|
||||
implemented in EVerest, please refer to the
|
||||
:doc:`Plug&Charge explanations </explanation/pnc-process>`
|
||||
and the :doc:`Plug&Charge Configuration Howto </how-to-guides/configure-pnc>`
|
||||
|
||||
Packages for ISO 15118 communication
|
||||
------------------------------------
|
||||
|
||||
To be able to build EVerest with ISO 15118 capability, you will have to
|
||||
install the requirements for Josev:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd {EVerest Workspace Directory}/Josev
|
||||
python3 -m pip install -r requirements.txt
|
||||
|
||||
For ISO 15118 communication including Plug&Charge, install Josev and some CA
|
||||
certificates:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd {EVerest Workspace Directory}/Josev/iso15118/shared/pki
|
||||
./create_certs.sh -v iso-2 -i {EVerest Workspace Directory}/EVerest
|
||||
|
||||
This will enable ISO 15118 communication including Plug&Charge and install the
|
||||
required CA certificates inside ``config/certs/ca`` and the client certificates,
|
||||
private keys and password files inside ``config/certs/client``.
|
||||
|
||||
.. attention::
|
||||
|
||||
This will generate an example PKI setup that can only be used for testing
|
||||
and simulation. It will not work and is not recommended for production.
|
||||
|
||||
As the shell script uses the Java ``keytool``, it is required for this
|
||||
procedure to have Java installed.
|
||||
|
||||
The script for setting up PKI can also be used with the EvseV2G module.
|
||||
|
||||
.. _plug_and_charge_process:
|
||||
|
||||
The Plug&Charge process
|
||||
-----------------------
|
||||
|
||||
The process we are going to simulate covers a complete AC Plug&Charge process
|
||||
including a CertificateInstallation request to install a virtual contract in
|
||||
the simulated EV.
|
||||
|
||||
The components included in this setup are the following:
|
||||
|
||||
1. Charging Station (SECC): The EVerest stack provides the software running on
|
||||
the charger. It provides the ISO 15118 and OCPP implementations.
|
||||
2. Electric Vehicle (EVCC): The EV is simulated using the software in the
|
||||
loop (SIL). The SIL runs as part of EVerest using separate modules that are
|
||||
started alongside with the EVerest application.
|
||||
3. Charging Station Management System (CSMS): The CSMS used in this setup is
|
||||
an external service. It's a very simple implementation of an OCPP central
|
||||
system based on the Python ocpp package from TheMobilityHouse
|
||||
(https://github.com/mobilityhouse/ocpp).
|
||||
|
||||
Let's get started step by step
|
||||
------------------------------
|
||||
|
||||
1. Prerequisites must be fullfilled: EVerest must be installed on your system.
|
||||
By default, this includes a complete and automatic installation of a test PKI.
|
||||
The certificates and keys are located under ``dist/etc/everest/certs``.
|
||||
|
||||
2. Let's prepare the central system that we are going to use. Follow the
|
||||
instructions described here to set it up:
|
||||
https://github.com/EVerest/ocpp-csms
|
||||
|
||||
3. Run EVerest with either OCPP1.6, OCPP2.x using the prepared run-scripts.
|
||||
Make sure the the endpoint ``localhost:9000/<id>`` is specified in the respective
|
||||
ocpp configuration file (OCPP2.x config defaults to this address, while for
|
||||
OCPP1.6 the default is different).
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./run-scripts/run-sil-ocpp201-pnc.sh
|
||||
|
||||
or
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./run-scripts/run-sil-ocpp-pnc.sh
|
||||
|
||||
Make sure Node-RED is running and access the UI on ``localhost:1880/ui``.
|
||||
|
||||
In Node-RED select ``AC ISO 15118-2`` from the Car Simulation dropdown and click "Car Plugin". This will initiate the EV plugin and start the Plug&Charge process.
|
||||
|
||||
Check the EVerest console and OCPP logs. By default OCPP logs are located in ``/tmp/everest_ocpp_logs`` .
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
If you observe logging messages indicating a timeout of the SDP request like
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
2025-10-17 17:21:47.039511 [WARN] iso15118_car pybind11_init_everestpy(pybind11::module_&)::<lambda(const std::string&)> :: A TimeoutError occurred. Waited for Timeouts.SDP_REQ s after sending an SDPRequest
|
||||
|
||||
you may need to adjust your firewall settings to allow communication between
|
||||
the EVCC and SECC modules.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo ip6tables -I INPUT -i <your_network_interface_name> -p udp --dport 15118 -j ACCEPT
|
||||
|
||||
|
||||
----
|
||||
|
||||
**Authors**: Piet Gömpel
|
||||
@@ -0,0 +1,142 @@
|
||||
:title: Managed by devrd CLI
|
||||
|
||||
######################################################
|
||||
Setup Variant: Service Containers Managed by devrd cli
|
||||
######################################################
|
||||
|
||||
This variant utilizes the devrd CLI to manage service containers,
|
||||
making it an ideal choice for users who do not use VSCode.
|
||||
It provides dedicated control of the service containers independent
|
||||
of the devcontainer lifecycle. The devcontainer itself will not start
|
||||
or stop any service containers.
|
||||
|
||||
.. note::
|
||||
|
||||
When using this variant and still using VSCode, the VSCode
|
||||
built-in terminal cannot execute commands directly within the devcontainer.
|
||||
Instead, use the devrd CLI to open an interactive session (see below).
|
||||
|
||||
******************************
|
||||
What to expect from this setup
|
||||
******************************
|
||||
|
||||
If one prefers to run the devcontainer outside VSCode, this setup variant is
|
||||
the right choice.
|
||||
|
||||
The devrd cli will help to manage the service containers independent
|
||||
of the devcontainer lifecycle. So one can start and stop the service containers
|
||||
at any time.
|
||||
The contents of the EVerest repo are mapped inside the container
|
||||
in the directory ``/workspace``.
|
||||
|
||||
*************
|
||||
Prerequisites
|
||||
*************
|
||||
|
||||
To install the prerequisites, please check your operating system or distribution online documentation:
|
||||
|
||||
- Docker installed [#docker]_
|
||||
- Docker compose installed version V2 (not working with V1) [#docker_compose]_
|
||||
|
||||
**************
|
||||
Required Steps
|
||||
**************
|
||||
|
||||
1. **Clone the EVerest repository**
|
||||
|
||||
If you have not done this yet, clone the EVerest repository
|
||||
from GitHub to your local machine:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/EVerest/EVerest.git path/to/EVerest
|
||||
|
||||
Where ``path/to/EVerest`` is the path where you want to
|
||||
clone the repository to.
|
||||
|
||||
2. **Build and start the devcontainer and service containers**
|
||||
|
||||
Change into the cloned repository directory:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd path/to/EVerest
|
||||
|
||||
Then build and start the devcontainer and the service containers
|
||||
with the devrd cli:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd start
|
||||
|
||||
This will build and start the devcontainer and all service containers.
|
||||
If not yet existing, devrd will generate the ``.devcontainer/.env`` file.
|
||||
|
||||
3. **Open an interactive shell in the devcontainer**
|
||||
|
||||
To run commands inside the devcontainer, open an interactive shell
|
||||
with the devrd cli:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd prompt
|
||||
|
||||
This will open an interactive shell inside the devcontainer.
|
||||
The contents of the EVerest repository are mapped
|
||||
to the ``/workspace`` directory inside the container.
|
||||
|
||||
You can now run all development commands inside this shell.
|
||||
|
||||
To exit the shell, simply type ``exit`` or press ``Ctrl+D``.
|
||||
|
||||
See the :doc:`howto </how-to-guides/devcontainer-usage/index>` to learn how to
|
||||
execute EVerest in a SIL using containers.
|
||||
|
||||
*************************************
|
||||
Optional: Install bash/zsh completion
|
||||
*************************************
|
||||
|
||||
If you want to enable completion on your host system follow the steps below.
|
||||
|
||||
Install bash completion
|
||||
-----------------------
|
||||
|
||||
Add the following lines to your ``~/.bashrc`` file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# bash completion for devrd cli
|
||||
source applications/devrd/devrd-completion.bash
|
||||
|
||||
Then reload your ``~/.bashrc`` file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
source ~/.bashrc
|
||||
|
||||
Install zsh completion
|
||||
----------------------
|
||||
|
||||
Add the following lines to your ``~/.zshrc`` file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# zsh completion for devrd cli
|
||||
autoload -U compinit && compinit
|
||||
source applications/devrd/devrd-completion.zsh
|
||||
|
||||
Then reload your ``~/.zshrc`` file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
source ~/.zshrc
|
||||
|
||||
See the :doc:`separate troubleshooting section <troubleshooting>` for help
|
||||
on devcontainer-specific issues.
|
||||
|
||||
----
|
||||
|
||||
**Authors:** Florian Mihut, Andreas Heinrich
|
||||
|
||||
.. [#docker] `<https://docs.docker.com/engine/install/>`_
|
||||
.. [#docker_compose] `<https://docs.docker.com/compose/install>`_
|
||||
@@ -0,0 +1,37 @@
|
||||
#######################################
|
||||
Setup the EVerest Development Container
|
||||
#######################################
|
||||
|
||||
There are two variants for the devcontainer setup:
|
||||
|
||||
.. grid:: 1 2 2 2
|
||||
:gutter: 2
|
||||
|
||||
.. grid-item-card:: Service Containers managed by VSCode
|
||||
:link: /tutorials/setup-devcontainer/vscode
|
||||
:link-type: doc
|
||||
|
||||
Uses the VSCode Dev Containers extension, which manages both
|
||||
the devcontainer and the service containers.
|
||||
|
||||
.. grid-item-card:: Service Containers managed by devrd cli
|
||||
:link: /tutorials/setup-devcontainer/devrd
|
||||
:link-type: doc
|
||||
|
||||
Uses the devrd cli to manage the service containers.
|
||||
This variant can be used if one is not using VSCode or needs dedicated
|
||||
control over the service containers.
|
||||
|
||||
Also consider these documents:
|
||||
|
||||
- :doc:`troubleshooting section <troubleshooting>` that deals for devcontainer-specific issues.
|
||||
- :doc:`How-to Guide: How to use a development container for EVerest development and sil testing </how-to-guides/devcontainer-usage/index>`
|
||||
- :doc:`Internals of the EVerest Development Container </explanation/devcontainer-internal/index>`
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
Managed by devrd CLI <devrd>
|
||||
Managed by VSCode <vscode>
|
||||
troubleshooting
|
||||
@@ -0,0 +1,110 @@
|
||||
###############
|
||||
Troubleshooting
|
||||
###############
|
||||
|
||||
Port conflicts
|
||||
--------------
|
||||
|
||||
Each instance uses the same ports (1883, 1880, 4000, etc.). Please note that only one instance can run at a time.
|
||||
If another process is using the port you need here is how to detect it and make it available:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
sudo lsof -ti:1880 \| xargs sudo kill -9
|
||||
./applications/devrd/devrd start
|
||||
|
||||
If a system service is using a port (e.g. mosquitto) stopping/disabling this service may be required.
|
||||
|
||||
Regenerate environment configuration
|
||||
------------------------------------
|
||||
|
||||
If you suspect that the environment variables in the ``.env`` file
|
||||
are not correct, you can regenerate it with:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd env
|
||||
|
||||
Customize environment variables
|
||||
--------------------------------
|
||||
|
||||
To customize specific environment variables, you can edit the
|
||||
``.devcontainer/.env`` file directly or pass them as arguments to the ``./applications/devrd/devrd env`` command.
|
||||
|
||||
.. note::
|
||||
|
||||
If you manually edit the ``.env`` file and change ``EVEREST_TOOL_BRANCH``
|
||||
or other build arguments, you must rebuild the container for changes to take effect:
|
||||
|
||||
Rebuild devrd setup
|
||||
-------------------
|
||||
|
||||
The setup can be rebuild with:
|
||||
|
||||
Option 1: Force rebuild (recommended)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd env # Regenerate .env if you edited it manually
|
||||
./applications/devrd/devrd build # Rebuild with new environment variables
|
||||
|
||||
Option 2: Clean rebuild (if rebuild doesn't work)
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd stop # Stop all containers, images, and volumes
|
||||
./applications/devrd/devrd purge # Remove all containers, images, and volumes
|
||||
./applications/devrd/devrd build # Rebuild from scratch
|
||||
|
||||
|
||||
Purge and rebuild devrd setup
|
||||
-----------------------------
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd purge # Remove all resources for current folder
|
||||
./applications/devrd/devrd build # Will generate .env if missing
|
||||
|
||||
|
||||
Volume conflicts
|
||||
----------------
|
||||
|
||||
Docker volumes are shared. Use
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./applications/devrd/devrd purge
|
||||
|
||||
before switching instances.
|
||||
|
||||
SSH keys
|
||||
--------
|
||||
|
||||
Ensure your SSH agent has the necessary keys for all repositories.
|
||||
|
||||
Container naming
|
||||
----------------
|
||||
|
||||
Docker containers are named based on the workspace directory to avoid conflicts.
|
||||
|
||||
Switching between instances
|
||||
---------------------------
|
||||
|
||||
When switching between different EVerest instances (e.g., different branches or forks),
|
||||
use the following commands:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Stop current instance
|
||||
./applications/devrd/devrd stop
|
||||
|
||||
# Purge if switching to different branch/project
|
||||
./applications/devrd/devrd purge
|
||||
|
||||
# Start new instance
|
||||
cd ~/different-everest-directory
|
||||
./applications/devrd/devrd start
|
||||
|
||||
----
|
||||
|
||||
**Authors:** Florian Mihut, Andreas Heinrich
|
||||
@@ -0,0 +1,109 @@
|
||||
:title: Managed by VSCode
|
||||
|
||||
###################################################
|
||||
Setup Variant: Service Containers Managed by VSCode
|
||||
###################################################
|
||||
|
||||
This variant makes use of the VSCode Dev Containers extension [#vscode_devcontainter]_
|
||||
.
|
||||
This will allow to run commands in the VSCode built-in terminal.
|
||||
It will manage the service containers by starting them together with
|
||||
the `devcontainer` itself. Dedicated control of individual services
|
||||
is not possible with this variant.
|
||||
|
||||
******************************
|
||||
What to expect from this setup
|
||||
******************************
|
||||
|
||||
By following the steps in this tutorial you will setup a development
|
||||
environment for EVerest using a development container (devcontainer).
|
||||
VSCode will automatically build the container. After this all development
|
||||
happens inside the container.
|
||||
|
||||
The contents of the EVerest repo are mapped inside the container
|
||||
in the directory ``/workspace``
|
||||
You can exit VSCode at any time, re-running it will cause VSCode to ask you
|
||||
again to reopen in container.
|
||||
|
||||
Opening the EVerest repository in the VSCode devcontainer will
|
||||
automatically start all of the provided service containers.
|
||||
|
||||
*************
|
||||
Prerequisites
|
||||
*************
|
||||
|
||||
To install the prerequisites, please check your operating system or distribution online documentation:
|
||||
|
||||
- Docker installed [#docker]_
|
||||
- Docker compose installed version V2 (not working with V1) [#docker_compose]_
|
||||
- VS Code with Dev Containers extension installed [#vscode_devcontainter]_
|
||||
|
||||
**************
|
||||
Required Steps
|
||||
**************
|
||||
|
||||
1. **Clone the EVerest repository**
|
||||
|
||||
If you have not done this yet, clone the EVerest repository
|
||||
from GitHub to your local machine:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/EVerest/EVerest.git path/to/EVerest
|
||||
|
||||
Where ``path/to/EVerest`` is the path where you want to
|
||||
clone the repository to.
|
||||
|
||||
2. **Open in VSCode**
|
||||
|
||||
Then open this repository in VSCode:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
code path/to/EVerest
|
||||
|
||||
Choose **Reopen in container** when prompted by VSCode.
|
||||
|
||||
Now VSCode will build the devcontainer.
|
||||
This can take some time depending on your machine and internet connection.
|
||||
After this you can use the built-in terminal in VSCode to run commands
|
||||
inside the devcontainer as for example to build EVerest.
|
||||
|
||||
*************
|
||||
Example Usage
|
||||
*************
|
||||
|
||||
You can now use VSCode's terminal to issue commands inside the devcontainer, e.g. for building:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker@16898a21b4f1:/workspace$ mkdir build
|
||||
docker@16898a21b4f1:/workspace$ cd build
|
||||
docker@16898a21b4f1:/workspace$ cmake ..
|
||||
docker@16898a21b4f1:/workspace$ cmake --build . --parallel 8
|
||||
|
||||
This will readily build EVerest regardless of your host system setup.
|
||||
|
||||
****************************************
|
||||
Tips for VSCode Dev Containers Extension
|
||||
****************************************
|
||||
|
||||
When the repository is opened in VSCode you can enter the devcontainer at
|
||||
any time by running the command **Dev Containers: Reopen in Container** from the
|
||||
command palette (F1).
|
||||
You can also stop the devcontainer by running the command **Dev Containers: Reopen Folder Locally**.
|
||||
|
||||
***************
|
||||
Troubleshooting
|
||||
***************
|
||||
|
||||
See the :doc:`separate troubleshooting section <troubleshooting>` for help
|
||||
on devcontainer-specific issues.
|
||||
|
||||
----
|
||||
|
||||
**Authors:** Florian Mihut, Andreas Heinrich
|
||||
|
||||
.. [#docker] `<https://docs.docker.com/engine/install/>`_
|
||||
.. [#docker_compose] `<https://docs.docker.com/compose/install>`_
|
||||
.. [#vscode_devcontainter] `<https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers>`_
|
||||
Reference in New Issue
Block a user