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:
@@ -0,0 +1,33 @@
|
||||
# EVerest Boot Mode Application Logic
|
||||
|
||||
The `manager` process retrieves the EVerest configuration, manages module dependencies and communication, and starts EVerest modules as individual processes.
|
||||
|
||||
The EVerest configuration can be provided via a YAML file, an SQLite database, or both. This section explains how EVerest starts up depending on the CLI options used:
|
||||
|
||||
- `--config`: Full path to the EVerest YAML configuration file.
|
||||
- `--db`: Full path to the EVerest SQLite configuration database.
|
||||
- `--db-init`: Indicates that the specified config should be used to initialize the database if it does not exist or does not contain a valid configuration.
|
||||
|
||||
Based on these options, there are three possible boot modes:
|
||||
|
||||
- **YAML Boot Mode**: The configuration is loaded from a YAML file. This mode is used when only the `--config` argument is provided.
|
||||
- **Database Boot Mode**: The configuration is loaded from an SQLite database. This mode is used when only the `--db` argument is provided.
|
||||
- **DatabaseInit Boot Mode**: The configuration is preferably loaded from an SQLite database. If the database does not exist or does not contain a valid EVerest configuration, the YAML file specified by `--config` is used instead, and the configuration is then written to the database. This mode requires all three options: `--config`, `--db`, and `--db-init`. In a subsequent start of the application, the database can be used to retrieve
|
||||
the configuration.
|
||||
|
||||
## Boot Mode Application Logic Flow Chart
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
A[Start] --> B[Parse CLI arguments]
|
||||
|
||||
B --> C{--config provided}
|
||||
C -->|yes| D{--db provided}
|
||||
D -->|yes| E{--db-init provided}
|
||||
E -->|yes| F[Boot Mode: DatabaseInit]
|
||||
E -->|no| H[Invalid combination]
|
||||
D -->|no| J[Boot Mode: YAML]
|
||||
C -->|no| L{--db provided}
|
||||
L -->|yes| M[Boot Mode: Database]
|
||||
L -->|no| O[Invalid combination]
|
||||
```
|
||||
@@ -0,0 +1,134 @@
|
||||
# EVerest Framework MQTT Topic Structure
|
||||
|
||||
This document describes the MQTT topic structure used by the EVerest framework for communication between modules.
|
||||
|
||||
## Topic Prefix Structure
|
||||
|
||||
The EVerest framework uses a configurable MQTT prefixes for topics. This allows multiple instances of EVerest
|
||||
to run at the same time using the same broker. The default prefix is `everest`.
|
||||
|
||||
## 1. Variables (Vars)
|
||||
|
||||
The following structure applies for variable topics:
|
||||
|
||||
### Topic Structure
|
||||
|
||||
```bash
|
||||
{everest_prefix}modules/{module_id}/impl/{impl_id}/var/{var_name}
|
||||
```
|
||||
|
||||
### Message Payload Structure
|
||||
|
||||
The payload contains the actual variable data in the `data` field.
|
||||
|
||||
```json
|
||||
{
|
||||
"data": <variable_value>
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Commands (Cmds)
|
||||
|
||||
The following structure applies for command topics. Modules that provide (implement) the command subscribe to the command topic, while modules that call the command publish to it. Each command call generates a unique UUID as the call ID. The origin field identifies the calling module. Command handlers process the request and publish responses to a separate response topic.
|
||||
|
||||
### Topic Structure
|
||||
|
||||
```bash
|
||||
{everest_prefix}modules/{module_id}/impl/{impl_id}/cmd/{cmd_name}
|
||||
```
|
||||
|
||||
### Message Payload Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "<unique_call_id>",
|
||||
"args": {
|
||||
"arg1": "value1",
|
||||
"arg2": "value2"
|
||||
},
|
||||
"origin": "<calling_module_id>"
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Command Responses
|
||||
|
||||
The following structure applies for command response topics. These are used to send back results or errors from command handlers to the calling module. Response topics include the calling module ID for proper routing. The call ID matches the original command request.
|
||||
|
||||
### Topic Structure
|
||||
|
||||
```bash
|
||||
{everest_prefix}modules/{module_id}/impl/{impl_id}/cmd/{cmd_name}/response/{calling_module_id}
|
||||
```
|
||||
|
||||
### Message Payload Structure
|
||||
|
||||
#### Successful Response
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "<cmd_name>",
|
||||
"type": "result",
|
||||
"data": {
|
||||
"id": "<matching_call_id>",
|
||||
"retval": <return_value>,
|
||||
"origin": "<responding_module_id>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Error Response
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "<cmd_name>",
|
||||
"type": "result",
|
||||
"data": {
|
||||
"id": "<matching_call_id>",
|
||||
"error": {
|
||||
"event": "<error_type>",
|
||||
"msg": "<error_message>"
|
||||
},
|
||||
"origin": "<responding_module_id>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Types
|
||||
|
||||
Command responses can contain the following error events:
|
||||
|
||||
- `MessageParsingFailed`: JSON parsing error
|
||||
- `SchemaValidationFailed`: Schema validation error
|
||||
- `HandlerException`: Exception in command handler
|
||||
- `Timeout`: Command execution timeout
|
||||
- `Shutdown`: System shutdown
|
||||
- `NotReady`: Module not ready
|
||||
|
||||
## 4. Errors
|
||||
|
||||
The following structure applies for error topics. Errors are raised by modules and can be subscribed to by other modules. Each error has a unique UUID and includes information about the originating module, implementation, EVSE, and connector if applicable.
|
||||
|
||||
### Topic Structure
|
||||
|
||||
```bash
|
||||
{everest_prefix}modules/{module_id}/impl/{impl_id}/error/{error_type}
|
||||
```
|
||||
|
||||
### Message Payload Structure
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "<error_namespace>/<error_name>",
|
||||
"message": "<error_description>",
|
||||
"severity": "<error_severity>",
|
||||
"origin": {
|
||||
"module_id": "<originating_module>",
|
||||
"implementation_id": "<originating_impl>",
|
||||
"evse": <evse_number>,
|
||||
"connector": <connector_number>
|
||||
},
|
||||
"state": "<error_state>",
|
||||
"timestamp": "<iso_timestamp>",
|
||||
"uuid": "<unique_error_id>"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,120 @@
|
||||
# Module configuration distributed via MQTT
|
||||
|
||||
Since everest-framework 0.19.0 the module configuration is parsed once
|
||||
by the manager and then distributed to the modules via MQTT.
|
||||
This is achieved by parsing the MQTT settings from the config,
|
||||
spawning the modules and passing these MQTT settings to them.
|
||||
The modules themselves then ask for their module config via MQTT,
|
||||
which is in turn provided to them from the manager.
|
||||
After the modules have received their config, their init() function is called.
|
||||
Afterwards they signal ready to the manager.
|
||||
The manager sends out the global ready signal
|
||||
once it has received all Module ready signals.
|
||||
|
||||
The following sequence diagram illustrates this startup process
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
create participant manager
|
||||
create participant ManagerSettings
|
||||
manager-)ManagerSettings: ManagerSettings(prefix, config_path)
|
||||
ManagerSettings-->>manager: return ms
|
||||
create participant ManagerConfig
|
||||
manager-)ManagerConfig: ManagerConfig(ms)
|
||||
create participant MQTTAbstraction
|
||||
manager-)MQTTAbstraction: MQTTAbstraction(ms.mqtt_settings)
|
||||
MQTTAbstraction-->>manager: return mqtt_abstraction
|
||||
activate manager
|
||||
manager->>manager: start_modules()
|
||||
manager->>ManagerConfig: serialize()
|
||||
ManagerConfig-->>manager: serialized_config
|
||||
manager->>MQTTAbstraction: publish(interfaces, types, schemas, manifests, settings, retain=true)
|
||||
loop For every module
|
||||
manager->>manager: spawn_modules(Module)
|
||||
create participant Module
|
||||
manager->>Module: spawn Module
|
||||
Module->>MQTTAbstraction: get(Config)
|
||||
MQTTAbstraction->>manager: get(Config of Module)
|
||||
manager-->>MQTTAbstraction: publish(module configs, mappings)
|
||||
MQTTAbstraction-->>Module: publish(module configs, mappings)
|
||||
Module->>Module: init
|
||||
Module->>MQTTAbstraction: publish(ready)
|
||||
MQTTAbstraction->>manager: publish(ready of Module)
|
||||
end
|
||||
manager->>MQTTAbstraction: publish global ready
|
||||
```
|
||||
|
||||
Class diagram
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
ConfigBase <|-- ManagerConfig
|
||||
ConfigBase <|-- Config
|
||||
MQTTSettings *-- ConfigBase
|
||||
ManagerSettings *-- ManagerConfig
|
||||
|
||||
note for ConfigBase "
|
||||
Baseclass containing json config, manifests, interfaces,
|
||||
types and functions to access this information which
|
||||
needs to be available in all derived classes
|
||||
"
|
||||
|
||||
class ManagerSettings{
|
||||
+fs::path configs_dir
|
||||
+fs::path schemas_dir
|
||||
+fs::path interfaces_dir
|
||||
+fs::path types_dir
|
||||
+fs::path errors_dir
|
||||
+fs::path config_file
|
||||
+fs::path www_dir
|
||||
+int controller_port
|
||||
+int controller_rpc_timeout_ms
|
||||
+std::string run_as_user
|
||||
+std::string version_information
|
||||
+nlohmann::json config
|
||||
+MQTTSettings mqtt_settings
|
||||
+std::unique_ptr<RuntimeSettings> runtime_settings
|
||||
+ManagerSettings(const std::string& prefix, const std::string& config)
|
||||
+const RuntimeSettings& get_runtime_settings()
|
||||
}
|
||||
|
||||
class MQTTSettings{
|
||||
+std::string broker_socket_path
|
||||
+std::string broker_host
|
||||
+int broker_port
|
||||
+std::string everest_prefix
|
||||
+std::string external_prefix
|
||||
+bool uses_socket()
|
||||
}
|
||||
|
||||
class ConfigBase{
|
||||
#const MQTTSettings mqtt_settings
|
||||
+ConfigBase(const MQTTSettings& mqtt_settings)
|
||||
}
|
||||
|
||||
class ManagerConfig{
|
||||
-const ManagerSettings& ms
|
||||
+ManagerConfig(const ManagerSettings& ms)
|
||||
+nlohmann::json serialize()
|
||||
-load_and_validate_manifest(const std::string& module_id, const nlohmann::json& module_config)
|
||||
-std::tuple~nlohmann::json, int64_t~ load_and_validate_with_schema(const fs::path& file_path, const nlohmann::json& schema)
|
||||
-nlohmann::json resolve_interface(const std::string& intf_name)
|
||||
-nlohmann::json load_interface_file(const std::string& intf_name)
|
||||
-resolve_all_requirements()
|
||||
-parse(nlohmann::json config)
|
||||
}
|
||||
|
||||
class Config{
|
||||
+Config(const MQTTSettings& mqtt_settings, nlohmann::json config)
|
||||
+bool module_provides(const std::string& module_name, const std::string& impl_id);
|
||||
+nlohmann::json get_module_cmds(const std::string& module_name, const std::string& impl_id)
|
||||
+nlohmann::json resolve_requirement(const std::string& module_id, const std::string& requirement_id)
|
||||
+std::list~Requirement~ get_requirements(const std::string& module_id)
|
||||
+RequirementInitialization get_requirement_initialization(const std::string& module_id)
|
||||
+ModuleConfigs get_module_configs(const std::string& module_id)
|
||||
+nlohmann::json get_module_json_config(const std::string& module_id)
|
||||
+ModuleInfo get_module_info(const std::string& module_id)
|
||||
+std::optional~<~TelemetryConfig~ get_telemetry_config()
|
||||
+nlohmann::json get_interface_definition(const std::string& interface_name) const;
|
||||
}
|
||||
```
|
||||
3
tools/EVerest-main/lib/everest/framework/docs/README.md
Normal file
3
tools/EVerest-main/lib/everest/framework/docs/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Additional documentation about the inner workings of EVerest Framework
|
||||
|
||||
[MQTT Config distribution](MQTTConfigDistribution.md)
|
||||
Reference in New Issue
Block a user