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,162 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <device_model/composed_device_model_storage.hpp>
|
||||
|
||||
static constexpr auto VARIABLE_SOURCE_OCPP = "OCPP";
|
||||
|
||||
namespace module::device_model {
|
||||
|
||||
bool ComposedDeviceModelStorage::register_device_model_storage(
|
||||
std::string device_model_storage_id, std::shared_ptr<ocpp::v2::DeviceModelStorageInterface> device_model_storage) {
|
||||
if (this->device_model_storages.find(device_model_storage_id) != this->device_model_storages.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto device_model_map = device_model_storage->get_device_model();
|
||||
// store the sources of each variable to be able to lookup requests to the device model storage
|
||||
for (const auto& [component, variable_map] : device_model_map) {
|
||||
for (const auto& [variable, variable_meta] : variable_map) {
|
||||
// check if component variable source is already exist in the map
|
||||
if (this->component_variable_source_map.find(component) != this->component_variable_source_map.end() &&
|
||||
this->component_variable_source_map.at(component).find(variable) !=
|
||||
this->component_variable_source_map.at(component).end()) {
|
||||
EVLOG_warning << "Component variable source already exists for component: " << component.name
|
||||
<< ", variable: " << variable.name << ". Fix your device model configuration.";
|
||||
}
|
||||
|
||||
// Note: Source should not be optional, should be changed in libocpp
|
||||
this->component_variable_source_map[component][variable] =
|
||||
variable_meta.source.value_or(VARIABLE_SOURCE_OCPP);
|
||||
}
|
||||
}
|
||||
|
||||
this->device_model_storages[device_model_storage_id] = device_model_storage;
|
||||
return true;
|
||||
}
|
||||
|
||||
ocpp::v2::DeviceModelMap ComposedDeviceModelStorage::get_device_model() {
|
||||
ocpp::v2::DeviceModelMap device_model_map;
|
||||
for (const auto& [name, device_model_storage] : this->device_model_storages) {
|
||||
device_model_map.merge(device_model_storage->get_device_model());
|
||||
}
|
||||
return device_model_map;
|
||||
}
|
||||
|
||||
std::optional<ocpp::v2::VariableAttribute>
|
||||
ComposedDeviceModelStorage::get_variable_attribute(const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum) {
|
||||
const auto variable_source = get_variable_source(component_id, variable_id);
|
||||
if (this->device_model_storages.find(variable_source) == this->device_model_storages.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
return this->device_model_storages.at(variable_source)
|
||||
->get_variable_attribute(component_id, variable_id, attribute_enum);
|
||||
}
|
||||
|
||||
std::vector<ocpp::v2::VariableAttribute>
|
||||
ComposedDeviceModelStorage::get_variable_attributes(const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id,
|
||||
const std::optional<ocpp::v2::AttributeEnum>& attribute_enum) {
|
||||
const auto variable_source = get_variable_source(component_id, variable_id);
|
||||
if (this->device_model_storages.find(variable_source) == this->device_model_storages.end()) {
|
||||
return {};
|
||||
}
|
||||
return this->device_model_storages.at(variable_source)
|
||||
->get_variable_attributes(component_id, variable_id, attribute_enum);
|
||||
}
|
||||
|
||||
ocpp::v2::SetVariableStatusEnum ComposedDeviceModelStorage::set_variable_attribute_value(
|
||||
const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum, const std::string& value, const std::string& source) {
|
||||
// the "source" parameter is the VALUE_SOURCE
|
||||
const auto variable_source = get_variable_source(component_id, variable_id);
|
||||
if (this->device_model_storages.find(variable_source) == this->device_model_storages.end()) {
|
||||
return ocpp::v2::SetVariableStatusEnum::Rejected;
|
||||
}
|
||||
return this->device_model_storages.at(variable_source)
|
||||
->set_variable_attribute_value(component_id, variable_id, attribute_enum, value, source);
|
||||
}
|
||||
|
||||
std::optional<ocpp::v2::VariableMonitoringMeta>
|
||||
ComposedDeviceModelStorage::set_monitoring_data(const ocpp::v2::SetMonitoringData& data,
|
||||
const ocpp::v2::VariableMonitorType type) {
|
||||
if (this->device_model_storages.find(VARIABLE_SOURCE_OCPP) == this->device_model_storages.end()) {
|
||||
EVLOG_error << "OCPP device model storage not registered, cannot set monitoring data";
|
||||
return std::nullopt;
|
||||
}
|
||||
return this->device_model_storages.at(VARIABLE_SOURCE_OCPP)->set_monitoring_data(data, type);
|
||||
}
|
||||
|
||||
bool ComposedDeviceModelStorage::update_monitoring_reference(const int32_t monitor_id,
|
||||
const std::string& reference_value) {
|
||||
if (this->device_model_storages.find(VARIABLE_SOURCE_OCPP) == this->device_model_storages.end()) {
|
||||
EVLOG_error << "OCPP device model storage not registered, cannot update monitoring reference";
|
||||
return false;
|
||||
}
|
||||
return this->device_model_storages.at(VARIABLE_SOURCE_OCPP)
|
||||
->update_monitoring_reference(monitor_id, reference_value);
|
||||
}
|
||||
|
||||
std::vector<ocpp::v2::VariableMonitoringMeta>
|
||||
ComposedDeviceModelStorage::get_monitoring_data(const std::vector<ocpp::v2::MonitoringCriterionEnum>& criteria,
|
||||
const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id) {
|
||||
const auto variable_source = get_variable_source(component_id, variable_id);
|
||||
if (this->device_model_storages.find(variable_source) == this->device_model_storages.end()) {
|
||||
return {};
|
||||
}
|
||||
return this->device_model_storages.at(variable_source)->get_monitoring_data(criteria, component_id, variable_id);
|
||||
}
|
||||
|
||||
ocpp::v2::ClearMonitoringStatusEnum ComposedDeviceModelStorage::clear_variable_monitor(int monitor_id,
|
||||
bool allow_protected) {
|
||||
if (this->device_model_storages.find(VARIABLE_SOURCE_OCPP) == this->device_model_storages.end()) {
|
||||
EVLOG_error << "OCPP device model storage not registered, cannot clear variable monitor";
|
||||
return ocpp::v2::ClearMonitoringStatusEnum::Rejected;
|
||||
}
|
||||
return this->device_model_storages.at(VARIABLE_SOURCE_OCPP)->clear_variable_monitor(monitor_id, allow_protected);
|
||||
}
|
||||
|
||||
int32_t ComposedDeviceModelStorage::clear_custom_variable_monitors() {
|
||||
if (this->device_model_storages.find(VARIABLE_SOURCE_OCPP) == this->device_model_storages.end()) {
|
||||
EVLOG_error << "OCPP device model storage not registered, cannot clear custom variable monitors";
|
||||
return 0;
|
||||
}
|
||||
return this->device_model_storages.at(VARIABLE_SOURCE_OCPP)->clear_custom_variable_monitors();
|
||||
}
|
||||
|
||||
void ComposedDeviceModelStorage::check_integrity() {
|
||||
for (const auto& [name, device_model_storage] : this->device_model_storages) {
|
||||
device_model_storage->check_integrity();
|
||||
}
|
||||
}
|
||||
|
||||
bool ComposedDeviceModelStorage::create_network_configuration_slot_from_default_schema(std::int32_t new_slot) {
|
||||
// NetworkConfiguration_<N> components live in the OCPP-source storage (the SQLite-backed
|
||||
// EverestDeviceModelStorage). Without this dispatch, libocpp's blob-migration fallback hits
|
||||
// DeviceModelStorageInterface's default virtual (returns false) and the operator's
|
||||
// NetworkConnectionProfiles blob ends up cleared without ever populating the per-slot
|
||||
// device-model rows on targets that ship no NetworkConfiguration_<N>.json.
|
||||
const auto it = this->device_model_storages.find(VARIABLE_SOURCE_OCPP);
|
||||
if (it == this->device_model_storages.end()) {
|
||||
EVLOG_error << "OCPP device model storage not registered, cannot create NetworkConfiguration_" << new_slot;
|
||||
return false;
|
||||
}
|
||||
return it->second->create_network_configuration_slot_from_default_schema(new_slot);
|
||||
}
|
||||
|
||||
std::string module::device_model::ComposedDeviceModelStorage::get_variable_source(const ocpp::v2::Component& component,
|
||||
const ocpp::v2::Variable& variable) {
|
||||
if (this->component_variable_source_map.find(component) == this->component_variable_source_map.end()) {
|
||||
return VARIABLE_SOURCE_OCPP; // default source
|
||||
}
|
||||
const auto& variable_map = this->component_variable_source_map.at(component);
|
||||
if (variable_map.find(variable) == variable_map.end()) {
|
||||
return VARIABLE_SOURCE_OCPP; // default source
|
||||
}
|
||||
return variable_map.at(variable);
|
||||
}
|
||||
|
||||
} // namespace module::device_model
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <device_model/everest_device_model_storage.hpp>
|
||||
#include <ocpp/v2/device_model_storage_interface.hpp>
|
||||
#include <ocpp/v2/device_model_storage_sqlite.hpp>
|
||||
|
||||
namespace module::device_model {
|
||||
|
||||
using ComponentVariableSourceMap = std::map<ocpp::v2::Component, std::map<ocpp::v2::Variable, std::string>>;
|
||||
class ComposedDeviceModelStorage : public ocpp::v2::DeviceModelStorageInterface {
|
||||
private:
|
||||
std::map<std::string, std::shared_ptr<ocpp::v2::DeviceModelStorageInterface>>
|
||||
device_model_storages; // key is identifier for the device model storage
|
||||
ComponentVariableSourceMap component_variable_source_map;
|
||||
|
||||
public:
|
||||
ComposedDeviceModelStorage() = default;
|
||||
|
||||
/// \brief Register a device model storage.
|
||||
/// \param device_model_storage_id The id of the device model storage. Component variable combinations can be
|
||||
/// used to map to this id to identify which device model is adressed for certain requests.
|
||||
/// \param device_model_storage The device model storage to register.
|
||||
/// \return True if the device model storage name is not yet registered, false otherwise.
|
||||
bool register_device_model_storage(std::string device_model_storage_id,
|
||||
std::shared_ptr<ocpp::v2::DeviceModelStorageInterface> device_model_storage);
|
||||
virtual ~ComposedDeviceModelStorage() override = default;
|
||||
virtual ocpp::v2::DeviceModelMap get_device_model() override;
|
||||
virtual std::optional<ocpp::v2::VariableAttribute>
|
||||
get_variable_attribute(const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum) override;
|
||||
virtual std::vector<ocpp::v2::VariableAttribute>
|
||||
get_variable_attributes(const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id,
|
||||
const std::optional<ocpp::v2::AttributeEnum>& attribute_enum) override;
|
||||
virtual ocpp::v2::SetVariableStatusEnum set_variable_attribute_value(const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum,
|
||||
const std::string& value,
|
||||
const std::string& source) override;
|
||||
virtual std::optional<ocpp::v2::VariableMonitoringMeta>
|
||||
set_monitoring_data(const ocpp::v2::SetMonitoringData& data, const ocpp::v2::VariableMonitorType type) override;
|
||||
virtual bool update_monitoring_reference(const int32_t monitor_id, const std::string& reference_value) override;
|
||||
virtual std::vector<ocpp::v2::VariableMonitoringMeta>
|
||||
get_monitoring_data(const std::vector<ocpp::v2::MonitoringCriterionEnum>& criteria,
|
||||
const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id) override;
|
||||
virtual ocpp::v2::ClearMonitoringStatusEnum clear_variable_monitor(int monitor_id, bool allow_protected) override;
|
||||
virtual int32_t clear_custom_variable_monitors() override;
|
||||
virtual void check_integrity() override;
|
||||
virtual bool create_network_configuration_slot_from_default_schema(std::int32_t new_slot) override;
|
||||
|
||||
private:
|
||||
///
|
||||
/// \brief Get variable source of given variable.
|
||||
/// \param component Component the variable belongs to.
|
||||
/// \param variable The variable to get the source from.
|
||||
/// \return The variable source. Defaults to 'OCPP'.
|
||||
///
|
||||
std::string get_variable_source(const ocpp::v2::Component& component, const ocpp::v2::Variable& variable);
|
||||
};
|
||||
} // namespace module::device_model
|
||||
@@ -0,0 +1,224 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <device_model/definitions.hpp>
|
||||
#include <optional>
|
||||
|
||||
#include <ocpp/v2/ocpp_types.hpp>
|
||||
|
||||
using ocpp::CiString;
|
||||
using ocpp::v2::DataEnum;
|
||||
|
||||
namespace EvseDefinitions {
|
||||
|
||||
EVSE get_evse(const int32_t evse_id, const std::optional<int32_t>& connector_id) {
|
||||
EVSE evse;
|
||||
evse.id = evse_id;
|
||||
evse.connectorId = connector_id;
|
||||
return evse;
|
||||
}
|
||||
|
||||
namespace Characteristics {
|
||||
|
||||
const VariableCharacteristics AllowReset = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics AvailabilityState = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::OptionList;
|
||||
var.supportsMonitoring = false;
|
||||
var.valuesList = CiString<1000>("Available,Occupied,Reserved,Unavailable,Faulted");
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics Available = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics EvseId = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
VariableCharacteristics EVSEPower = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::decimal;
|
||||
var.supportsMonitoring = false;
|
||||
var.unit = CiString<16>("W");
|
||||
var.maxLimit = 0.0f; // will be updated at runtime
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics SupplyPhases = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::integer;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics ISO15118EvseId = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
var.minLimit = 7.0f;
|
||||
var.maxLimit = 37.0f;
|
||||
return var;
|
||||
}();
|
||||
} // namespace Characteristics
|
||||
} // namespace EvseDefinitions
|
||||
|
||||
namespace ConnectorDefinitions {
|
||||
namespace Characteristics {
|
||||
|
||||
const VariableCharacteristics AvailabilityState = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::OptionList;
|
||||
var.supportsMonitoring = false;
|
||||
var.valuesList = CiString<1000>("Available,Occupied,Reserved,Unavailable,Faulted");
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics Available = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics ConnectorType = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics SupplyPhases = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::integer;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
} // namespace Characteristics
|
||||
} // namespace ConnectorDefinitions
|
||||
|
||||
namespace V2XDefinitions {
|
||||
namespace Characteristics {
|
||||
const VariableCharacteristics Available = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics Enabled = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics SupportedEnergyTransferModes = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::MemberList;
|
||||
var.supportsMonitoring = false;
|
||||
var.valuesList =
|
||||
"AC_single_phase,AC_two_phase,AC_three_phase,DC,AC_BPT,AC_BPT_DER,AC_DER,DC_BPT,DC_ACDP,DC_ACDP_BPT,WPT";
|
||||
return var;
|
||||
}();
|
||||
|
||||
const VariableCharacteristics SupportedOperationModes = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::MemberList;
|
||||
var.supportsMonitoring = false;
|
||||
var.valuesList = "Idle,ChargingOnly,CentralSetpoint,ExternalSetpoint,ExternalLimits,CentralFrequency,"
|
||||
"LocalFrequency,LocalLoadBalancing";
|
||||
return var;
|
||||
}();
|
||||
|
||||
} // namespace Characteristics
|
||||
} // namespace V2XDefinitions
|
||||
|
||||
namespace ISO15118Definitions {
|
||||
namespace Characteristics {
|
||||
const VariableCharacteristics Enabled = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics ServiceRenegotiationSupport = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics ProtocolSupported = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
} // namespace Characteristics
|
||||
} // namespace ISO15118Definitions
|
||||
|
||||
namespace ConnectedEVDefinitions {
|
||||
namespace Characteristics {
|
||||
const VariableCharacteristics Available = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::boolean;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics VehicleId = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics ProtocolAgreed = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics VehicleCertificateLeaf = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics VehicleCertificateSubCa1 = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics VehicleCertificateSubCa2 = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics VehicleCertificateRoot = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
const VariableCharacteristics ProtocolSupportedByEV = [] {
|
||||
VariableCharacteristics var;
|
||||
var.dataType = DataEnum::string;
|
||||
var.supportsMonitoring = false;
|
||||
return var;
|
||||
}();
|
||||
} // namespace Characteristics
|
||||
} // namespace ConnectedEVDefinitions
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <ocpp/v2/ctrlr_component_variables.hpp>
|
||||
|
||||
using ocpp::v2::EVSE;
|
||||
using ocpp::v2::VariableCharacteristics;
|
||||
|
||||
namespace EvseDefinitions {
|
||||
|
||||
EVSE get_evse(const int32_t evse_id, const std::optional<int32_t>& connector_id = std::nullopt);
|
||||
|
||||
namespace Characteristics {
|
||||
extern const VariableCharacteristics AllowReset;
|
||||
extern const VariableCharacteristics AvailabilityState;
|
||||
extern const VariableCharacteristics Available;
|
||||
extern const VariableCharacteristics EvseId;
|
||||
extern VariableCharacteristics EVSEPower;
|
||||
extern const VariableCharacteristics SupplyPhases;
|
||||
extern const VariableCharacteristics ISO15118EvseId;
|
||||
} // namespace Characteristics
|
||||
} // namespace EvseDefinitions
|
||||
|
||||
namespace ConnectorDefinitions {
|
||||
namespace Characteristics {
|
||||
extern const VariableCharacteristics AvailabilityState;
|
||||
extern const VariableCharacteristics Available;
|
||||
extern const VariableCharacteristics ConnectorType;
|
||||
extern const VariableCharacteristics SupplyPhases;
|
||||
} // namespace Characteristics
|
||||
} // namespace ConnectorDefinitions
|
||||
|
||||
namespace V2XDefinitions {
|
||||
namespace Characteristics {
|
||||
extern const VariableCharacteristics Available;
|
||||
extern const VariableCharacteristics Enabled;
|
||||
extern const VariableCharacteristics SupportedEnergyTransferModes;
|
||||
extern const VariableCharacteristics SupportedOperationModes;
|
||||
} // namespace Characteristics
|
||||
} // namespace V2XDefinitions
|
||||
|
||||
namespace ISO15118Definitions {
|
||||
namespace Characteristics {
|
||||
extern const VariableCharacteristics Enabled;
|
||||
extern const VariableCharacteristics ServiceRenegotiationSupport;
|
||||
extern const VariableCharacteristics ProtocolSupported;
|
||||
} // namespace Characteristics
|
||||
} // namespace ISO15118Definitions
|
||||
|
||||
namespace ConnectedEVDefinitions {
|
||||
namespace Characteristics {
|
||||
extern const VariableCharacteristics Available;
|
||||
extern const VariableCharacteristics VehicleId;
|
||||
extern const VariableCharacteristics ProtocolAgreed;
|
||||
extern const VariableCharacteristics VehicleCertificateLeaf;
|
||||
extern const VariableCharacteristics VehicleCertificateSubCa1;
|
||||
extern const VariableCharacteristics VehicleCertificateSubCa2;
|
||||
extern const VariableCharacteristics VehicleCertificateRoot;
|
||||
extern const VariableCharacteristics ProtocolSupportedByEV;
|
||||
} // namespace Characteristics
|
||||
} // namespace ConnectedEVDefinitions
|
||||
@@ -0,0 +1,781 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <algorithm>
|
||||
#include <everest/logging.hpp>
|
||||
|
||||
#include <device_model/definitions.hpp>
|
||||
#include <device_model/everest_device_model_storage.hpp>
|
||||
#include <ocpp/v2/init_device_model_db.hpp>
|
||||
#include <ocpp/v2/ocpp_types.hpp>
|
||||
|
||||
using ocpp::v2::Component;
|
||||
using ocpp::v2::DataEnum;
|
||||
using ocpp::v2::EVSE;
|
||||
using ocpp::v2::Variable;
|
||||
using ocpp::v2::VariableAttribute;
|
||||
using ocpp::v2::VariableCharacteristics;
|
||||
using ocpp::v2::VariableMap;
|
||||
using ocpp::v2::VariableMetaData;
|
||||
|
||||
static constexpr auto VARIABLE_SOURCE_EVEREST = "EVEREST";
|
||||
static constexpr auto NUMBER_OF_CONNECTED_EV_PROTOCOLS = 20;
|
||||
|
||||
using ocpp::v2::ComponentKey;
|
||||
using ocpp::v2::DbVariableAttribute;
|
||||
using ocpp::v2::DeviceModelVariable;
|
||||
|
||||
namespace module::device_model {
|
||||
ocpp::v2::DataEnum to_ocpp_data_enum(const everest::config::Datatype& data_type) {
|
||||
switch (data_type) {
|
||||
case everest::config::Datatype::Unknown:
|
||||
throw std::out_of_range("Could not convert Datatype::Unknown to DataEnum");
|
||||
case everest::config::Datatype::String:
|
||||
return ocpp::v2::DataEnum::string;
|
||||
case everest::config::Datatype::Decimal:
|
||||
return ocpp::v2::DataEnum::decimal;
|
||||
case everest::config::Datatype::Integer:
|
||||
return ocpp::v2::DataEnum::integer;
|
||||
case everest::config::Datatype::Boolean:
|
||||
return ocpp::v2::DataEnum::boolean;
|
||||
}
|
||||
throw std::out_of_range("Could not convert Datatype to DataEnum");
|
||||
}
|
||||
|
||||
ocpp::v2::MutabilityEnum to_ocpp_mutability_enum(const everest::config::Mutability& mutability) {
|
||||
switch (mutability) {
|
||||
case everest::config::Mutability::ReadOnly:
|
||||
return ocpp::v2::MutabilityEnum::ReadOnly;
|
||||
case everest::config::Mutability::ReadWrite:
|
||||
return ocpp::v2::MutabilityEnum::ReadWrite;
|
||||
case everest::config::Mutability::WriteOnly:
|
||||
return ocpp::v2::MutabilityEnum::WriteOnly;
|
||||
}
|
||||
throw std::out_of_range("Could not convert Mutability to MutabilityEnum");
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Component get_evse_component(const int32_t evse_id) {
|
||||
Component component;
|
||||
component.name = "EVSE";
|
||||
component.evse = EvseDefinitions::get_evse(evse_id);
|
||||
return component;
|
||||
}
|
||||
|
||||
Component get_connector_component(const int32_t evse_id, const int32_t connector_id) {
|
||||
Component component;
|
||||
component.name = "Connector";
|
||||
component.evse = EvseDefinitions::get_evse(evse_id, connector_id);
|
||||
return component;
|
||||
}
|
||||
|
||||
Component get_v2x_component(const int32_t evse_id) {
|
||||
Component component;
|
||||
component.name = "V2XChargingCtrlr";
|
||||
component.evse = EvseDefinitions::get_evse(evse_id);
|
||||
return component;
|
||||
}
|
||||
|
||||
Component get_iso15118_component(const int32_t evse_id) {
|
||||
Component component;
|
||||
component.name = "ISO15118Ctrlr";
|
||||
component.evse = EvseDefinitions::get_evse(evse_id);
|
||||
return component;
|
||||
}
|
||||
|
||||
Component get_connected_ev_component(const int32_t evse_id) {
|
||||
Component component;
|
||||
component.name = "ConnectedEV";
|
||||
component.evse = EvseDefinitions::get_evse(evse_id);
|
||||
return component;
|
||||
}
|
||||
|
||||
ComponentKey get_evse_component_key(const int32_t evse_id) {
|
||||
ComponentKey component;
|
||||
component.name = "EVSE";
|
||||
component.evse_id = evse_id;
|
||||
return component;
|
||||
}
|
||||
|
||||
ComponentKey get_connector_component_key(const int32_t evse_id, const int32_t connector_id) {
|
||||
ComponentKey component;
|
||||
component.name = "Connector";
|
||||
component.evse_id = evse_id;
|
||||
component.connector_id = connector_id;
|
||||
return component;
|
||||
}
|
||||
|
||||
ComponentKey get_v2x_component_key(const int32_t evse_id) {
|
||||
ComponentKey component;
|
||||
component.name = "V2XChargingCtrlr";
|
||||
component.evse_id = evse_id;
|
||||
return component;
|
||||
}
|
||||
|
||||
ComponentKey get_iso15118_component_key(const int32_t evse_id) {
|
||||
ComponentKey component;
|
||||
component.name = "ISO15118Ctrlr";
|
||||
component.evse_id = evse_id;
|
||||
return component;
|
||||
}
|
||||
|
||||
ComponentKey get_connected_ev_component_key(const int32_t evse_id) {
|
||||
ComponentKey component;
|
||||
component.name = "ConnectedEV";
|
||||
component.evse_id = evse_id;
|
||||
return component;
|
||||
}
|
||||
|
||||
// Helper function to construct DeviceModelVariable with common structure
|
||||
DeviceModelVariable make_variable(const std::string& name, const ocpp::v2::VariableCharacteristics& characteristics,
|
||||
const std::string& value = "",
|
||||
ocpp::v2::MutabilityEnum mutability = ocpp::v2::MutabilityEnum::ReadOnly) {
|
||||
DeviceModelVariable var_data;
|
||||
var_data.name = name;
|
||||
var_data.characteristics = characteristics;
|
||||
var_data.source = VARIABLE_SOURCE_EVEREST;
|
||||
|
||||
DbVariableAttribute db_attr;
|
||||
VariableAttribute attr;
|
||||
attr.type = ocpp::v2::AttributeEnum::Actual;
|
||||
attr.value = value;
|
||||
attr.mutability = mutability;
|
||||
db_attr.variable_attribute = attr;
|
||||
|
||||
var_data.attributes.push_back(db_attr);
|
||||
return var_data;
|
||||
}
|
||||
|
||||
// Helper function to construct DeviceModelVariable with common structure
|
||||
DeviceModelVariable
|
||||
make_variable_with_instance(const std::string& name, const std::string& instance,
|
||||
const ocpp::v2::VariableCharacteristics& characteristics, const std::string& value = "",
|
||||
ocpp::v2::MutabilityEnum mutability = ocpp::v2::MutabilityEnum::ReadOnly) {
|
||||
DeviceModelVariable var_data;
|
||||
var_data.name = name;
|
||||
var_data.instance = instance;
|
||||
var_data.characteristics = characteristics;
|
||||
var_data.source = VARIABLE_SOURCE_EVEREST;
|
||||
|
||||
DbVariableAttribute db_attr;
|
||||
VariableAttribute attr;
|
||||
attr.type = ocpp::v2::AttributeEnum::Actual;
|
||||
attr.value = value;
|
||||
attr.mutability = mutability;
|
||||
db_attr.variable_attribute = attr;
|
||||
|
||||
var_data.attributes.push_back(db_attr);
|
||||
return var_data;
|
||||
}
|
||||
|
||||
// Populates EVSE variables
|
||||
std::vector<DeviceModelVariable> build_evse_variables(const float max_power) {
|
||||
std::vector<DeviceModelVariable> variables;
|
||||
|
||||
auto evse_power_characteristics = EvseDefinitions::Characteristics::EVSEPower;
|
||||
evse_power_characteristics.maxLimit = max_power;
|
||||
|
||||
return {make_variable(ocpp::v2::EvseComponentVariables::Available.name, EvseDefinitions::Characteristics::Available,
|
||||
"true"),
|
||||
make_variable(ocpp::v2::EvseComponentVariables::AvailabilityState.name,
|
||||
EvseDefinitions::Characteristics::AvailabilityState, "Available"),
|
||||
make_variable(ocpp::v2::EvseComponentVariables::Power.name, evse_power_characteristics),
|
||||
make_variable(ocpp::v2::EvseComponentVariables::SupplyPhases.name,
|
||||
EvseDefinitions::Characteristics::SupplyPhases),
|
||||
make_variable(ocpp::v2::EvseComponentVariables::AllowReset.name,
|
||||
EvseDefinitions::Characteristics::AllowReset, "false"),
|
||||
make_variable(ocpp::v2::EvseComponentVariables::ISO15118EvseId.name,
|
||||
EvseDefinitions::Characteristics::ISO15118EvseId, "DEFAULT_EVSE_ID")};
|
||||
}
|
||||
|
||||
// Populates Connector variables
|
||||
std::vector<DeviceModelVariable> build_connector_variables() {
|
||||
|
||||
return {make_variable(ocpp::v2::ConnectorComponentVariables::Available.name,
|
||||
ConnectorDefinitions::Characteristics::Available, "true"),
|
||||
make_variable(ocpp::v2::ConnectorComponentVariables::AvailabilityState.name,
|
||||
ConnectorDefinitions::Characteristics::AvailabilityState, "Available"),
|
||||
make_variable(ocpp::v2::ConnectorComponentVariables::Type.name,
|
||||
ConnectorDefinitions::Characteristics::ConnectorType),
|
||||
make_variable(ocpp::v2::ConnectorComponentVariables::SupplyPhases.name,
|
||||
ConnectorDefinitions::Characteristics::SupplyPhases)};
|
||||
}
|
||||
|
||||
// Populates V2X variables
|
||||
std::vector<DeviceModelVariable> build_v2x_variables(const bool v2x_supported,
|
||||
const std::string& supported_energy_transfers,
|
||||
const std::string& supported_operation_modes) {
|
||||
std::string v2x_supported_string = v2x_supported ? "true" : "false";
|
||||
return {make_variable(ocpp::v2::V2xComponentVariables::Available.name, V2XDefinitions::Characteristics::Available,
|
||||
v2x_supported_string),
|
||||
make_variable(ocpp::v2::V2xComponentVariables::Enabled.name, V2XDefinitions::Characteristics::Enabled,
|
||||
v2x_supported_string),
|
||||
make_variable(ocpp::v2::V2xComponentVariables::SupportedEnergyTransferModes.name,
|
||||
V2XDefinitions::Characteristics::SupportedEnergyTransferModes, supported_energy_transfers),
|
||||
make_variable(ocpp::v2::V2xComponentVariables::SupportedOperationModes.name,
|
||||
V2XDefinitions::Characteristics::SupportedOperationModes, supported_operation_modes)};
|
||||
}
|
||||
|
||||
// Populates ISO15118 variables
|
||||
std::vector<DeviceModelVariable> build_iso15118_variables(const bool iso_supported,
|
||||
const bool service_renegotiation_supported,
|
||||
const std::string& supported_protocols) {
|
||||
return {make_variable(ocpp::v2::ISO15118ComponentVariables::Enabled.name,
|
||||
ISO15118Definitions::Characteristics::Enabled, iso_supported ? "true" : "false"),
|
||||
make_variable(ocpp::v2::ISO15118ComponentVariables::ServiceRenegotiationSupport.name,
|
||||
ISO15118Definitions::Characteristics::ServiceRenegotiationSupport,
|
||||
service_renegotiation_supported ? "true" : "false"),
|
||||
make_variable(ocpp::v2::ISO15118ComponentVariables::ProtocolSupported.name,
|
||||
ISO15118Definitions::Characteristics::ProtocolSupported, supported_protocols)};
|
||||
}
|
||||
|
||||
// Populates ConnectedEV variables
|
||||
std::vector<DeviceModelVariable> build_connected_ev_variables() {
|
||||
std::vector<DeviceModelVariable> connected_ev_variables{
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::Available.name,
|
||||
ConnectedEVDefinitions::Characteristics::Available, "false"),
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::VehicleId.name,
|
||||
ConnectedEVDefinitions::Characteristics::VehicleId, ""),
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::ProtocolAgreed.name,
|
||||
ConnectedEVDefinitions::Characteristics::ProtocolAgreed, ""),
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateLeaf.name,
|
||||
ConnectedEVDefinitions::Characteristics::VehicleCertificateLeaf, ""),
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateSubCa1.name,
|
||||
ConnectedEVDefinitions::Characteristics::VehicleCertificateSubCa1, ""),
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateSubCa2.name,
|
||||
ConnectedEVDefinitions::Characteristics::VehicleCertificateSubCa2, ""),
|
||||
make_variable(ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateRoot.name,
|
||||
ConnectedEVDefinitions::Characteristics::VehicleCertificateRoot, "")};
|
||||
const int number_of_variables = NUMBER_OF_CONNECTED_EV_PROTOCOLS + connected_ev_variables.size();
|
||||
connected_ev_variables.resize(number_of_variables);
|
||||
|
||||
std::string variable_name = ocpp::v2::ConnectedEvComponentVariables::get_protocol_supported_by_ev(1).name;
|
||||
for (int i = 1; i <= NUMBER_OF_CONNECTED_EV_PROTOCOLS; ++i) {
|
||||
connected_ev_variables.emplace_back(make_variable_with_instance(
|
||||
variable_name, std::to_string(i), ConnectedEVDefinitions::Characteristics::ProtocolSupportedByEV));
|
||||
}
|
||||
return connected_ev_variables;
|
||||
}
|
||||
|
||||
std::string get_everest_config_value(const everest::config::ModuleConfigurationParameters& module_config,
|
||||
const std::string& impl, const std::string& config_key) {
|
||||
const auto& config = module_config.at(impl);
|
||||
for (const auto& config_param : config) {
|
||||
if (config_param.name == config_key) {
|
||||
return everest::config::config_entry_to_string(config_param.value);
|
||||
}
|
||||
}
|
||||
throw std::out_of_range("Could not find requested config key: " + config_key);
|
||||
}
|
||||
|
||||
// Populate EVerest module config variables
|
||||
std::vector<DeviceModelVariable>
|
||||
build_everest_config_variables(const everest::config::ModuleConfigurationParameters& module_config) {
|
||||
std::vector<DeviceModelVariable> component_config;
|
||||
for (const auto& [impl, config_params] : module_config) {
|
||||
std::string prefix;
|
||||
if (impl != Everest::config::MODULE_IMPLEMENTATION_ID) {
|
||||
// prefix variable name with impl + .
|
||||
prefix = impl + ".";
|
||||
}
|
||||
for (const auto& config_param : config_params) {
|
||||
try {
|
||||
const auto variable_name = prefix + config_param.name;
|
||||
ocpp::v2::VariableCharacteristics characteristics;
|
||||
characteristics.dataType = to_ocpp_data_enum(config_param.characteristics.datatype);
|
||||
characteristics.supportsMonitoring = false; // TODO: can we enable monitoring support?
|
||||
// TODO: add unit if/once available?
|
||||
|
||||
auto device_model_variable = make_variable(
|
||||
variable_name, characteristics, get_everest_config_value(module_config, impl, config_param.name),
|
||||
to_ocpp_mutability_enum(config_param.characteristics.mutability));
|
||||
component_config.push_back(device_model_variable);
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Could not add EVerest config entry to OCPP device model: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return component_config;
|
||||
}
|
||||
|
||||
std::string supported_energy_transfer_modes_vector_to_string(
|
||||
const std::vector<types::iso15118::EnergyTransferMode>& evse_supported_energy_transfers) {
|
||||
std::string supported_string{};
|
||||
for (const auto& supported_transfer : evse_supported_energy_transfers) {
|
||||
supported_string += types::iso15118::energy_transfer_mode_to_string(supported_transfer) + ",";
|
||||
}
|
||||
if (!supported_string.empty()) {
|
||||
supported_string.pop_back();
|
||||
}
|
||||
return supported_string;
|
||||
}
|
||||
|
||||
std::string supported_operation_modes_vector_to_string(
|
||||
const std::vector<ocpp::v2::OperationModeEnum>& evse_supported_operation_modes) {
|
||||
std::string supported_string{};
|
||||
for (const auto& operation_mode : evse_supported_operation_modes) {
|
||||
supported_string += ocpp::v2::conversions::operation_mode_enum_to_string(operation_mode) + ",";
|
||||
}
|
||||
if (!supported_string.empty()) {
|
||||
supported_string.pop_back();
|
||||
}
|
||||
return supported_string;
|
||||
}
|
||||
|
||||
std::string build_supported_protocol_string(const std::string& uri, const int32_t major, const int32_t minor) {
|
||||
return uri + ',' + std::to_string(major) + ',' + std::to_string(minor);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
EverestDeviceModelStorage::EverestDeviceModelStorage(
|
||||
const std::vector<std::unique_ptr<evse_managerIntf>>& r_evse_manager,
|
||||
const std::vector<std::unique_ptr<iso15118_extensionsIntf>>& r_extensions_15118,
|
||||
const std::map<int32_t, types::evse_board_support::HardwareCapabilities>& evse_hardware_capabilities_map,
|
||||
const std::map<int32_t, std::vector<types::iso15118::EnergyTransferMode>>& evse_supported_energy_transfers,
|
||||
const std::map<int32_t, bool>& evse_service_renegotiation_supported, const std::filesystem::path& db_path,
|
||||
const std::filesystem::path& migration_files_path,
|
||||
std::shared_ptr<Everest::config::ConfigServiceClient> config_service_client) :
|
||||
r_evse_manager(r_evse_manager),
|
||||
r_extensions_15118(r_extensions_15118),
|
||||
config_service_client(config_service_client) {
|
||||
this->module_configs = config_service_client->get_module_configs();
|
||||
this->mappings = config_service_client->get_mappings();
|
||||
std::map<ComponentKey, std::vector<DeviceModelVariable>> component_configs;
|
||||
|
||||
for (const auto& evse_manager : r_evse_manager) {
|
||||
const auto evse_info = evse_manager->call_get_evse();
|
||||
const auto& hw_capabilities = evse_hardware_capabilities_map.at(evse_info.id);
|
||||
|
||||
ComponentKey evse_component_key = get_evse_component_key(evse_info.id);
|
||||
const auto max_power = hw_capabilities.max_current_A_import * 230.0F * hw_capabilities.max_phase_count_import;
|
||||
component_configs[evse_component_key] = build_evse_variables(max_power);
|
||||
|
||||
for (const auto& connector : evse_info.connectors) {
|
||||
ComponentKey connector_component_key = get_connector_component_key(evse_info.id, connector.id);
|
||||
component_configs[connector_component_key] = build_connector_variables();
|
||||
}
|
||||
|
||||
const auto v2x_component_key = get_v2x_component_key(evse_info.id);
|
||||
const auto& supported_energy_transfer_modes = evse_supported_energy_transfers.at(evse_info.id);
|
||||
// TODO(mlitre): Update dynamically operation mode, depends on future implementation
|
||||
const bool supports_v2x =
|
||||
std::find_if(supported_energy_transfer_modes.cbegin(), supported_energy_transfer_modes.cend(),
|
||||
[](const types::iso15118::EnergyTransferMode& mode) {
|
||||
return mode == types::iso15118::EnergyTransferMode::AC_BPT or
|
||||
mode == types::iso15118::EnergyTransferMode::AC_BPT_DER or
|
||||
mode == types::iso15118::EnergyTransferMode::DC_BPT or
|
||||
mode == types::iso15118::EnergyTransferMode::DC_ACDP_BPT;
|
||||
}) != supported_energy_transfer_modes.cend();
|
||||
component_configs[v2x_component_key] = build_v2x_variables(
|
||||
supports_v2x, supported_energy_transfer_modes_vector_to_string(supported_energy_transfer_modes),
|
||||
supported_operation_modes_vector_to_string(
|
||||
std::vector<ocpp::v2::OperationModeEnum>{ocpp::v2::OperationModeEnum::ChargingOnly}));
|
||||
|
||||
const auto connected_ev_component_key = get_connected_ev_component_key(evse_info.id);
|
||||
component_configs[connected_ev_component_key] = build_connected_ev_variables();
|
||||
}
|
||||
for (const auto& extension : r_extensions_15118) {
|
||||
auto mapping = extension->get_mapping();
|
||||
if (!mapping.has_value()) {
|
||||
continue;
|
||||
}
|
||||
int evse_id = mapping->evse;
|
||||
// TODO(mlitre): Correctly fill iso supported protocols
|
||||
const auto iso15118_component_key = get_iso15118_component_key(evse_id);
|
||||
component_configs[iso15118_component_key] =
|
||||
build_iso15118_variables(true, evse_service_renegotiation_supported.at(evse_id), "");
|
||||
}
|
||||
|
||||
// build OCPP2.x device model components from EVerest config // This is our mapping strategy:
|
||||
// Component.name = module_type
|
||||
// Component.instance = module_id
|
||||
// Component.evse.id/connector = mapping of module
|
||||
// impl mappings are not taken into account at the moment
|
||||
for (const auto& [module_id_type, module_config] : this->module_configs) {
|
||||
ComponentKey component_key;
|
||||
component_key.name = module_id_type.module_type;
|
||||
component_key.instance = module_id_type.module_id;
|
||||
const auto& mapping = this->mappings.at(module_id_type.module_id);
|
||||
if (mapping.module.has_value()) {
|
||||
const auto& module_mapping = mapping.module.value();
|
||||
// in OCPP2.x the id and connectorId of the EVSEType must be > 0
|
||||
if (module_mapping.evse > 0) {
|
||||
component_key.evse_id = module_mapping.evse;
|
||||
if (module_mapping.connector.has_value()) {
|
||||
const auto connector_id = module_mapping.connector.value();
|
||||
if (connector_id > 0) {
|
||||
component_key.connector_id = module_mapping.connector;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
component_configs[component_key] = build_everest_config_variables(module_config);
|
||||
}
|
||||
|
||||
ocpp::v2::InitDeviceModelDb init_device_model_db(db_path, migration_files_path);
|
||||
init_device_model_db.initialize_database(component_configs, false);
|
||||
init_device_model_db.close_connection();
|
||||
this->device_model_storage = std::make_unique<ocpp::v2::DeviceModelStorageSqlite>(db_path);
|
||||
|
||||
this->init_evse_components_and_variables(evse_hardware_capabilities_map, evse_supported_energy_transfers);
|
||||
this->init_everest_config();
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::init_evse_components_and_variables(
|
||||
const std::map<int32_t, types::evse_board_support::HardwareCapabilities>& evse_hardware_capabilities_map,
|
||||
const std::map<int32_t, std::vector<types::iso15118::EnergyTransferMode>>& evse_supported_energy_transfers) {
|
||||
for (const auto& evse_manager : r_evse_manager) {
|
||||
const auto evse_info = evse_manager->call_get_evse();
|
||||
Component evse_component = get_evse_component(evse_info.id);
|
||||
|
||||
if (evse_hardware_capabilities_map.find(evse_info.id) != evse_hardware_capabilities_map.end()) {
|
||||
this->update_hw_capabilities(evse_component, evse_hardware_capabilities_map.at(evse_info.id));
|
||||
} else {
|
||||
EVLOG_error << "No hardware capabilities found for EVSE with ID " << evse_info.id;
|
||||
}
|
||||
|
||||
evse_manager->subscribe_hw_capabilities(
|
||||
[this, evse_component](const types::evse_board_support::HardwareCapabilities hw_capabilities) {
|
||||
this->update_hw_capabilities(evse_component, hw_capabilities);
|
||||
});
|
||||
|
||||
Component v2x_component = get_v2x_component(evse_info.id);
|
||||
|
||||
if (evse_supported_energy_transfers.find(evse_info.id) != evse_supported_energy_transfers.end()) {
|
||||
this->update_supported_energy_transfers(v2x_component, evse_supported_energy_transfers.at(evse_info.id));
|
||||
} else {
|
||||
EVLOG_error << "No supported energy transfer modes found for EVSE with ID " << evse_info.id;
|
||||
}
|
||||
|
||||
evse_manager->subscribe_supported_energy_transfer_modes(
|
||||
[this,
|
||||
v2x_component](const std::vector<types::iso15118::EnergyTransferMode>& supported_energy_transfer_modes) {
|
||||
this->update_supported_energy_transfers(v2x_component, supported_energy_transfer_modes);
|
||||
});
|
||||
// TODO(mlitre): Dynamic update of OperationModeEnum via energy manger conf or subscribed var
|
||||
|
||||
for (const auto& connector : evse_info.connectors) {
|
||||
if (connector.type.has_value()) {
|
||||
const auto component = get_connector_component(evse_info.id, connector.id);
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
component, ocpp::v2::ConnectorComponentVariables::Type, ocpp::v2::AttributeEnum::Actual,
|
||||
types::evse_manager::connector_type_enum_to_string(connector.type.value()),
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto& extension : r_extensions_15118) {
|
||||
const auto mapping = extension->get_mapping();
|
||||
if (!mapping.has_value()) {
|
||||
continue;
|
||||
}
|
||||
const auto evse_id = mapping->evse;
|
||||
Component iso15118_component = get_iso15118_component(evse_id);
|
||||
extension->subscribe_service_renegotiation_supported(
|
||||
[this, iso15118_component](const bool service_renegotiation_supported) {
|
||||
this->update_service_renegotiation_supported(iso15118_component, service_renegotiation_supported);
|
||||
});
|
||||
|
||||
const auto connected_ev_component = get_connected_ev_component(evse_id);
|
||||
extension->subscribe_ev_info(
|
||||
[this, connected_ev_component](const types::iso15118::EvInformation& ev_information) {
|
||||
this->update_connected_ev_information(connected_ev_component, ev_information);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::init_everest_config() {
|
||||
for (const auto& [module_id_type, module_config] : this->module_configs) {
|
||||
for (const auto& [impl, config_params] : module_config) {
|
||||
std::string prefix;
|
||||
if (impl != Everest::config::MODULE_IMPLEMENTATION_ID) {
|
||||
// prefix variable name with impl + .
|
||||
prefix = impl + ".";
|
||||
}
|
||||
for (const auto& config_param : config_params) {
|
||||
try {
|
||||
const auto variable_name = prefix + config_param.name;
|
||||
|
||||
Component component;
|
||||
component.name = module_id_type.module_type;
|
||||
component.instance = module_id_type.module_id;
|
||||
Variable variable;
|
||||
variable.name = variable_name;
|
||||
ocpp::v2::ComponentVariable component_variable;
|
||||
component_variable.component = component;
|
||||
component_variable.variable = variable;
|
||||
// allows to differentiate variables backed by the EVerest config from other device model variables
|
||||
this->stored_in_everest_config_service.insert(component_variable);
|
||||
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
component, variable, ocpp::v2::AttributeEnum::Actual,
|
||||
get_everest_config_value(module_config, impl, config_param.name), VARIABLE_SOURCE_EVEREST);
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_error << "Could not initialize EVerest config entry in OCPP device model: " << e.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_hw_capabilities(
|
||||
const Component& evse_component, const types::evse_board_support::HardwareCapabilities& hw_capabilities) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
evse_component, ocpp::v2::EvseComponentVariables::SupplyPhases, ocpp::v2::AttributeEnum::Actual,
|
||||
std::to_string(hw_capabilities.max_phase_count_import), VARIABLE_SOURCE_EVEREST);
|
||||
// TODO: update EVSE.Power maxLimit value once device model storage interface supports it
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_supported_energy_transfers(
|
||||
const ocpp::v2::Component& evse_component,
|
||||
const std::vector<types::iso15118::EnergyTransferMode>& evse_supported_energy_transfers) {
|
||||
std::string supported_string = supported_energy_transfer_modes_vector_to_string(evse_supported_energy_transfers);
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
evse_component, ocpp::v2::V2xComponentVariables::SupportedEnergyTransferModes, ocpp::v2::AttributeEnum::Actual,
|
||||
supported_string, VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_supported_operation_modes(
|
||||
const ocpp::v2::Component& evse_component,
|
||||
const std::vector<ocpp::v2::OperationModeEnum>& evse_supported_operation_modes) {
|
||||
std::string supported_string = supported_operation_modes_vector_to_string(evse_supported_operation_modes);
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
evse_component, ocpp::v2::V2xComponentVariables::SupportedOperationModes, ocpp::v2::AttributeEnum::Actual,
|
||||
supported_string, VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_service_renegotiation_supported(const ocpp::v2::Component& iso15118_component,
|
||||
const bool& service_renegotiation_supported) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
iso15118_component, ocpp::v2::ISO15118ComponentVariables::ServiceRenegotiationSupport,
|
||||
ocpp::v2::AttributeEnum::Actual, service_renegotiation_supported ? "true" : "false", VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_connected_ev_information(const ocpp::v2::Component& connected_ev_component,
|
||||
const types::iso15118::EvInformation& ev_information) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
// We update to true even though it should already be true as a precaution
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::Available, ocpp::v2::AttributeEnum::Actual,
|
||||
"true", VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleId, ocpp::v2::AttributeEnum::Actual,
|
||||
ev_information.evcc_id, VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::ProtocolAgreed,
|
||||
ocpp::v2::AttributeEnum::Actual,
|
||||
build_supported_protocol_string(ev_information.selected_protocol.protocol_namespace,
|
||||
ev_information.selected_protocol.version_number_major,
|
||||
ev_information.selected_protocol.version_number_minor),
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateLeaf,
|
||||
ocpp::v2::AttributeEnum::Actual,
|
||||
ev_information.tls_leaf_certificate.has_value() ? ev_information.tls_leaf_certificate.value() : "",
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateSubCa1,
|
||||
ocpp::v2::AttributeEnum::Actual,
|
||||
ev_information.tls_sub_ca_1_certificate.has_value() ? ev_information.tls_sub_ca_1_certificate.value() : "",
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateSubCa2,
|
||||
ocpp::v2::AttributeEnum::Actual,
|
||||
ev_information.tls_sub_ca_2_certificate.has_value() ? ev_information.tls_sub_ca_2_certificate.value() : "",
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateRoot,
|
||||
ocpp::v2::AttributeEnum::Actual,
|
||||
ev_information.tls_root_certificate.has_value() ? ev_information.tls_root_certificate.value() : "",
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
for (const auto& protocol : ev_information.supported_protocols.Protocols) {
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component,
|
||||
ocpp::v2::ConnectedEvComponentVariables::get_protocol_supported_by_ev(protocol.priority),
|
||||
ocpp::v2::AttributeEnum::Actual,
|
||||
build_supported_protocol_string(protocol.protocol_namespace, protocol.version_number_major,
|
||||
protocol.version_number_minor),
|
||||
VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_connected_ev_available(const int32_t evse_id, const bool connected) {
|
||||
const auto connected_ev_component = get_connected_ev_component(evse_id);
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::Available, ocpp::v2::AttributeEnum::Actual,
|
||||
connected ? "true" : "false", VARIABLE_SOURCE_EVEREST);
|
||||
if (!connected) {
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleId, ocpp::v2::AttributeEnum::Actual,
|
||||
"", VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::ProtocolAgreed,
|
||||
ocpp::v2::AttributeEnum::Actual, "", VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateLeaf,
|
||||
ocpp::v2::AttributeEnum::Actual, "", VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateSubCa1,
|
||||
ocpp::v2::AttributeEnum::Actual, "", VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateSubCa2,
|
||||
ocpp::v2::AttributeEnum::Actual, "", VARIABLE_SOURCE_EVEREST);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleCertificateRoot,
|
||||
ocpp::v2::AttributeEnum::Actual, "", VARIABLE_SOURCE_EVEREST);
|
||||
for (int i = 1; i <= NUMBER_OF_CONNECTED_EV_PROTOCOLS; ++i) {
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::get_protocol_supported_by_ev(i),
|
||||
ocpp::v2::AttributeEnum::Actual, "", VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_connected_ev_vehicle_id(const int32_t evse_id, const std::string& vehicle_id) {
|
||||
const auto connected_ev_component = get_connected_ev_component(evse_id);
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
connected_ev_component, ocpp::v2::ConnectedEvComponentVariables::VehicleId, ocpp::v2::AttributeEnum::Actual,
|
||||
vehicle_id, VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::update_power(const int32_t evse_id, const float total_power_active_import) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
Component evse_component = get_evse_component(evse_id);
|
||||
this->device_model_storage->set_variable_attribute_value(
|
||||
evse_component, ocpp::v2::EvseComponentVariables::Power, ocpp::v2::AttributeEnum::Actual,
|
||||
std::to_string(total_power_active_import), VARIABLE_SOURCE_EVEREST);
|
||||
}
|
||||
|
||||
ocpp::v2::DeviceModelMap EverestDeviceModelStorage::get_device_model() {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->get_device_model();
|
||||
}
|
||||
|
||||
std::optional<ocpp::v2::VariableAttribute>
|
||||
EverestDeviceModelStorage::get_variable_attribute(const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->get_variable_attribute(component_id, variable_id, attribute_enum);
|
||||
}
|
||||
|
||||
std::vector<ocpp::v2::VariableAttribute>
|
||||
EverestDeviceModelStorage::get_variable_attributes(const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id,
|
||||
const std::optional<ocpp::v2::AttributeEnum>& attribute_enum) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->get_variable_attributes(component_id, variable_id, attribute_enum);
|
||||
}
|
||||
|
||||
ocpp::v2::SetVariableStatusEnum EverestDeviceModelStorage::set_variable_attribute_value(
|
||||
const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum, const std::string& value, const std::string& source) {
|
||||
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
|
||||
int evse_id = 0;
|
||||
if (component_id.evse.has_value()) {
|
||||
evse_id = component_id.evse.value().id;
|
||||
}
|
||||
|
||||
ocpp::v2::ComponentVariable component_variable;
|
||||
component_variable.component = component_id;
|
||||
component_variable.variable = variable_id;
|
||||
auto stored_in_everest_config_service_it = this->stored_in_everest_config_service.find(component_variable);
|
||||
if (stored_in_everest_config_service_it != this->stored_in_everest_config_service.end()) {
|
||||
if (attribute_enum != ocpp::v2::AttributeEnum::Actual) {
|
||||
return ocpp::v2::SetVariableStatusEnum::Rejected;
|
||||
}
|
||||
if (not component_id.instance.has_value()) {
|
||||
return ocpp::v2::SetVariableStatusEnum::Rejected;
|
||||
}
|
||||
const auto module_id = component_id.instance.value();
|
||||
everest::config::ConfigurationParameterIdentifier identifier;
|
||||
identifier.module_id = module_id;
|
||||
const std::string variable_name = variable_id.name;
|
||||
const auto strpos = variable_name.find(".");
|
||||
if (strpos != std::string::npos) {
|
||||
identifier.module_implementation_id = variable_name.substr(0, strpos);
|
||||
identifier.configuration_parameter_name = variable_name.substr(strpos + 1, variable_name.length());
|
||||
} else {
|
||||
identifier.module_implementation_id = Everest::config::MODULE_IMPLEMENTATION_ID;
|
||||
identifier.configuration_parameter_name = variable_name;
|
||||
}
|
||||
|
||||
const auto result = this->config_service_client->set_config_value(identifier, value);
|
||||
|
||||
if (result.set_status == everest::config::SetConfigStatus::Accepted) {
|
||||
// immediately set it in the libocpp device model as well
|
||||
const auto libocpp_result = this->device_model_storage->set_variable_attribute_value(
|
||||
component_id, variable_id, attribute_enum, value, source);
|
||||
if (libocpp_result != ocpp::v2::SetVariableStatusEnum::Accepted) {
|
||||
EVLOG_error << "Device model set variable results disagree";
|
||||
}
|
||||
return libocpp_result; // FIXME: what to return, libocpp or EVerest result?
|
||||
} else if (result.set_status == everest::config::SetConfigStatus::Rejected) {
|
||||
return ocpp::v2::SetVariableStatusEnum::Rejected;
|
||||
} else if (result.set_status == everest::config::SetConfigStatus::RebootRequired) {
|
||||
return ocpp::v2::SetVariableStatusEnum::RebootRequired;
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: device_model_storage->set_variable_attribute_value does only return accepted or rejected, no other
|
||||
// checks
|
||||
// are performed. Since libocpp contains the full device model in memory and does these checks independently,
|
||||
// it's currently only a minor issue.
|
||||
return this->device_model_storage->set_variable_attribute_value(component_id, variable_id, attribute_enum, value,
|
||||
source);
|
||||
}
|
||||
|
||||
std::optional<ocpp::v2::VariableMonitoringMeta>
|
||||
EverestDeviceModelStorage::set_monitoring_data(const ocpp::v2::SetMonitoringData& data,
|
||||
const ocpp::v2::VariableMonitorType type) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->set_monitoring_data(data, type);
|
||||
}
|
||||
|
||||
bool EverestDeviceModelStorage::update_monitoring_reference(const int32_t monitor_id,
|
||||
const std::string& reference_value) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->update_monitoring_reference(monitor_id, reference_value);
|
||||
}
|
||||
|
||||
std::vector<ocpp::v2::VariableMonitoringMeta>
|
||||
EverestDeviceModelStorage::get_monitoring_data(const std::vector<ocpp::v2::MonitoringCriterionEnum>& criteria,
|
||||
const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->get_monitoring_data(criteria, component_id, variable_id);
|
||||
}
|
||||
|
||||
ocpp::v2::ClearMonitoringStatusEnum EverestDeviceModelStorage::clear_variable_monitor(int monitor_id,
|
||||
bool allow_protected) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->clear_variable_monitor(monitor_id, allow_protected);
|
||||
}
|
||||
|
||||
int32_t EverestDeviceModelStorage::clear_custom_variable_monitors() {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->clear_custom_variable_monitors();
|
||||
}
|
||||
|
||||
void EverestDeviceModelStorage::check_integrity() {
|
||||
}
|
||||
|
||||
bool EverestDeviceModelStorage::create_network_configuration_slot_from_default_schema(std::int32_t new_slot) {
|
||||
std::lock_guard<std::mutex> lock(device_model_mutex);
|
||||
return this->device_model_storage->create_network_configuration_slot_from_default_schema(new_slot);
|
||||
}
|
||||
} // namespace module::device_model
|
||||
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <generated/interfaces/evse_manager/Interface.hpp>
|
||||
#include <generated/interfaces/iso15118_extensions/Interface.hpp>
|
||||
#include <generated/types/evse_board_support.hpp>
|
||||
#include <generated/types/powermeter.hpp>
|
||||
|
||||
#include <ocpp/v2/device_model_storage_interface.hpp>
|
||||
#include <ocpp/v2/device_model_storage_sqlite.hpp>
|
||||
#include <utils/config_service.hpp>
|
||||
|
||||
namespace module::device_model {
|
||||
class EverestDeviceModelStorage : public ocpp::v2::DeviceModelStorageInterface {
|
||||
public:
|
||||
EverestDeviceModelStorage(
|
||||
const std::vector<std::unique_ptr<evse_managerIntf>>& r_evse_manager,
|
||||
const std::vector<std::unique_ptr<iso15118_extensionsIntf>>& r_extensions_15118,
|
||||
const std::map<int32_t, types::evse_board_support::HardwareCapabilities>& evse_hardware_capabilities_map,
|
||||
const std::map<int32_t, std::vector<types::iso15118::EnergyTransferMode>>& evse_supported_energy_transfers,
|
||||
const std::map<int32_t, bool>& evse_service_renegotiation_supported, const std::filesystem::path& db_path,
|
||||
const std::filesystem::path& migration_files_path,
|
||||
std::shared_ptr<Everest::config::ConfigServiceClient> config_service_client);
|
||||
virtual ~EverestDeviceModelStorage() override = default;
|
||||
virtual ocpp::v2::DeviceModelMap get_device_model() override;
|
||||
virtual std::optional<ocpp::v2::VariableAttribute>
|
||||
get_variable_attribute(const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum) override;
|
||||
virtual std::vector<ocpp::v2::VariableAttribute>
|
||||
get_variable_attributes(const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id,
|
||||
const std::optional<ocpp::v2::AttributeEnum>& attribute_enum) override;
|
||||
virtual ocpp::v2::SetVariableStatusEnum set_variable_attribute_value(const ocpp::v2::Component& component_id,
|
||||
const ocpp::v2::Variable& variable_id,
|
||||
const ocpp::v2::AttributeEnum& attribute_enum,
|
||||
const std::string& value,
|
||||
const std::string& source) override;
|
||||
virtual std::optional<ocpp::v2::VariableMonitoringMeta>
|
||||
set_monitoring_data(const ocpp::v2::SetMonitoringData& data, const ocpp::v2::VariableMonitorType type) override;
|
||||
virtual bool update_monitoring_reference(const int32_t monitor_id, const std::string& reference_value) override;
|
||||
virtual std::vector<ocpp::v2::VariableMonitoringMeta>
|
||||
get_monitoring_data(const std::vector<ocpp::v2::MonitoringCriterionEnum>& criteria,
|
||||
const ocpp::v2::Component& component_id, const ocpp::v2::Variable& variable_id) override;
|
||||
virtual ocpp::v2::ClearMonitoringStatusEnum clear_variable_monitor(int monitor_id, bool allow_protected) override;
|
||||
virtual int32_t clear_custom_variable_monitors() override;
|
||||
virtual void check_integrity() override;
|
||||
virtual bool create_network_configuration_slot_from_default_schema(std::int32_t new_slot) override;
|
||||
|
||||
/// \brief Updates the actual value of the EVSE Power variable to the given \p total_power_active_import value
|
||||
void update_power(const int32_t evse_id, const float total_power_active_import);
|
||||
|
||||
/// \bried Updates the Available variable for the ConnectedEV component
|
||||
void update_connected_ev_available(const int32_t evse_id, const bool connected);
|
||||
|
||||
/// \bried Updates the VehicleId variable for the ConnectedEV component
|
||||
void update_connected_ev_vehicle_id(const int32_t evse_id, const std::string& vehicle_id);
|
||||
|
||||
private:
|
||||
const std::vector<std::unique_ptr<evse_managerIntf>>& r_evse_manager;
|
||||
const std::vector<std::unique_ptr<iso15118_extensionsIntf>>& r_extensions_15118;
|
||||
std::mutex device_model_mutex;
|
||||
std::unique_ptr<ocpp::v2::DeviceModelStorageSqlite> device_model_storage;
|
||||
std::set<ocpp::v2::ComponentVariable> stored_in_everest_config_service;
|
||||
std::shared_ptr<Everest::config::ConfigServiceClient> config_service_client;
|
||||
std::map<Everest::config::ModuleIdType, everest::config::ModuleConfigurationParameters> module_configs;
|
||||
std::map<std::string, ModuleTierMappings> mappings;
|
||||
|
||||
void init_evse_components_and_variables(
|
||||
const std::map<int32_t, types::evse_board_support::HardwareCapabilities>& evse_hardware_capabilities_map,
|
||||
const std::map<int32_t, std::vector<types::iso15118::EnergyTransferMode>>& evse_supported_energy_transfers);
|
||||
void update_hw_capabilities(const ocpp::v2::Component& evse_component,
|
||||
const types::evse_board_support::HardwareCapabilities& hw_capabilities);
|
||||
void update_supported_energy_transfers(
|
||||
const ocpp::v2::Component& evse_component,
|
||||
const std::vector<types::iso15118::EnergyTransferMode>& evse_supported_energy_transfers);
|
||||
void
|
||||
update_supported_operation_modes(const ocpp::v2::Component& evse_component,
|
||||
const std::vector<ocpp::v2::OperationModeEnum>& evse_supported_operation_modes);
|
||||
void update_service_renegotiation_supported(const ocpp::v2::Component& iso15118_component,
|
||||
const bool& service_renegotiation_supported);
|
||||
void update_connected_ev_information(const ocpp::v2::Component& connected_ev_component,
|
||||
const types::iso15118::EvInformation& ev_information);
|
||||
void init_everest_config();
|
||||
};
|
||||
} // namespace module::device_model
|
||||
Reference in New Issue
Block a user