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:
48
tools/EVerest-main/modules/EVSE/OCPP/CMakeLists.txt
Normal file
48
tools/EVerest-main/modules/EVSE/OCPP/CMakeLists.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
#
|
||||
# AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
# template version 3
|
||||
#
|
||||
|
||||
# module setup:
|
||||
# - ${MODULE_NAME}: module name
|
||||
ev_setup_cpp_module()
|
||||
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
# insert your custom targets and additional config variables here
|
||||
find_package(OpenSSL)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
everest::util
|
||||
everest::ocpp
|
||||
everest::ocpp_evse_security
|
||||
everest::ocpp_conversions
|
||||
everest::external_energy_limits
|
||||
)
|
||||
|
||||
target_compile_options(${MODULE_NAME}
|
||||
PRIVATE
|
||||
-Wimplicit-fallthrough
|
||||
-Werror=switch-enum
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"main/ocpp_1_6_charge_pointImpl.cpp"
|
||||
"auth_validator/auth_token_validatorImpl.cpp"
|
||||
"auth_provider/auth_token_providerImpl.cpp"
|
||||
"data_transfer/ocpp_data_transferImpl.cpp"
|
||||
"ocpp_generic/ocppImpl.cpp"
|
||||
"session_cost/session_costImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"conversions.cpp"
|
||||
)
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
1171
tools/EVerest-main/modules/EVSE/OCPP/OCPP.cpp
Normal file
1171
tools/EVerest-main/modules/EVSE/OCPP/OCPP.cpp
Normal file
File diff suppressed because it is too large
Load Diff
201
tools/EVerest-main/modules/EVSE/OCPP/OCPP.hpp
Normal file
201
tools/EVerest-main/modules/EVSE/OCPP/OCPP.hpp
Normal file
@@ -0,0 +1,201 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef OCPP_HPP
|
||||
#define OCPP_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
|
||||
#include <generated/interfaces/auth_token_validator/Implementation.hpp>
|
||||
#include <generated/interfaces/ocpp/Implementation.hpp>
|
||||
#include <generated/interfaces/ocpp_1_6_charge_point/Implementation.hpp>
|
||||
#include <generated/interfaces/ocpp_data_transfer/Implementation.hpp>
|
||||
#include <generated/interfaces/session_cost/Implementation.hpp>
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/auth/Interface.hpp>
|
||||
#include <generated/interfaces/charger_information/Interface.hpp>
|
||||
#include <generated/interfaces/display_message/Interface.hpp>
|
||||
#include <generated/interfaces/evse_manager/Interface.hpp>
|
||||
#include <generated/interfaces/evse_security/Interface.hpp>
|
||||
#include <generated/interfaces/external_energy_limits/Interface.hpp>
|
||||
#include <generated/interfaces/iso15118_extensions/Interface.hpp>
|
||||
#include <generated/interfaces/ocpp_data_transfer/Interface.hpp>
|
||||
#include <generated/interfaces/reservation/Interface.hpp>
|
||||
#include <generated/interfaces/system/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
#include <chrono>
|
||||
#include <date/date.h>
|
||||
#include <date/tz.h>
|
||||
#include <everest/timer.hpp>
|
||||
#include <everest/util/async/monitor.hpp>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
#include <ocpp/common/types.hpp>
|
||||
#include <ocpp/v16/charge_point.hpp>
|
||||
#include <ocpp/v16/charge_point_configuration.hpp>
|
||||
#include <ocpp/v16/types.hpp>
|
||||
#include <ocpp/v2/ocpp_types.hpp>
|
||||
|
||||
struct ErrorRaised : public Everest::error::Error {};
|
||||
struct ErrorCleared : public Everest::error::Error {};
|
||||
struct PowermeterPublicKey {
|
||||
std::string value;
|
||||
};
|
||||
|
||||
using EventData = std::variant<types::evse_manager::SessionEvent, ErrorRaised, ErrorCleared, types::system::LogStatus,
|
||||
types::system::FirmwareUpdateStatus, PowermeterPublicKey>;
|
||||
|
||||
struct Event {
|
||||
int32_t evse_id;
|
||||
EventData data;
|
||||
|
||||
Event(int32_t evse_id_, EventData data_) : evse_id(evse_id_), data(std::move(data_)) {
|
||||
}
|
||||
};
|
||||
|
||||
using EvseConnectorMap = std::map<int32_t, std::map<int32_t, int32_t>>;
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string ChargePointConfigPath;
|
||||
std::string UserConfigPath;
|
||||
std::string DatabasePath;
|
||||
bool EnableExternalWebsocketControl;
|
||||
int PublishChargingScheduleIntervalS;
|
||||
int PublishChargingScheduleDurationS;
|
||||
std::string MessageLogPath;
|
||||
int MessageQueueResumeDelay;
|
||||
std::string RequestCompositeScheduleUnit;
|
||||
int DelayOcppStart;
|
||||
int ResetStopDelay;
|
||||
};
|
||||
|
||||
class OCPP : public Everest::ModuleBase {
|
||||
public:
|
||||
OCPP() = delete;
|
||||
OCPP(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider,
|
||||
std::unique_ptr<ocpp_1_6_charge_pointImplBase> p_main,
|
||||
std::unique_ptr<auth_token_validatorImplBase> p_auth_validator,
|
||||
std::unique_ptr<auth_token_providerImplBase> p_auth_provider,
|
||||
std::unique_ptr<ocpp_data_transferImplBase> p_data_transfer, std::unique_ptr<ocppImplBase> p_ocpp_generic,
|
||||
std::unique_ptr<session_costImplBase> p_session_cost,
|
||||
std::vector<std::unique_ptr<charger_informationIntf>> r_charger_information,
|
||||
std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager,
|
||||
std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_energy_sink,
|
||||
std::unique_ptr<reservationIntf> r_reservation, std::unique_ptr<authIntf> r_auth,
|
||||
std::unique_ptr<systemIntf> r_system, std::unique_ptr<evse_securityIntf> r_security,
|
||||
std::vector<std::unique_ptr<ocpp_data_transferIntf>> r_data_transfer,
|
||||
std::vector<std::unique_ptr<display_messageIntf>> r_display_message,
|
||||
std::vector<std::unique_ptr<iso15118_extensionsIntf>> r_extensions_15118, Conf& config) :
|
||||
ModuleBase(info),
|
||||
mqtt(mqtt_provider),
|
||||
p_main(std::move(p_main)),
|
||||
p_auth_validator(std::move(p_auth_validator)),
|
||||
p_auth_provider(std::move(p_auth_provider)),
|
||||
p_data_transfer(std::move(p_data_transfer)),
|
||||
p_ocpp_generic(std::move(p_ocpp_generic)),
|
||||
p_session_cost(std::move(p_session_cost)),
|
||||
r_charger_information(std::move(r_charger_information)),
|
||||
r_evse_manager(std::move(r_evse_manager)),
|
||||
r_evse_energy_sink(std::move(r_evse_energy_sink)),
|
||||
r_reservation(std::move(r_reservation)),
|
||||
r_auth(std::move(r_auth)),
|
||||
r_system(std::move(r_system)),
|
||||
r_security(std::move(r_security)),
|
||||
r_data_transfer(std::move(r_data_transfer)),
|
||||
r_display_message(std::move(r_display_message)),
|
||||
r_extensions_15118(std::move(r_extensions_15118)),
|
||||
config(config){};
|
||||
|
||||
Everest::MqttProvider& mqtt;
|
||||
const std::unique_ptr<ocpp_1_6_charge_pointImplBase> p_main;
|
||||
const std::unique_ptr<auth_token_validatorImplBase> p_auth_validator;
|
||||
const std::unique_ptr<auth_token_providerImplBase> p_auth_provider;
|
||||
const std::unique_ptr<ocpp_data_transferImplBase> p_data_transfer;
|
||||
const std::unique_ptr<ocppImplBase> p_ocpp_generic;
|
||||
const std::unique_ptr<session_costImplBase> p_session_cost;
|
||||
const std::vector<std::unique_ptr<charger_informationIntf>> r_charger_information;
|
||||
const std::vector<std::unique_ptr<evse_managerIntf>> r_evse_manager;
|
||||
const std::vector<std::unique_ptr<external_energy_limitsIntf>> r_evse_energy_sink;
|
||||
const std::unique_ptr<reservationIntf> r_reservation;
|
||||
const std::unique_ptr<authIntf> r_auth;
|
||||
const std::unique_ptr<systemIntf> r_system;
|
||||
const std::unique_ptr<evse_securityIntf> r_security;
|
||||
const std::vector<std::unique_ptr<ocpp_data_transferIntf>> r_data_transfer;
|
||||
const std::vector<std::unique_ptr<display_messageIntf>> r_display_message;
|
||||
const std::vector<std::unique_ptr<iso15118_extensionsIntf>> r_extensions_15118;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
std::unique_ptr<ocpp::v16::ChargePoint> charge_point;
|
||||
std::unique_ptr<ocpp::v16::ChargePointConfiguration> charge_point_config;
|
||||
std::unique_ptr<Everest::SteadyTimer> charging_schedules_timer;
|
||||
bool ocpp_stopped = false;
|
||||
|
||||
// Return the OCPP connector id from a pair of EVerest EVSE id and connector
|
||||
// id
|
||||
int32_t get_ocpp_connector_id(int32_t evse_id, int32_t connector_id);
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
|
||||
protected:
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
// insert your protected definitions here
|
||||
// ev@4714b2ab-a24f-4b95-ab81-36439e1478de:v1
|
||||
|
||||
private:
|
||||
friend class LdEverest;
|
||||
void init();
|
||||
void ready();
|
||||
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
// insert your private definitions here
|
||||
std::filesystem::path ocpp_share_path;
|
||||
ocpp::v16::ChargingRateUnit composite_schedule_charging_rate_unit;
|
||||
void set_external_limits(const std::map<int32_t, ocpp::v16::EnhancedChargingSchedule>& charging_schedules);
|
||||
void publish_charging_schedules(const std::map<int32_t, ocpp::v16::EnhancedChargingSchedule>& charging_schedules);
|
||||
|
||||
void init_evse_subscriptions(); // initialize subscriptions to all EVSEs
|
||||
// provided by r_evse_manager
|
||||
void init_evse_connector_map();
|
||||
void init_evse_maps();
|
||||
void init_module_configuration();
|
||||
void handle_config_key(const ocpp::v16::KeyValue& kv);
|
||||
EvseConnectorMap evse_connector_map; // provides access to OCPP connector id by using
|
||||
// EVerests evse and connector id
|
||||
std::map<int32_t, int32_t> connector_evse_index_map; // provides access to r_evse_manager index by
|
||||
// using OCPP connector id
|
||||
everest::lib::util::monitor<std::map<int32_t, bool>> evse_ready_map;
|
||||
everest::lib::util::monitor<std::map<int32_t, std::optional<float>>> evse_soc_map;
|
||||
std::set<std::string> resuming_session_ids;
|
||||
|
||||
std::mutex event_mutex;
|
||||
bool started{false};
|
||||
std::queue<Event> event_queue;
|
||||
void process_session_event(int32_t evse_id, const types::evse_manager::SessionEvent& session_event);
|
||||
|
||||
std::string source_ext_limit;
|
||||
// ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1
|
||||
};
|
||||
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
// insert other definitions here
|
||||
// ev@087e516b-124c-48df-94fb-109508c7cda9:v1
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif // OCPP_HPP
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2022 - 2022 Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "auth_token_providerImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace auth_provider {
|
||||
|
||||
void auth_token_providerImpl::init() {
|
||||
}
|
||||
|
||||
void auth_token_providerImpl::ready() {
|
||||
}
|
||||
|
||||
} // namespace auth_provider
|
||||
} // namespace module
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef AUTH_PROVIDER_AUTH_TOKEN_PROVIDER_IMPL_HPP
|
||||
#define AUTH_PROVIDER_AUTH_TOKEN_PROVIDER_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/auth_token_provider/Implementation.hpp>
|
||||
|
||||
#include "../OCPP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace auth_provider {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class auth_token_providerImpl : public auth_token_providerImplBase {
|
||||
public:
|
||||
auth_token_providerImpl() = delete;
|
||||
auth_token_providerImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<OCPP>& mod, Conf& config) :
|
||||
auth_token_providerImplBase(ev, "auth_provider"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// no commands defined for this interface
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<OCPP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace auth_provider
|
||||
} // namespace module
|
||||
|
||||
#endif // AUTH_PROVIDER_AUTH_TOKEN_PROVIDER_IMPL_HPP
|
||||
@@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
|
||||
#include "auth_token_validatorImpl.hpp"
|
||||
#include <conversions.hpp>
|
||||
#include <everest/conversions/ocpp/ocpp_conversions.hpp>
|
||||
#include <ocpp/common/types.hpp>
|
||||
#include <ocpp/v16/ocpp_enums.hpp>
|
||||
#include <ocpp/v2/ocpp_types.hpp>
|
||||
|
||||
namespace module {
|
||||
namespace auth_validator {
|
||||
|
||||
void auth_token_validatorImpl::init() {
|
||||
}
|
||||
|
||||
void auth_token_validatorImpl::ready() {
|
||||
}
|
||||
|
||||
types::authorization::ValidationResult
|
||||
auth_token_validatorImpl::handle_validate_token(types::authorization::ProvidedIdToken& provided_token) {
|
||||
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle validate token command";
|
||||
types::authorization::ValidationResult result;
|
||||
result.authorization_status = types::authorization::AuthorizationStatus::Unknown;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (provided_token.authorization_type == types::authorization::AuthorizationType::PlugAndCharge) {
|
||||
return validate_pnc_request(provided_token);
|
||||
} else {
|
||||
return validate_standard_request(provided_token);
|
||||
}
|
||||
};
|
||||
|
||||
types::authorization::ValidationResult
|
||||
auth_token_validatorImpl::validate_pnc_request(const types::authorization::ProvidedIdToken& provided_token) {
|
||||
|
||||
types::authorization::ValidationResult validation_result;
|
||||
try {
|
||||
// preparing payload for data_transfer_pnc_authorize
|
||||
std::optional<std::vector<ocpp::v2::OCSPRequestData>> iso15118_certificate_hash_data_opt;
|
||||
if (provided_token.iso15118CertificateHashData.has_value()) {
|
||||
std::vector<ocpp::v2::OCSPRequestData> iso15118_certificate_hash_data;
|
||||
for (const auto& certificate_hash_data : provided_token.iso15118CertificateHashData.value()) {
|
||||
ocpp::v2::OCSPRequestData v2_certificate_hash_data;
|
||||
v2_certificate_hash_data.hashAlgorithm =
|
||||
conversions::to_ocpp_hash_algorithm_enum(certificate_hash_data.hashAlgorithm);
|
||||
v2_certificate_hash_data.issuerKeyHash = certificate_hash_data.issuerKeyHash;
|
||||
v2_certificate_hash_data.issuerNameHash = certificate_hash_data.issuerNameHash;
|
||||
v2_certificate_hash_data.responderURL = certificate_hash_data.responderURL;
|
||||
v2_certificate_hash_data.serialNumber = certificate_hash_data.serialNumber;
|
||||
iso15118_certificate_hash_data.push_back(v2_certificate_hash_data);
|
||||
}
|
||||
iso15118_certificate_hash_data_opt.emplace(iso15118_certificate_hash_data);
|
||||
}
|
||||
|
||||
// this is the actual OCPP request via DataTransfer.req to CSMS according to
|
||||
// PnC1.6 whitepaper
|
||||
const auto authorize_response = mod->charge_point->data_transfer_pnc_authorize(
|
||||
provided_token.id_token.value, provided_token.certificate, iso15118_certificate_hash_data_opt);
|
||||
|
||||
validation_result.authorization_status =
|
||||
conversions::to_everest_authorization_status(authorize_response.idTokenInfo.status);
|
||||
validation_result.evse_ids = authorize_response.idTokenInfo.evseId;
|
||||
if (authorize_response.certificateStatus.has_value()) {
|
||||
validation_result.certificate_status.emplace(
|
||||
conversions::to_everest_certificate_status(authorize_response.certificateStatus.value()));
|
||||
}
|
||||
if (authorize_response.idTokenInfo.cacheExpiryDateTime.has_value()) {
|
||||
validation_result.expiry_time.emplace(
|
||||
authorize_response.idTokenInfo.cacheExpiryDateTime.value().to_rfc3339());
|
||||
}
|
||||
if (authorize_response.idTokenInfo.groupIdToken.has_value()) {
|
||||
validation_result.parent_id_token = {authorize_response.idTokenInfo.groupIdToken.value().idToken.get(),
|
||||
types::authorization::IdTokenType::Central};
|
||||
}
|
||||
} catch (const ocpp::StringConversionException& e) {
|
||||
EVLOG_warning << "Error converting id token to validate: " << e.what();
|
||||
validation_result.authorization_status = types::authorization::AuthorizationStatus::Unknown;
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_warning << "Unknown error during validation of id token: " << e.what();
|
||||
validation_result.authorization_status = types::authorization::AuthorizationStatus::Unknown;
|
||||
}
|
||||
|
||||
return validation_result;
|
||||
}
|
||||
|
||||
types::authorization::ValidationResult
|
||||
auth_token_validatorImpl::validate_standard_request(const types::authorization::ProvidedIdToken& provided_token) {
|
||||
types::authorization::ValidationResult result;
|
||||
try {
|
||||
const auto enhanced_id_tag_info =
|
||||
mod->charge_point->authorize_id_token(ocpp::CiString<20>(provided_token.id_token.value));
|
||||
const auto id_tag_info = enhanced_id_tag_info.id_tag_info;
|
||||
result.authorization_status = conversions::to_everest_authorization_status(id_tag_info.status);
|
||||
if (id_tag_info.expiryDate) {
|
||||
result.expiry_time = id_tag_info.expiryDate->to_rfc3339();
|
||||
}
|
||||
if (id_tag_info.parentIdTag) {
|
||||
result.parent_id_token = {
|
||||
id_tag_info.parentIdTag->get(),
|
||||
types::authorization::IdTokenType::Central}; // For OCPP1.6 no IdTokenType is given,
|
||||
// so we assume it is a central token
|
||||
}
|
||||
if (enhanced_id_tag_info.tariff_message.has_value()) {
|
||||
// this can be used as the TT field of the OCMF.
|
||||
const auto& tariff_message = enhanced_id_tag_info.tariff_message.value();
|
||||
for (const auto& message : tariff_message.message) {
|
||||
result.tariff_messages.push_back(ocpp_conversions::to_everest_display_message_content(message));
|
||||
}
|
||||
}
|
||||
} catch (const ocpp::StringConversionException& e) {
|
||||
EVLOG_warning << "Error converting id token to validate: " << e.what();
|
||||
result.authorization_status = types::authorization::AuthorizationStatus::Unknown;
|
||||
} catch (const std::exception& e) {
|
||||
EVLOG_warning << "Unknown error during validation of id token: " << e.what();
|
||||
result.authorization_status = types::authorization::AuthorizationStatus::Unknown;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
} // namespace auth_validator
|
||||
} // namespace module
|
||||
@@ -0,0 +1,66 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef AUTH_VALIDATOR_AUTH_TOKEN_VALIDATOR_IMPL_HPP
|
||||
#define AUTH_VALIDATOR_AUTH_TOKEN_VALIDATOR_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/auth_token_validator/Implementation.hpp>
|
||||
|
||||
#include "../OCPP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace auth_validator {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class auth_token_validatorImpl : public auth_token_validatorImplBase {
|
||||
public:
|
||||
auth_token_validatorImpl() = delete;
|
||||
auth_token_validatorImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<OCPP>& mod, Conf& config) :
|
||||
auth_token_validatorImplBase(ev, "auth_validator"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual types::authorization::ValidationResult
|
||||
handle_validate_token(types::authorization::ProvidedIdToken& provided_token) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<OCPP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
types::authorization::ValidationResult
|
||||
validate_standard_request(const types::authorization::ProvidedIdToken& provided_token);
|
||||
types::authorization::ValidationResult
|
||||
validate_pnc_request(const types::authorization::ProvidedIdToken& provided_token);
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace auth_validator
|
||||
} // namespace module
|
||||
|
||||
#endif // AUTH_VALIDATOR_AUTH_TOKEN_VALIDATOR_IMPL_HPP
|
||||
477
tools/EVerest-main/modules/EVSE/OCPP/conversions.cpp
Normal file
477
tools/EVerest-main/modules/EVSE/OCPP/conversions.cpp
Normal file
@@ -0,0 +1,477 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include <conversions.hpp>
|
||||
#include <everest/conversions/ocpp/ocpp_conversions.hpp>
|
||||
|
||||
namespace module {
|
||||
namespace conversions {
|
||||
|
||||
ocpp::FirmwareStatusNotification
|
||||
to_ocpp_firmware_status_notification(const types::system::FirmwareUpdateStatusEnum status) {
|
||||
switch (status) {
|
||||
case types::system::FirmwareUpdateStatusEnum::Downloaded:
|
||||
return ocpp::FirmwareStatusNotification::Downloaded;
|
||||
case types::system::FirmwareUpdateStatusEnum::DownloadFailed:
|
||||
return ocpp::FirmwareStatusNotification::DownloadFailed;
|
||||
case types::system::FirmwareUpdateStatusEnum::Downloading:
|
||||
return ocpp::FirmwareStatusNotification::Downloading;
|
||||
case types::system::FirmwareUpdateStatusEnum::DownloadScheduled:
|
||||
return ocpp::FirmwareStatusNotification::DownloadScheduled;
|
||||
case types::system::FirmwareUpdateStatusEnum::DownloadPaused:
|
||||
return ocpp::FirmwareStatusNotification::DownloadPaused;
|
||||
case types::system::FirmwareUpdateStatusEnum::Idle:
|
||||
return ocpp::FirmwareStatusNotification::Idle;
|
||||
case types::system::FirmwareUpdateStatusEnum::InstallationFailed:
|
||||
return ocpp::FirmwareStatusNotification::InstallationFailed;
|
||||
case types::system::FirmwareUpdateStatusEnum::Installing:
|
||||
return ocpp::FirmwareStatusNotification::Installing;
|
||||
case types::system::FirmwareUpdateStatusEnum::Installed:
|
||||
return ocpp::FirmwareStatusNotification::Installed;
|
||||
case types::system::FirmwareUpdateStatusEnum::InstallRebooting:
|
||||
return ocpp::FirmwareStatusNotification::InstallRebooting;
|
||||
case types::system::FirmwareUpdateStatusEnum::InstallScheduled:
|
||||
return ocpp::FirmwareStatusNotification::InstallScheduled;
|
||||
case types::system::FirmwareUpdateStatusEnum::InstallVerificationFailed:
|
||||
return ocpp::FirmwareStatusNotification::InstallVerificationFailed;
|
||||
case types::system::FirmwareUpdateStatusEnum::InvalidSignature:
|
||||
return ocpp::FirmwareStatusNotification::InvalidSignature;
|
||||
case types::system::FirmwareUpdateStatusEnum::SignatureVerified:
|
||||
return ocpp::FirmwareStatusNotification::SignatureVerified;
|
||||
}
|
||||
throw std::out_of_range("Could not convert FirmwareUpdateStatusEnum to FirmwareStatusNotification");
|
||||
}
|
||||
|
||||
ocpp::SessionStartedReason to_ocpp_session_started_reason(const types::evse_manager::StartSessionReason reason) {
|
||||
switch (reason) {
|
||||
case types::evse_manager::StartSessionReason::EVConnected:
|
||||
return ocpp::SessionStartedReason::EVConnected;
|
||||
case types::evse_manager::StartSessionReason::Authorized:
|
||||
return ocpp::SessionStartedReason::Authorized;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::evse_manager::StartSessionReason to ocpp::SessionStartedReason");
|
||||
}
|
||||
|
||||
ocpp::v16::DataTransferStatus to_ocpp_data_transfer_status(const types::ocpp::DataTransferStatus status) {
|
||||
switch (status) {
|
||||
case types::ocpp::DataTransferStatus::Accepted:
|
||||
return ocpp::v16::DataTransferStatus::Accepted;
|
||||
case types::ocpp::DataTransferStatus::Rejected:
|
||||
return ocpp::v16::DataTransferStatus::Rejected;
|
||||
case types::ocpp::DataTransferStatus::UnknownMessageId:
|
||||
return ocpp::v16::DataTransferStatus::UnknownMessageId;
|
||||
case types::ocpp::DataTransferStatus::UnknownVendorId:
|
||||
return ocpp::v16::DataTransferStatus::UnknownVendorId;
|
||||
case types::ocpp::DataTransferStatus::Offline:
|
||||
return ocpp::v16::DataTransferStatus::UnknownVendorId;
|
||||
}
|
||||
return ocpp::v16::DataTransferStatus::UnknownVendorId;
|
||||
}
|
||||
|
||||
ocpp::v16::Reason to_ocpp_reason(const types::evse_manager::StopTransactionReason reason) {
|
||||
switch (reason) {
|
||||
case types::evse_manager::StopTransactionReason::EmergencyStop:
|
||||
return ocpp::v16::Reason::EmergencyStop;
|
||||
case types::evse_manager::StopTransactionReason::EVDisconnected:
|
||||
return ocpp::v16::Reason::EVDisconnected;
|
||||
case types::evse_manager::StopTransactionReason::HardReset:
|
||||
return ocpp::v16::Reason::HardReset;
|
||||
case types::evse_manager::StopTransactionReason::Local:
|
||||
return ocpp::v16::Reason::Local;
|
||||
case types::evse_manager::StopTransactionReason::PowerLoss:
|
||||
return ocpp::v16::Reason::PowerLoss;
|
||||
case types::evse_manager::StopTransactionReason::Reboot:
|
||||
return ocpp::v16::Reason::Reboot;
|
||||
case types::evse_manager::StopTransactionReason::Remote:
|
||||
return ocpp::v16::Reason::Remote;
|
||||
case types::evse_manager::StopTransactionReason::SoftReset:
|
||||
return ocpp::v16::Reason::SoftReset;
|
||||
case types::evse_manager::StopTransactionReason::UnlockCommand:
|
||||
return ocpp::v16::Reason::UnlockCommand;
|
||||
case types::evse_manager::StopTransactionReason::DeAuthorized:
|
||||
return ocpp::v16::Reason::DeAuthorized;
|
||||
case types::evse_manager::StopTransactionReason::EnergyLimitReached:
|
||||
case types::evse_manager::StopTransactionReason::GroundFault:
|
||||
case types::evse_manager::StopTransactionReason::LocalOutOfCredit:
|
||||
case types::evse_manager::StopTransactionReason::MasterPass:
|
||||
case types::evse_manager::StopTransactionReason::OvercurrentFault:
|
||||
case types::evse_manager::StopTransactionReason::PowerQuality:
|
||||
case types::evse_manager::StopTransactionReason::SOCLimitReached:
|
||||
case types::evse_manager::StopTransactionReason::StoppedByEV:
|
||||
case types::evse_manager::StopTransactionReason::TimeLimitReached:
|
||||
case types::evse_manager::StopTransactionReason::Timeout:
|
||||
case types::evse_manager::StopTransactionReason::ReqEnergyTransferRejected:
|
||||
case types::evse_manager::StopTransactionReason::Other:
|
||||
case types::evse_manager::StopTransactionReason::EVSEDisabled:
|
||||
return ocpp::v16::Reason::Other;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::evse_manager::StopTransactionReason to ocpp::v16::Reason");
|
||||
}
|
||||
|
||||
ocpp::v2::CertificateActionEnum to_ocpp_certificate_action_enum(const types::iso15118::CertificateActionEnum action) {
|
||||
switch (action) {
|
||||
case types::iso15118::CertificateActionEnum::Install:
|
||||
return ocpp::v2::CertificateActionEnum::Install;
|
||||
case types::iso15118::CertificateActionEnum::Update:
|
||||
return ocpp::v2::CertificateActionEnum::Update;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert types::iso15118::CertificateActionEnum to ocpp::v2::CertificateActionEnum");
|
||||
}
|
||||
|
||||
ocpp::v16::ReservationStatus to_ocpp_reservation_status(const types::reservation::ReservationResult result) {
|
||||
switch (result) {
|
||||
case types::reservation::ReservationResult::Accepted:
|
||||
return ocpp::v16::ReservationStatus::Accepted;
|
||||
case types::reservation::ReservationResult::Faulted:
|
||||
return ocpp::v16::ReservationStatus::Faulted;
|
||||
case types::reservation::ReservationResult::Occupied:
|
||||
return ocpp::v16::ReservationStatus::Occupied;
|
||||
case types::reservation::ReservationResult::Rejected:
|
||||
return ocpp::v16::ReservationStatus::Rejected;
|
||||
case types::reservation::ReservationResult::Unavailable:
|
||||
return ocpp::v16::ReservationStatus::Unavailable;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::reservation::ReservationResult to ocpp::v16::ReservationStatus");
|
||||
}
|
||||
|
||||
ocpp::v16::LogStatusEnumType to_ocpp_log_status_enum_type(const types::system::UploadLogsStatus status) {
|
||||
switch (status) {
|
||||
case types::system::UploadLogsStatus::Accepted:
|
||||
return ocpp::v16::LogStatusEnumType::Accepted;
|
||||
case types::system::UploadLogsStatus::Rejected:
|
||||
return ocpp::v16::LogStatusEnumType::Rejected;
|
||||
case types::system::UploadLogsStatus::AcceptedCanceled:
|
||||
return ocpp::v16::LogStatusEnumType::AcceptedCanceled;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::system::UploadLogsStatus to ocpp::v16::LogStatusEnumType");
|
||||
}
|
||||
|
||||
ocpp::v16::UpdateFirmwareStatusEnumType
|
||||
to_ocpp_update_firmware_status_enum_type(const types::system::UpdateFirmwareResponse response) {
|
||||
switch (response) {
|
||||
case types::system::UpdateFirmwareResponse::Accepted:
|
||||
return ocpp::v16::UpdateFirmwareStatusEnumType::Accepted;
|
||||
case types::system::UpdateFirmwareResponse::Rejected:
|
||||
return ocpp::v16::UpdateFirmwareStatusEnumType::Rejected;
|
||||
case types::system::UpdateFirmwareResponse::AcceptedCanceled:
|
||||
return ocpp::v16::UpdateFirmwareStatusEnumType::AcceptedCanceled;
|
||||
case types::system::UpdateFirmwareResponse::InvalidCertificate:
|
||||
return ocpp::v16::UpdateFirmwareStatusEnumType::InvalidCertificate;
|
||||
case types::system::UpdateFirmwareResponse::RevokedCertificate:
|
||||
return ocpp::v16::UpdateFirmwareStatusEnumType::RevokedCertificate;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert types::system::UpdateFirmwareResponse to ocpp::v16::UpdateFirmwareStatusEnumType");
|
||||
}
|
||||
|
||||
ocpp::v16::HashAlgorithmEnumType to_ocpp_hash_algorithm_enum_type(const types::iso15118::HashAlgorithm hash_algorithm) {
|
||||
switch (hash_algorithm) {
|
||||
case types::iso15118::HashAlgorithm::SHA256:
|
||||
return ocpp::v16::HashAlgorithmEnumType::SHA256;
|
||||
case types::iso15118::HashAlgorithm::SHA384:
|
||||
return ocpp::v16::HashAlgorithmEnumType::SHA384;
|
||||
case types::iso15118::HashAlgorithm::SHA512:
|
||||
return ocpp::v16::HashAlgorithmEnumType::SHA512;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::iso15118::HashAlgorithm to ocpp::v16::HashAlgorithmEnumType");
|
||||
}
|
||||
|
||||
ocpp::v16::BootReasonEnum to_ocpp_boot_reason_enum(const types::system::BootReason reason) {
|
||||
switch (reason) {
|
||||
case types::system::BootReason::ApplicationReset:
|
||||
return ocpp::v16::BootReasonEnum::ApplicationReset;
|
||||
case types::system::BootReason::FirmwareUpdate:
|
||||
return ocpp::v16::BootReasonEnum::FirmwareUpdate;
|
||||
case types::system::BootReason::LocalReset:
|
||||
return ocpp::v16::BootReasonEnum::LocalReset;
|
||||
case types::system::BootReason::PowerUp:
|
||||
return ocpp::v16::BootReasonEnum::PowerUp;
|
||||
case types::system::BootReason::RemoteReset:
|
||||
return ocpp::v16::BootReasonEnum::RemoteReset;
|
||||
case types::system::BootReason::ScheduledReset:
|
||||
return ocpp::v16::BootReasonEnum::ScheduledReset;
|
||||
case types::system::BootReason::Triggered:
|
||||
return ocpp::v16::BootReasonEnum::Triggered;
|
||||
case types::system::BootReason::Unknown:
|
||||
return ocpp::v16::BootReasonEnum::Unknown;
|
||||
case types::system::BootReason::Watchdog:
|
||||
return ocpp::v16::BootReasonEnum::Watchdog;
|
||||
}
|
||||
throw std::runtime_error("Could not convert BootReasonEnum");
|
||||
}
|
||||
|
||||
ocpp::Powermeter to_ocpp_power_meter(const types::powermeter::Powermeter& powermeter) {
|
||||
ocpp::Powermeter ocpp_powermeter;
|
||||
ocpp_powermeter.timestamp = ocpp_conversions::to_ocpp_datetime_or_now(powermeter.timestamp);
|
||||
ocpp_powermeter.energy_Wh_import = {powermeter.energy_Wh_import.total, powermeter.energy_Wh_import.L1,
|
||||
powermeter.energy_Wh_import.L2, powermeter.energy_Wh_import.L3};
|
||||
|
||||
ocpp_powermeter.meter_id = powermeter.meter_id;
|
||||
ocpp_powermeter.phase_seq_error = powermeter.phase_seq_error;
|
||||
|
||||
if (powermeter.energy_Wh_export.has_value()) {
|
||||
const auto energy_wh_export = powermeter.energy_Wh_export.value();
|
||||
ocpp_powermeter.energy_Wh_export =
|
||||
ocpp::Energy{energy_wh_export.total, energy_wh_export.L1, energy_wh_export.L2, energy_wh_export.L3};
|
||||
}
|
||||
|
||||
if (powermeter.power_W.has_value()) {
|
||||
const auto power_w = powermeter.power_W.value();
|
||||
ocpp_powermeter.power_W = ocpp::Power{power_w.total, power_w.L1, power_w.L2, power_w.L3};
|
||||
}
|
||||
|
||||
if (powermeter.voltage_V.has_value()) {
|
||||
const auto voltage_v = powermeter.voltage_V.value();
|
||||
ocpp_powermeter.voltage_V = ocpp::Voltage{voltage_v.DC, voltage_v.L1, voltage_v.L2, voltage_v.L3};
|
||||
}
|
||||
|
||||
if (powermeter.VAR.has_value()) {
|
||||
const auto var = powermeter.VAR.value();
|
||||
ocpp_powermeter.VAR = ocpp::ReactivePower{var.total, var.L1, var.L2, var.L3};
|
||||
}
|
||||
|
||||
if (powermeter.current_A.has_value()) {
|
||||
const auto current_a = powermeter.current_A.value();
|
||||
ocpp_powermeter.current_A = ocpp::Current{current_a.DC, current_a.L1, current_a.L2, current_a.L3, current_a.N};
|
||||
}
|
||||
|
||||
if (powermeter.frequency_Hz.has_value()) {
|
||||
const auto frequency_hz = powermeter.frequency_Hz.value();
|
||||
ocpp_powermeter.frequency_Hz = ocpp::Frequency{frequency_hz.L1, frequency_hz.L2, frequency_hz.L3};
|
||||
}
|
||||
|
||||
return ocpp_powermeter;
|
||||
}
|
||||
|
||||
std::vector<ocpp::Temperature> to_ocpp_temperatures(const std::vector<types::temperature::Temperature>& temperatures) {
|
||||
std::vector<ocpp::Temperature> ocpp_temperatures;
|
||||
for (const auto temperature : temperatures) {
|
||||
ocpp::Temperature ocpp_temperature;
|
||||
ocpp_temperature.value = temperature.temperature;
|
||||
if (temperature.location.has_value()) {
|
||||
ocpp_temperature.location = temperature.location.value();
|
||||
}
|
||||
ocpp_temperatures.push_back(ocpp_temperature);
|
||||
}
|
||||
return ocpp_temperatures;
|
||||
}
|
||||
|
||||
ocpp::v2::HashAlgorithmEnum to_ocpp_hash_algorithm_enum(const types::iso15118::HashAlgorithm hash_algorithm) {
|
||||
switch (hash_algorithm) {
|
||||
case types::iso15118::HashAlgorithm::SHA256:
|
||||
return ocpp::v2::HashAlgorithmEnum::SHA256;
|
||||
case types::iso15118::HashAlgorithm::SHA384:
|
||||
return ocpp::v2::HashAlgorithmEnum::SHA384;
|
||||
case types::iso15118::HashAlgorithm::SHA512:
|
||||
return ocpp::v2::HashAlgorithmEnum::SHA512;
|
||||
}
|
||||
throw std::out_of_range("Could not convert types::iso15118::HashAlgorithm to ocpp::v16::HashAlgorithmEnumType");
|
||||
}
|
||||
|
||||
types::evse_manager::StopTransactionReason to_everest_stop_transaction_reason(const ocpp::v16::Reason reason) {
|
||||
switch (reason) {
|
||||
case ocpp::v16::Reason::EmergencyStop:
|
||||
return types::evse_manager::StopTransactionReason::EmergencyStop;
|
||||
case ocpp::v16::Reason::EVDisconnected:
|
||||
return types::evse_manager::StopTransactionReason::EVDisconnected;
|
||||
case ocpp::v16::Reason::HardReset:
|
||||
return types::evse_manager::StopTransactionReason::HardReset;
|
||||
case ocpp::v16::Reason::Local:
|
||||
return types::evse_manager::StopTransactionReason::Local;
|
||||
case ocpp::v16::Reason::PowerLoss:
|
||||
return types::evse_manager::StopTransactionReason::PowerLoss;
|
||||
case ocpp::v16::Reason::Reboot:
|
||||
return types::evse_manager::StopTransactionReason::Reboot;
|
||||
case ocpp::v16::Reason::Remote:
|
||||
return types::evse_manager::StopTransactionReason::Remote;
|
||||
case ocpp::v16::Reason::SoftReset:
|
||||
return types::evse_manager::StopTransactionReason::SoftReset;
|
||||
case ocpp::v16::Reason::UnlockCommand:
|
||||
return types::evse_manager::StopTransactionReason::UnlockCommand;
|
||||
case ocpp::v16::Reason::DeAuthorized:
|
||||
return types::evse_manager::StopTransactionReason::DeAuthorized;
|
||||
case ocpp::v16::Reason::Other:
|
||||
return types::evse_manager::StopTransactionReason::Other;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::v16::Reason to types::evse_manager::StopTransactionReason");
|
||||
}
|
||||
|
||||
types::system::ResetType to_everest_reset_type(const ocpp::v16::ResetType type) {
|
||||
switch (type) {
|
||||
case ocpp::v16::ResetType::Hard:
|
||||
return types::system::ResetType::Hard;
|
||||
case ocpp::v16::ResetType::Soft:
|
||||
return types::system::ResetType::Soft;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::v16::ResetType to types::system::ResetType");
|
||||
}
|
||||
|
||||
types::iso15118::Status to_everest_iso15118_status(const ocpp::v2::Iso15118EVCertificateStatusEnum status) {
|
||||
switch (status) {
|
||||
case ocpp::v2::Iso15118EVCertificateStatusEnum::Accepted:
|
||||
return types::iso15118::Status::Accepted;
|
||||
case ocpp::v2::Iso15118EVCertificateStatusEnum::Failed:
|
||||
return types::iso15118::Status::Failed;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::v2::Iso15118EVCertificateStatusEnum to types::iso15118::Status");
|
||||
}
|
||||
|
||||
types::iso15118::CertificateActionEnum
|
||||
to_everest_certificate_action_enum(const ocpp::v2::CertificateActionEnum action) {
|
||||
switch (action) {
|
||||
case ocpp::v2::CertificateActionEnum::Install:
|
||||
return types::iso15118::CertificateActionEnum::Install;
|
||||
case ocpp::v2::CertificateActionEnum::Update:
|
||||
return types::iso15118::CertificateActionEnum::Update;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert ocpp::v2::CertificateActionEnum to types::iso15118::CertificateActionEnum");
|
||||
}
|
||||
|
||||
types::authorization::CertificateStatus
|
||||
to_everest_certificate_status(const ocpp::v2::AuthorizeCertificateStatusEnum status) {
|
||||
switch (status) {
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::Accepted:
|
||||
return types::authorization::CertificateStatus::Accepted;
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::SignatureError:
|
||||
return types::authorization::CertificateStatus::SignatureError;
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::CertificateExpired:
|
||||
return types::authorization::CertificateStatus::CertificateExpired;
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::CertificateRevoked:
|
||||
return types::authorization::CertificateStatus::CertificateRevoked;
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::NoCertificateAvailable:
|
||||
return types::authorization::CertificateStatus::NoCertificateAvailable;
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::CertChainError:
|
||||
return types::authorization::CertificateStatus::CertChainError;
|
||||
case ocpp::v2::AuthorizeCertificateStatusEnum::ContractCancelled:
|
||||
return types::authorization::CertificateStatus::ContractCancelled;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert ocpp::v2::AuthorizeCertificateStatusEnum to types::authorization::CertificateStatus");
|
||||
}
|
||||
|
||||
types::authorization::AuthorizationStatus to_everest_authorization_status(const ocpp::v16::AuthorizationStatus status) {
|
||||
switch (status) {
|
||||
case ocpp::v16::AuthorizationStatus::Accepted:
|
||||
return types::authorization::AuthorizationStatus::Accepted;
|
||||
case ocpp::v16::AuthorizationStatus::Blocked:
|
||||
return types::authorization::AuthorizationStatus::Blocked;
|
||||
case ocpp::v16::AuthorizationStatus::Expired:
|
||||
return types::authorization::AuthorizationStatus::Expired;
|
||||
case ocpp::v16::AuthorizationStatus::Invalid:
|
||||
return types::authorization::AuthorizationStatus::Invalid;
|
||||
case ocpp::v16::AuthorizationStatus::ConcurrentTx:
|
||||
return types::authorization::AuthorizationStatus::ConcurrentTx;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert ocpp::v16::AuthorizationStatus to types::authorization::AuthorizationStatus");
|
||||
}
|
||||
|
||||
types::authorization::AuthorizationStatus
|
||||
to_everest_authorization_status(const ocpp::v2::AuthorizationStatusEnum status) {
|
||||
switch (status) {
|
||||
case ocpp::v2::AuthorizationStatusEnum::Accepted:
|
||||
return types::authorization::AuthorizationStatus::Accepted;
|
||||
case ocpp::v2::AuthorizationStatusEnum::Blocked:
|
||||
return types::authorization::AuthorizationStatus::Blocked;
|
||||
case ocpp::v2::AuthorizationStatusEnum::ConcurrentTx:
|
||||
return types::authorization::AuthorizationStatus::ConcurrentTx;
|
||||
case ocpp::v2::AuthorizationStatusEnum::Expired:
|
||||
return types::authorization::AuthorizationStatus::Expired;
|
||||
case ocpp::v2::AuthorizationStatusEnum::Invalid:
|
||||
return types::authorization::AuthorizationStatus::Invalid;
|
||||
case ocpp::v2::AuthorizationStatusEnum::NoCredit:
|
||||
return types::authorization::AuthorizationStatus::NoCredit;
|
||||
case ocpp::v2::AuthorizationStatusEnum::NotAllowedTypeEVSE:
|
||||
return types::authorization::AuthorizationStatus::NotAllowedTypeEVSE;
|
||||
case ocpp::v2::AuthorizationStatusEnum::NotAtThisLocation:
|
||||
return types::authorization::AuthorizationStatus::NotAtThisLocation;
|
||||
case ocpp::v2::AuthorizationStatusEnum::NotAtThisTime:
|
||||
return types::authorization::AuthorizationStatus::NotAtThisTime;
|
||||
case ocpp::v2::AuthorizationStatusEnum::Unknown:
|
||||
return types::authorization::AuthorizationStatus::Unknown;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert ocpp::v2::AuthorizationStatusEnum to types::authorization::AuthorizationStatus");
|
||||
}
|
||||
|
||||
types::ocpp::ChargingSchedulePeriod
|
||||
to_charging_schedule_period(const ocpp::v16::EnhancedChargingSchedulePeriod& period) {
|
||||
types::ocpp::ChargingSchedulePeriod csp;
|
||||
csp.start_period = period.startPeriod;
|
||||
csp.limit = period.limit;
|
||||
csp.number_phases = period.numberPhases;
|
||||
csp.stack_level = period.stackLevel;
|
||||
return csp;
|
||||
}
|
||||
|
||||
types::ocpp::ChargingSchedule to_charging_schedule(const ocpp::v16::EnhancedChargingSchedule& schedule) {
|
||||
types::ocpp::ChargingSchedule csch = {
|
||||
0,
|
||||
ocpp::v16::conversions::charging_rate_unit_to_string(schedule.chargingRateUnit),
|
||||
{},
|
||||
schedule.duration,
|
||||
std::nullopt,
|
||||
schedule.minChargingRate};
|
||||
for (const auto& i : schedule.chargingSchedulePeriod) {
|
||||
csch.charging_schedule_period.emplace_back(to_charging_schedule_period(i));
|
||||
}
|
||||
if (schedule.startSchedule.has_value()) {
|
||||
csch.start_schedule = schedule.startSchedule.value().to_rfc3339();
|
||||
}
|
||||
return csch;
|
||||
}
|
||||
|
||||
types::ocpp::BootNotificationResponse
|
||||
to_everest_boot_notification_response(const ocpp::v16::BootNotificationResponse& boot_notification_response) {
|
||||
types::ocpp::BootNotificationResponse everest_boot_notification_response;
|
||||
everest_boot_notification_response.status = to_everest_registration_status(boot_notification_response.status);
|
||||
everest_boot_notification_response.current_time = boot_notification_response.currentTime.to_rfc3339();
|
||||
everest_boot_notification_response.interval = boot_notification_response.interval;
|
||||
return everest_boot_notification_response;
|
||||
}
|
||||
|
||||
types::ocpp::RegistrationStatus
|
||||
to_everest_registration_status(const ocpp::v16::RegistrationStatus& registration_status) {
|
||||
switch (registration_status) {
|
||||
case ocpp::v16::RegistrationStatus::Accepted:
|
||||
return types::ocpp::RegistrationStatus::Accepted;
|
||||
case ocpp::v16::RegistrationStatus::Pending:
|
||||
return types::ocpp::RegistrationStatus::Pending;
|
||||
case ocpp::v16::RegistrationStatus::Rejected:
|
||||
return types::ocpp::RegistrationStatus::Rejected;
|
||||
}
|
||||
throw std::out_of_range("Could not convert ocpp::v2::RegistrationStatus to types::ocpp::RegistrationStatus");
|
||||
}
|
||||
|
||||
ocpp::v16::DataTransferStatus
|
||||
to_ocpp_data_transfer_status(const types::display_message::DisplayMessageStatusEnum display_message_status_enum) {
|
||||
switch (display_message_status_enum) {
|
||||
case types::display_message::DisplayMessageStatusEnum::Accepted:
|
||||
return ocpp::v16::DataTransferStatus::Accepted;
|
||||
case types::display_message::DisplayMessageStatusEnum::NotSupportedMessageFormat:
|
||||
return ocpp::v16::DataTransferStatus::Rejected;
|
||||
case types::display_message::DisplayMessageStatusEnum::Rejected:
|
||||
return ocpp::v16::DataTransferStatus::Rejected;
|
||||
case types::display_message::DisplayMessageStatusEnum::NotSupportedPriority:
|
||||
return ocpp::v16::DataTransferStatus::Rejected;
|
||||
case types::display_message::DisplayMessageStatusEnum::NotSupportedState:
|
||||
return ocpp::v16::DataTransferStatus::Rejected;
|
||||
case types::display_message::DisplayMessageStatusEnum::UnknownTransaction:
|
||||
return ocpp::v16::DataTransferStatus::Rejected;
|
||||
}
|
||||
throw std::out_of_range(
|
||||
"Could not convert types::display_message::DisplayMessageStatusEnum to ocpp::v16::DataTransferStatus");
|
||||
}
|
||||
|
||||
ocpp::v16::DataTransferResponse
|
||||
to_ocpp_data_transfer_response(const types::display_message::SetDisplayMessageResponse& set_display_message_response) {
|
||||
ocpp::v16::DataTransferResponse response;
|
||||
response.status = to_ocpp_data_transfer_status(set_display_message_response.status);
|
||||
|
||||
response.data = set_display_message_response.status_info;
|
||||
return response;
|
||||
}
|
||||
} // namespace conversions
|
||||
} // namespace module
|
||||
121
tools/EVerest-main/modules/EVSE/OCPP/conversions.hpp
Normal file
121
tools/EVerest-main/modules/EVSE/OCPP/conversions.hpp
Normal file
@@ -0,0 +1,121 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef OCPP_V16_CONVERSIONS_HPP
|
||||
#define OCPP_V16_CONVERSIONS_HPP
|
||||
|
||||
#include <generated/types/display_message.hpp>
|
||||
#include <generated/types/evse_manager.hpp>
|
||||
#include <generated/types/iso15118.hpp>
|
||||
#include <generated/types/ocpp.hpp>
|
||||
#include <generated/types/reservation.hpp>
|
||||
#include <generated/types/session_cost.hpp>
|
||||
#include <generated/types/system.hpp>
|
||||
|
||||
#include <ocpp/common/types.hpp>
|
||||
#include <ocpp/v16/messages/BootNotification.hpp>
|
||||
#include <ocpp/v16/messages/DataTransfer.hpp>
|
||||
#include <ocpp/v16/messages/GetDiagnostics.hpp>
|
||||
#include <ocpp/v16/messages/LogStatusNotification.hpp>
|
||||
#include <ocpp/v16/messages/ReserveNow.hpp>
|
||||
#include <ocpp/v16/messages/StopTransaction.hpp>
|
||||
#include <ocpp/v16/types.hpp>
|
||||
#include <ocpp/v2/messages/DeleteCertificate.hpp>
|
||||
#include <ocpp/v2/messages/Get15118EVCertificate.hpp>
|
||||
|
||||
namespace module {
|
||||
namespace conversions {
|
||||
|
||||
/// \brief Converts a given types::system::FirmwareUpdateStatusEnum \p status to a ocpp::FirmwareStatusNotification.
|
||||
ocpp::FirmwareStatusNotification
|
||||
to_ocpp_firmware_status_notification(const types::system::FirmwareUpdateStatusEnum status);
|
||||
|
||||
/// \brief Converts a given types::evse_manager::StartSessionReason \p reason to a ocpp::SessionStartedReason.
|
||||
ocpp::SessionStartedReason to_ocpp_session_started_reason(const types::evse_manager::StartSessionReason reason);
|
||||
|
||||
/// \brief Converts a given types::ocpp::DataTransferStatus \p status to a ocpp::v16::DataTransferStatus.
|
||||
ocpp::v16::DataTransferStatus to_ocpp_data_transfer_status(const types::ocpp::DataTransferStatus status);
|
||||
|
||||
/// \brief Converts a given types::evse_manager::StopTransactionReason \p reason to a ocpp::v16::Reason.
|
||||
ocpp::v16::Reason to_ocpp_reason(const types::evse_manager::StopTransactionReason reason);
|
||||
|
||||
/// \brief Converts a given types::iso15118::CertificateActionEnum \p action to a
|
||||
/// ocpp::v2::CertificateActionEnum.
|
||||
ocpp::v2::CertificateActionEnum to_ocpp_certificate_action_enum(const types::iso15118::CertificateActionEnum action);
|
||||
|
||||
/// \brief Converts a given types::reservation::ReservationResult \p result to a ocpp::v16::ReservationStatus.
|
||||
ocpp::v16::ReservationStatus to_ocpp_reservation_status(const types::reservation::ReservationResult result);
|
||||
|
||||
/// \brief Converts a given types::system::UploadLogsStatus \p status to a ocpp::v16::LogStatusEnumType.
|
||||
ocpp::v16::LogStatusEnumType to_ocpp_log_status_enum_type(const types::system::UploadLogsStatus status);
|
||||
|
||||
/// \brief Converts a given types::system::UpdateFirmwareResponse \p response to a
|
||||
/// ocpp::v16::UpdateFirmwareStatusEnumType.
|
||||
ocpp::v16::UpdateFirmwareStatusEnumType
|
||||
to_ocpp_update_firmware_status_enum_type(const types::system::UpdateFirmwareResponse response);
|
||||
|
||||
/// \brief Converts a given types::iso15118::HashAlgorithm \p hash_algorithm to a
|
||||
/// ocpp::v16::HashAlgorithmEnumType.
|
||||
ocpp::v16::HashAlgorithmEnumType to_ocpp_hash_algorithm_enum_type(const types::iso15118::HashAlgorithm hash_algorithm);
|
||||
|
||||
/// \brief Converts a given types::iso15118::Status \p status to a ocpp::v2::Iso15118EVCertificateStatusEnum.
|
||||
ocpp::v16::BootReasonEnum to_ocpp_boot_reason_enum(const types::system::BootReason reason);
|
||||
|
||||
/// \brief Converts a given types::powermeter::Powermeter \p powermeter to a ocpp::Powermeter
|
||||
ocpp::Powermeter to_ocpp_power_meter(const types::powermeter::Powermeter& powermeter);
|
||||
|
||||
/// \brief Converts a given vector of types::temperature::Temperature \p powermeter to a vector of ocpp::Temperature
|
||||
std::vector<ocpp::Temperature> to_ocpp_temperatures(const std::vector<types::temperature::Temperature>& temperatures);
|
||||
|
||||
/// \brief Converts a given types::iso15118::HashAlgorithm \p hash_algorithm to a ocpp::v2::HashAlgorithmEnum.
|
||||
ocpp::v2::HashAlgorithmEnum to_ocpp_hash_algorithm_enum(const types::iso15118::HashAlgorithm hash_algorithm);
|
||||
|
||||
/// \brief Converts a given ocpp::v16::Reason \p reason to a types::evse_manager::StopTransactionReason.
|
||||
types::evse_manager::StopTransactionReason to_everest_stop_transaction_reason(const ocpp::v16::Reason reason);
|
||||
|
||||
/// \brief Converts a given ocpp::v16::ResetType \p type to a types::system::ResetType.
|
||||
types::system::ResetType to_everest_reset_type(const ocpp::v16::ResetType type);
|
||||
|
||||
/// \brief Converts a given ocpp::v2::Iso15118EVCertificateStatusEnum \p status to a types::iso15118::Status.
|
||||
types::iso15118::Status to_everest_iso15118_status(const ocpp::v2::Iso15118EVCertificateStatusEnum status);
|
||||
|
||||
/// \brief Converts a given ocpp::v2::CertificateActionEnum \p action to a
|
||||
/// types::iso15118::CertificateActionEnum.
|
||||
types::iso15118::CertificateActionEnum to_everest_certificate_action_enum(const ocpp::v2::CertificateActionEnum action);
|
||||
|
||||
/// \brief Converts a given ocpp::v2::AuthorizeCertificateStatusEnum \p status to a
|
||||
/// types::authorization::CertificateStatus.
|
||||
types::authorization::CertificateStatus
|
||||
to_everest_certificate_status(const ocpp::v2::AuthorizeCertificateStatusEnum status);
|
||||
|
||||
/// \brief Converts a given ocpp::v16::AuthorizationStatus \p status to a types::authorization::AuthorizationStatus.
|
||||
types::authorization::AuthorizationStatus to_everest_authorization_status(const ocpp::v16::AuthorizationStatus status);
|
||||
|
||||
/// \brief Converts a given ocpp::v2::AuthorizationStatusEnum \p status to a
|
||||
/// types::authorization::AuthorizationStatus.
|
||||
types::authorization::AuthorizationStatus
|
||||
to_everest_authorization_status(const ocpp::v2::AuthorizationStatusEnum status);
|
||||
|
||||
/// \brief Convert ocpp::v16::EnhancedChargingSchedulePeriod to types::ocpp::ChargingSchedulePeriod
|
||||
types::ocpp::ChargingSchedulePeriod
|
||||
to_charging_schedule_period(const ocpp::v16::EnhancedChargingSchedulePeriod& period);
|
||||
|
||||
/// \brief Convert ocpp::v16::EnhancedChargingSchedule to types::ocpp::ChargingSchedule
|
||||
types::ocpp::ChargingSchedule to_charging_schedule(const ocpp::v16::EnhancedChargingSchedule& schedule);
|
||||
|
||||
/// \brief Converts a given ocpp::v16::BootNotificationResponse \p boot_notification_response to a
|
||||
/// types::ocpp::BootNotificationResponse
|
||||
types::ocpp::BootNotificationResponse
|
||||
to_everest_boot_notification_response(const ocpp::v16::BootNotificationResponse& boot_notification_response);
|
||||
|
||||
/// \brief Converts a given ocpp::v16::RegistrationStatus \p registration_status to a
|
||||
/// types::ocpp::RegistrationStatus
|
||||
types::ocpp::RegistrationStatus
|
||||
to_everest_registration_status(const ocpp::v16::RegistrationStatus& registration_status);
|
||||
|
||||
ocpp::v16::DataTransferResponse
|
||||
to_ocpp_data_transfer_response(const types::display_message::SetDisplayMessageResponse& set_display_message_response);
|
||||
|
||||
} // namespace conversions
|
||||
} // namespace module
|
||||
|
||||
#endif // OCPP_V16_CONVERSIONS_HPP
|
||||
@@ -0,0 +1,51 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "ocpp_data_transferImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace data_transfer {
|
||||
|
||||
void ocpp_data_transferImpl::init() {
|
||||
}
|
||||
|
||||
void ocpp_data_transferImpl::ready() {
|
||||
}
|
||||
|
||||
types::ocpp::DataTransferStatus to_everest(ocpp::v16::DataTransferStatus status) {
|
||||
switch (status) {
|
||||
case ocpp::v16::DataTransferStatus::Accepted:
|
||||
return types::ocpp::DataTransferStatus::Accepted;
|
||||
case ocpp::v16::DataTransferStatus::Rejected:
|
||||
return types::ocpp::DataTransferStatus::Rejected;
|
||||
case ocpp::v16::DataTransferStatus::UnknownMessageId:
|
||||
return types::ocpp::DataTransferStatus::UnknownMessageId;
|
||||
case ocpp::v16::DataTransferStatus::UnknownVendorId:
|
||||
return types::ocpp::DataTransferStatus::UnknownVendorId;
|
||||
default:
|
||||
return types::ocpp::DataTransferStatus::UnknownVendorId;
|
||||
}
|
||||
}
|
||||
|
||||
types::ocpp::DataTransferResponse
|
||||
ocpp_data_transferImpl::handle_data_transfer(types::ocpp::DataTransferRequest& request) {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle data transfer command";
|
||||
types::ocpp::DataTransferResponse response;
|
||||
response.status = types::ocpp::DataTransferStatus::Offline;
|
||||
return response;
|
||||
}
|
||||
|
||||
auto ocpp_response = mod->charge_point->data_transfer(request.vendor_id, request.message_id, request.data);
|
||||
types::ocpp::DataTransferResponse response;
|
||||
if (ocpp_response.has_value()) {
|
||||
response.status = to_everest(ocpp_response.value().status);
|
||||
response.data = ocpp_response.value().data;
|
||||
} else {
|
||||
response.status = types::ocpp::DataTransferStatus::Offline;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
} // namespace data_transfer
|
||||
} // namespace module
|
||||
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef DATA_TRANSFER_OCPP_DATA_TRANSFER_IMPL_HPP
|
||||
#define DATA_TRANSFER_OCPP_DATA_TRANSFER_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ocpp_data_transfer/Implementation.hpp>
|
||||
|
||||
#include "../OCPP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace data_transfer {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ocpp_data_transferImpl : public ocpp_data_transferImplBase {
|
||||
public:
|
||||
ocpp_data_transferImpl() = delete;
|
||||
ocpp_data_transferImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<OCPP>& mod, Conf& config) :
|
||||
ocpp_data_transferImplBase(ev, "data_transfer"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual types::ocpp::DataTransferResponse handle_data_transfer(types::ocpp::DataTransferRequest& request) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<OCPP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace data_transfer
|
||||
} // namespace module
|
||||
|
||||
#endif // DATA_TRANSFER_OCPP_DATA_TRANSFER_IMPL_HPP
|
||||
400
tools/EVerest-main/modules/EVSE/OCPP/docs/index.rst
Normal file
400
tools/EVerest-main/modules/EVSE/OCPP/docs/index.rst
Normal file
@@ -0,0 +1,400 @@
|
||||
.. _everest_modules_handwritten_OCPP:
|
||||
|
||||
.. **************
|
||||
.. OCPP1.6 Module
|
||||
.. **************
|
||||
|
||||
This module implements and integrates OCPP1.6 within EVerest, including all feature profiles defined by the specification. A connection
|
||||
to a Charging Station Management System (CSMS) can be established by loading this module as part of the EVerest configuration. This module
|
||||
leverages `libocpp <https://github.com/EVerest/libocpp>`_, EVerest's OCPP library.
|
||||
|
||||
The EVerest config ``config-sil-ocpp.yaml`` serves as an example for how to add the OCPP module to
|
||||
your EVerest config.
|
||||
|
||||
Module configuration
|
||||
====================
|
||||
|
||||
Like for every EVerest module, the configuration parameters are defined as part of the module ``manifestyaml``. This module
|
||||
is a little special though. The OCPP1.6 protocol defines a lot of standardized configuration keys that are used as part of the functional
|
||||
requirements of the specification. These configuration keys mainly influence the control flow of libocpp and are managed by a separate
|
||||
JSON configuration file. The module uses the configuration parameter **ChargePointConfigPath** to point to this file.
|
||||
|
||||
:doc:`This EVerest OCPP tutorial </tutorials/ocpp16>`, the OCPP specification, and
|
||||
`libocpp's documentation <https://github.com/EVerest/libocpp>`_ are great resources to learn about the different configuration options.
|
||||
|
||||
Integration in EVerest
|
||||
======================
|
||||
|
||||
This module leverages `libocpp <https://github.com/EVerest/libocpp>`_, EVerest's OCPP library. Libocpp's approach to implementing the
|
||||
OCPP protocol is to do as much work as possible as part of the library. It therefore fulfills a large amount of protocol requirements
|
||||
internally. OCPP is a protocol that affects, controls, and monitors many areas of a charging station's operation, though. It is therefore
|
||||
required to integrate libocpp with other parts of EVerest. This integration is done by this module and will be explained in this section.
|
||||
|
||||
For a detailed description of libocpp and its functionalities, please refer to `its documentation <https://github.com/EVerest/libocpp>`_.
|
||||
|
||||
The ``manifest.yaml`` of this module defines requirements and implementations of EVerest interfaces to integrate the OCPP
|
||||
communication with other parts of EVerest. In order to describe how the responsibilities for functions and operations required by OCPP
|
||||
are divided between libocpp and this module, the following sections pick up the requirements of this module and implementations one by one.
|
||||
|
||||
Provides: main
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`ocpp_1_6_charge_point <everest_interfaces_ocpp_1_6_charge_point>`
|
||||
|
||||
This interface is implemented to provide an API to control the websocket connection and to control and retrieve OCPP-specific data like
|
||||
security events and configuration keys.
|
||||
|
||||
*Note: This interface is deprecated soon and will be removed soon. The functionality is already covered by the generic interface*
|
||||
:ref:`ocpp <everest_interfaces_ocpp>` *which is used by this module and OCPP201.*
|
||||
|
||||
Provides: auth_validator
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`auth_token_validator <everest_interfaces_auth_token_validator>`
|
||||
|
||||
This interface is implemented to forward authorization requests from EVerest to libocpp. Libocpp contains the business logic to either
|
||||
validate the authorization request locally using the authorization cache and local authorization list or to forward the request to the
|
||||
CSMS using an **Authorize.req**. The implementation also covers the validation of Plug&Charge authorization requests by triggering a
|
||||
`DataTransfer.req(Authorize)`.
|
||||
|
||||
Provides: auth_provider
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`auth_token_provider <everest_interfaces_auth_token_provider>`
|
||||
|
||||
This interface is implemented to publish authorization requests from the CSMS within EVerest. An authorization request from the CSMS is
|
||||
turned out by a **RemoteStartTransaction.req**.
|
||||
|
||||
Provides: data_transfer
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`ocpp_data_transfer <everest_interfaces_ocpp_data_transfer>`
|
||||
|
||||
This interface is implemented to provide a command to initiate a **DataTransfer.req** from the charging station to the CSMS.
|
||||
|
||||
.. _handwritten_ocpp_provides-ocpp_generic:
|
||||
|
||||
Provides: ocpp_generic
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`ocpp <everest_interfaces_ocpp>`
|
||||
|
||||
This interface is implemented to provide an API to control an OCPP service and to set and get OCPP-specific data.
|
||||
|
||||
Provides: session_cost
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`session_cost <everest_interfaces_session_cost>`
|
||||
|
||||
This interface is implemented to publish session costs received by the CSMS as part of the California Pricing whitepaper extension.
|
||||
|
||||
Requires: evse_manager
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`evse_manager <everest_interfaces_evse_manager>`
|
||||
|
||||
Typically the :ref:`EvseManager <everest_modules_EvseManager>` module is used to fulfill this requirement.
|
||||
|
||||
This module requires (1-128) implementations of this interface 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.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **get_evse** to get the EVSE id of the module implementing the **evse_manager** interface at startup
|
||||
* **pause_charging** to pause charging in case a **StopTransaction.conf** indicates charging shall be paused
|
||||
* **resume_charging** to resume charging
|
||||
* **stop_transaction** to stop a transaction in case the CSMS stops a transaction by e.g. a **RemoteStopTransaction.req**
|
||||
* **force_unlock** to force the unlock of a connector in case the CSMS sends a **UnlockConnector.req**
|
||||
* **enable_disable** to set the EVSE to operative or inoperative, e.g., in case the CSMS sends a **ChangeAvailability.req**. This command can
|
||||
be called from different sources. It therefore contains an argument **priority** in order to override the status if required. OCPP uses
|
||||
a priority of 5000, which is mid-range.
|
||||
* **set_external_limits** to apply a power or ampere limits at the EVSE received by the CSMS using the SmartCharging feature profile.
|
||||
Libocpp contains the business logic to calculate the composite schedule for received charging profiles. This module gets notified in
|
||||
case charging profiles are added, changed, or cleared. When notified, this module requests the composite schedule from libocpp and
|
||||
publishes the result via the provided :ref:`ocpp_generic <handwritten_ocpp_provides-ocpp_generic>` interface implementation. The duration of the composite schedule can
|
||||
be configured by the configuration parameter **PublishChargingScheduleDurationS** of this module. The configuration parameter
|
||||
**PublishChargingScheduleIntervalS** defines the interval to use to periodically retrieve and publish the composite schedules.
|
||||
* **external_ready_to_start_charging**: To signal that the module has started to establish an OCPP connection to the CSMS
|
||||
|
||||
The interface is used to receive the following variables:
|
||||
|
||||
* **powermeter** to push powermeter values of an EVSE. Libocpp initiates **MeterValues.req** internally and is responsible to comply with
|
||||
the configured intervals and measurands for clock-aligned and sampled meter values.
|
||||
* **ev_info** to obtain the state of charge (SoC) of an EV. If present, this is reported as part of a **MeterValues.req**
|
||||
* **limits** to obtain the current offered to the EV. If present, this is reported as part of a **MeterValues.req**
|
||||
* **session_event** to trigger **StatusNotification.req**, **StartTransaction.req**, and **StopTransaction.req** based on the reported event.
|
||||
This signal drives the state machine and the transaction handling of libocpp.
|
||||
* **waiting_for_external_ready** to obtain the information that a module implementing this interface is waiting for an external ready signal
|
||||
* **ready** to obtain a ready signal from a module implementing this interface
|
||||
|
||||
Requires: connector_zero_sink
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`external_energy_limits <everest_interfaces_external_energy_limits>`
|
||||
|
||||
Typically the :ref:`EnergyNode <everest_modules_EnergyNode>` module is used to fulfill this requirement.
|
||||
|
||||
This module optionally requires the connection to a module implementing the **external_energy_limits** interface. This connection is used
|
||||
to apply power or ampere limits at EVSE id zero received by the CSMS using the SmartCharging feature profile.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **set_external_limits** to apply a power or ampere limits for EVSE id zero (the whole charging station).
|
||||
|
||||
Requires: reservation
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`reservation <everest_interfaces_reservation>`
|
||||
|
||||
Typically the :ref:`Auth <everest_modules_Auth>` module is used to fulfill this requirement.
|
||||
|
||||
This module requires a connection to a module implementing the `reservation` interface. This connection is used to apply reservation
|
||||
requests from the CSMS.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **reserve_now** which is called when the CSMS sends a **ReserveNow.req**
|
||||
* **cancel_reservation** which is called when the CSMS sends a **CancelReservation.req**
|
||||
|
||||
Requires: auth
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`auth <everest_interfaces_auth>`
|
||||
|
||||
Typically the :ref:`Auth <everest_modules_Auth>` module is used to fulfill this requirement.
|
||||
|
||||
This module requires a connection to a module implementing the **auth** interface. This connection is used to set the standardized
|
||||
**ConnectionTimeout** configuration key if configured and/or changed by the CSMS.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **set_connection_timeout** which is e.g., called in case the CSMS uses a **ChangeConfiguration.req(ConnectionTimeout)**
|
||||
|
||||
Requires: system
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`system <everest_interfaces_system>`
|
||||
|
||||
The :ref:`System <everest_modules_System>` module can be used to fulfill this requirement. Note that this module is not meant to be used in
|
||||
production systems without any modification!
|
||||
|
||||
This module requires a connection to a module implementing the **system** interface. 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.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **update_firmware** to forward **UpdateFirmware.req** or **SignedUpdateFirmware.req** messages from the CSMS
|
||||
* **allow_firmware_installation** to notify the module that the installation of the firmware is now allowed. A prerequisite for this
|
||||
is that all EVSEs are set to inoperative. This module and libocpp take care of setting the EVSEs to inoperative before calling
|
||||
this command.
|
||||
* **upload_logs** to forward **GetDiagnostics.req** or **GetLog.req** messages from the CSMS
|
||||
* **is_reset_allowed** to check if a **Reset.req** message from the CSMS shall be accepted or rejected
|
||||
* **reset** to perform a reset in case of a **Reset.req** message from the CSMS
|
||||
* **set_system_time** to set the system time communicated by a **BootNotification.conf** or **Heartbeat.conf** messages from the CSMS
|
||||
* **get_boot_reason** to obtain the boot reason to use it as part of the **BootNotification.req** at startup
|
||||
|
||||
The interface is used to receive the following variables:
|
||||
|
||||
* **log_status** to obtain the log update status. This triggers a **LogStatusNotification.req** or **DiagnosticsStatusNotification.req**
|
||||
message to inform the CSMS about the current status. This signal is expected as a result of an **upload_logs** command.
|
||||
* **firmware_update_status** to obtain the firmware update status. This triggers a **FirmwareStatusNotification.req** or
|
||||
**SignedFirmwareStatusNotification.req** message to inform the CSMS about the current status. This signal is expected as a result
|
||||
of an **update_firmware** command.
|
||||
|
||||
Requires: security
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`evse_security <everest_interfaces_evse_security>`
|
||||
|
||||
This module requires a connection to a module implementing the `evse_security` interface. This connection is used to execute
|
||||
security-related operations and to manage certificates and private keys.
|
||||
|
||||
Typically the :ref:`EvseSecurity <everest_modules_EvseSecurity>` module is used to fulfill this requirement.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **install_ca_certificate** to handle **InstallCertificate.req** and **DataTransfer.req(InstallCertificate)** messages from the CSMS
|
||||
* **delete_certificate** to handle **DeleteCertificate.req** and **DataTransfer.req(DeleteCertificate)** messages from the CSMS
|
||||
* **update_leaf_certificate** to handle **CertificateSigned.req** and **DataTransfer.req(CertificateSigned)** messages from the CSMS
|
||||
* **verify_certificate** to verify certificates from the CSMS that are sent as part of **SignedUpdateFirmware.req**
|
||||
* **get_installed_certificates** to handle **GetInstalledCertificateIds.req** and **DataTransfer.req(GetInstalledCertificateIds)**
|
||||
messages from the CSMS
|
||||
* **get_v2g_ocsp_request_data** to update the OCSP cache of V2G sub-CA certificates using a **DataTransfer.req(GetCertificateStatus)**.
|
||||
Triggering this message is handled by libocpp internally
|
||||
* **get_mo_ocsp_request_data** to include the **iso15118CertificateHashData** as part of a **DataTransfer.req(Authorize)** for Plug&Charge
|
||||
if required
|
||||
* **update_ocsp_cache** to update the OCSP cache which is part of a **DataTransfer.conf(GetCertificateStatus)** message from the CSMS
|
||||
* **is_ca_certificate_installed** to verify if a certain CA certificate is installed
|
||||
* **generate_certificate_signing_request** to generate a CSR that can be used as part of a **SignCertificate.req** and
|
||||
`DataTransfer.req(SignCertificate)` message to the CSMS.
|
||||
* **get_leaf_certificate_info** to get the certificate and private key path of the CSMS client certificate used for security profile 3.
|
||||
* **get_verify_file** to get the path to a CA bundle that can be used for verifying, e.g., the CSMS TLS server certificate
|
||||
* **get_leaf_expiry_days_count** to determine when a leaf certificate expires. This information is used by libocpp in order to renew
|
||||
leaf certificates in case they expire soon
|
||||
|
||||
Note that a lot of conversion between the libocpp types and the generated EVerest types are required for the given commands. Since the
|
||||
conversion functionality is used by this OCPP module and the OCPP201 module, it is implemented as a
|
||||
`separate library <../../../../../lib/everest/conversions/ocpp/>`_ .
|
||||
|
||||
Requires: data_transfer
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`ocpp_data_transfer <everest_interfaces_ocpp_data_transfer>`
|
||||
|
||||
This module optionally requires a connection to a module implementing the **ocpp_data_transfer** interface. 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.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **data_transfer** to forward **DataTransfer.req** messages from the CSMS
|
||||
|
||||
Requires: display_message
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`display_message <everest_interfaces_display_message>`
|
||||
|
||||
This module optionally requires a connection to a module implementing the **display_message** interface. This connection is used to allow
|
||||
the CSMS to display pricing or other information on the display of a charging station.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **set_display_message** to set a message on the charging station's display. This is executed when the CSMS sends a
|
||||
|
||||
Requires: extensions_15118
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Interface**: :ref:`iso15118_extensions <everest_interfaces_iso15118_extensions>`
|
||||
|
||||
This module optionally requires (0-128) implementations of this interface in order to share data between ISO15118 and OCPP modules. One
|
||||
connection represents one ISO15118 module.
|
||||
|
||||
This module makes use of the following commands of this interface:
|
||||
|
||||
* **set_get_certificate_response** to report that the charging station received a **DataTransfer.conf(Get15118EVCertificateResponse)** from
|
||||
the CSMS (EV Contract installation for Plug&Charge)
|
||||
|
||||
The interface is used to receive the following variables:
|
||||
|
||||
* **iso15118_certificate_request** to trigger a **DataTransfer.req(Get15118EVCertificateRequest)** as part of the Plug&Charge process
|
||||
|
||||
Global Errors and Error Reporting
|
||||
=================================
|
||||
|
||||
The **enable_global_errors** flag for this module is enabled in its manifest. This module is therefore able to retrieve and process all reported errors
|
||||
from other modules loaded in the same EVerest configuration.
|
||||
|
||||
In OCPP1.6 errors can be reported using the **StatusNotification.req** message. If this module gets notified about a raised error,
|
||||
it initiates a **StatusNotification.req** that contains information about the error that has been raised.
|
||||
|
||||
The field **status** of the **StatusNotification.req** will be set to faulted only in case the error is of the special type
|
||||
**evse_manager/Inoperative**. The field **connectorId** is set based on the mapping (for EVSE id and connector id) of the origin of the error.
|
||||
If no mapping is provided, the error will be reported on connectorId 0. Note that the mapping can be configured per module inside the
|
||||
EVerest config file.
|
||||
|
||||
For all other errors, raised in EVerest, the following mapping to an
|
||||
OCPP **StatusNotification.req** will be used:
|
||||
|
||||
* **StatusNotification.req** property ``errorCode`` will always be
|
||||
``OtherError``
|
||||
* **StatusNotification.req** property ``status`` will reflect the present status of the
|
||||
charge point
|
||||
* **StatusNotification.req** property ``info`` -> origin of EVerest error
|
||||
* **StatusNotification.req** property ``vendorErrorCode`` -> EVerest error type and
|
||||
subtype (the error type is simplified, meaning, that its leading part,
|
||||
the interface name, is stripped)
|
||||
* **StatusNotification.req** property ``vendorId`` -> EVerest error message
|
||||
|
||||
The reason for using the **StatusNotification.req** property property
|
||||
``vendorId`` for the error message is that it can carry the largest
|
||||
string (255 characters), whereas the other fields (``info`` and
|
||||
``vendorErrorCode``) only allow up to 50 characters.
|
||||
|
||||
If for example the module with id `yeti_driver` within its
|
||||
implementation with id `board_support` creates the following error:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
error_factory->create_error("evse_board_support/EnergyManagement",
|
||||
"OutOfEnergy", "someone cut the wires")
|
||||
|
||||
the corresponding fields in the **StatusNotification.req** message will
|
||||
look like this:
|
||||
|
||||
.. code-block:: JSON
|
||||
|
||||
{
|
||||
"info": "yeti_driver->board_support",
|
||||
"vendorErrorCode": "EnergyManagement/OutOfEnergy",
|
||||
"vendorId": "someone cut the wires"
|
||||
}
|
||||
|
||||
The **StatusNotification.req** message has some limitations with respect
|
||||
to reporting errors:
|
||||
|
||||
* Single errors cannot simply be cleared. If multiple errors are raised,
|
||||
it is not possible to clear individual errors.
|
||||
* ``vendorId``, ``info`` and ``vendorErrorCode`` are limited in length
|
||||
(see above).
|
||||
|
||||
This module attempts to follow the Minimum Required Error Codes (MRECS): https://inl.gov/chargex/mrec/. This proposes a unified
|
||||
methodology to define and classify a minimum required set of error codes and how to report them via OCPP1.6.
|
||||
|
||||
This module currently deviates from the MREC specification in the following points:
|
||||
|
||||
* Simultaneous errors: MREC requires reporting simultaneous errors by reporting them in a single **StatusNotification.req** by separating
|
||||
the information of the fields **vendorId** and **info** by a semicolon. This module sends one **StatusNotification.req** per individual error
|
||||
because of the limited maximum characters of the **info** field.
|
||||
* MREC requires always using the value **Faulted** for the **status** field when reporting an error. The OCPP1.6 specification defines the
|
||||
**Faulted** value as follows: "When a Charge Point or connector has reported an error and is not available for energy delivery.
|
||||
(Inoperative)." This module, therefore, only reports **Faulted** when the Charge Point is not available for energy delivery.
|
||||
|
||||
Energy Management and Smart Charging Integration
|
||||
================================================
|
||||
|
||||
OCPP1.6 defines the SmartCharging feature profile to allow the CSMS to control or influence the power consumption of the charging station.
|
||||
This module integrates the composite schedule(s) within EVerest's energy management. For further information about smart charging and the
|
||||
composite schedule calculation please refer to the OCPP1.6 specification.
|
||||
|
||||
The integration of the composite schedules is implemented through the optional requirement(s) `evse_energy_sink` (interface: `external_energy_limits`)
|
||||
of this module. Depending on the number of EVSEs configured, each composite limit is communicated via a seperate sink, including the composite schedule
|
||||
for EVSE with id 0 (representing the whole charging station). The easiest way to explain this is with an example. If your charging station
|
||||
has two EVSEs you need to connect three modules that implement the `external_energy_limits` interface: One representing evse id 0 and
|
||||
two representing your actual EVSEs.
|
||||
|
||||
📌 **Note:** You have to configure an evse mapping for each module connected via the evse_energy_sink connection. This allows the module to identify
|
||||
which requirement to use when communicating the limits for the EVSEs. For more information about the module mapping please see
|
||||
:doc:`3-tier module mappings </explanation/tier-module-mappings>`.
|
||||
|
||||
This module defines a callback that gets executed every time charging profiles are changed, added or removed by the CSMS. The callback retrieves
|
||||
the composite schedules for all EVSEs (including evse id 0) and calls the `set_external_limits` command of the respective requirement that implements
|
||||
the `external_energy_limits` interface. In addition, the config parameter `PublishChargingScheduleIntervalS` defines a periodic interval to retrieve
|
||||
the composite schedule also in case no charging profiles have been changed. The configuration parameter `PublishChargingScheduleDurationS` defines
|
||||
the duration in seconds of the requested composite schedules starting now. The value configured for `PublishChargingScheduleDurationS` shall be greater
|
||||
than the value configured for `PublishChargingScheduleIntervalS` because otherwise time periods could be missed by the application.
|
||||
|
||||
|
||||
Certificate Management
|
||||
======================
|
||||
|
||||
Two leaf certificates are managed by the OCPP communication enabled by this module:
|
||||
|
||||
* CSMS Leaf certificate (used for mTLS for SecurityProfile3)
|
||||
* SECC Leaf certificate (Server certificate for ISO15118)
|
||||
|
||||
60 seconds after the first **BootNotification.req** message has been accepted by the CSMS, the charging station will check if the existing
|
||||
certificates are not present or have been expired. If this is the case, the charging station initiates the process of requesting a new
|
||||
certificate by sending a certificate signing request to CSMS.
|
||||
|
||||
For the CSMS Leaf certificate, this process is only triggered if SecurityProfile 3 is used.
|
||||
|
||||
For the SECC Leaf certificate, this process is only triggered if Plug&Charge is enabled by setting the **ISO15118CertificateManagementEnabled** to **true**.
|
||||
|
||||
If a certificate has expired is then periodically checked every 12 hours.
|
||||
|
||||
In addition to that, the charging station periodically updates the OCSP responses of the sub-CA certificates of the V2G certificate chain.
|
||||
The OCSP response is cached and can be used as part of the ISO15118 TLS handshake with EVs. The OCSP update is by default performed
|
||||
every seven days (or can be configured using the **OCSPRequestInterval** configuration key).
|
||||
The timestamp of the last update is stored persistently, so that this process is not necessarily performed at every start up.
|
||||
|
||||
48
tools/EVerest-main/modules/EVSE/OCPP/error_mapping.hpp
Normal file
48
tools/EVerest-main/modules/EVSE/OCPP/error_mapping.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef OCPP_ERROR_MAPPING_HPP
|
||||
#define OCPP_ERROR_MAPPING_HPP
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <ocpp/v16/ocpp_enums.hpp>
|
||||
|
||||
namespace module {
|
||||
|
||||
const std::string CHARGE_X_MREC_VENDOR_ID = "https://chargex.inl.gov";
|
||||
|
||||
// Error type mappings
|
||||
const std::unordered_map<std::string, std::pair<ocpp::v16::ChargePointErrorCode, std::string>> MREC_ERROR_MAP = {
|
||||
{"connector_lock/MREC1ConnectorLockFailure", {ocpp::v16::ChargePointErrorCode::ConnectorLockFailure, "CX001"}},
|
||||
{"evse_board_support/MREC2GroundFailure", {ocpp::v16::ChargePointErrorCode::GroundFailure, "CX002"}},
|
||||
{"evse_board_support/MREC3HighTemperature", {ocpp::v16::ChargePointErrorCode::HighTemperature, "CX003"}},
|
||||
{"evse_board_support/MREC4OverCurrentFailure", {ocpp::v16::ChargePointErrorCode::OverCurrentFailure, "CX004"}},
|
||||
{"evse_board_support/MREC5OverVoltage", {ocpp::v16::ChargePointErrorCode::OverVoltage, "CX005"}},
|
||||
{"evse_board_support/MREC6UnderVoltage", {ocpp::v16::ChargePointErrorCode::UnderVoltage, "CX006"}},
|
||||
{"evse_board_support/MREC8EmergencyStop", {ocpp::v16::ChargePointErrorCode::OtherError, "CX008"}},
|
||||
{"evse_board_support/MREC10InvalidVehicleMode", {ocpp::v16::ChargePointErrorCode::OtherError, "CX010"}},
|
||||
{"evse_board_support/MREC14PilotFault", {ocpp::v16::ChargePointErrorCode::OtherError, "CX014"}},
|
||||
{"evse_board_support/MREC15PowerLoss", {ocpp::v16::ChargePointErrorCode::OtherError, "CX015"}},
|
||||
{"evse_board_support/MREC17EVSEContactorFault", {ocpp::v16::ChargePointErrorCode::OtherError, "CX017"}},
|
||||
{"evse_board_support/MREC18CableOverTempDerate", {ocpp::v16::ChargePointErrorCode::OtherError, "CX018"}},
|
||||
{"evse_board_support/MREC19CableOverTempStop", {ocpp::v16::ChargePointErrorCode::OtherError, "CX019"}},
|
||||
{"evse_board_support/MREC20PartialInsertion", {ocpp::v16::ChargePointErrorCode::OtherError, "CX020"}},
|
||||
{"evse_board_support/MREC23ProximityFault", {ocpp::v16::ChargePointErrorCode::OtherError, "CX023"}},
|
||||
{"evse_board_support/MREC24ConnectorVoltageHigh", {ocpp::v16::ChargePointErrorCode::OtherError, "CX024"}},
|
||||
{"evse_board_support/MREC25BrokenLatch", {ocpp::v16::ChargePointErrorCode::OtherError, "CX025"}},
|
||||
{"evse_board_support/MREC26CutCable", {ocpp::v16::ChargePointErrorCode::OtherError, "CX026"}},
|
||||
{"evse_manager/MREC4OverCurrentFailure", {ocpp::v16::ChargePointErrorCode::OverCurrentFailure, "CX004"}},
|
||||
{"ac_rcd/MREC2GroundFailure", {ocpp::v16::ChargePointErrorCode::GroundFailure, "CX002"}},
|
||||
{"evse_manager/MREC22ResistanceFault", {ocpp::v16::ChargePointErrorCode::OtherError, "CX022"}},
|
||||
{"evse_manager/MREC11CableCheckFault", {ocpp::v16::ChargePointErrorCode::OtherError, "CX011"}},
|
||||
{"evse_manager/MREC5OverVoltage", {ocpp::v16::ChargePointErrorCode::OverVoltage, "CX005"}},
|
||||
};
|
||||
|
||||
// TODO: add other ChargePointErrorCode mappings
|
||||
const std::unordered_map<std::string, ocpp::v16::ChargePointErrorCode> OCPP_ERROR_MAP = {
|
||||
{"powermeter/CommunicationFault", ocpp::v16::ChargePointErrorCode::PowerMeterFailure},
|
||||
};
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,141 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright 2020 - 2022 Pionix GmbH and Contributors to EVerest
|
||||
#include "ocpp_1_6_charge_pointImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace main {
|
||||
|
||||
void ocpp_1_6_charge_pointImpl::init() {
|
||||
}
|
||||
|
||||
void ocpp_1_6_charge_pointImpl::ready() {
|
||||
}
|
||||
|
||||
bool ocpp_1_6_charge_pointImpl::handle_stop() {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle stop command";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->m);
|
||||
mod->charging_schedules_timer->stop();
|
||||
bool success = mod->charge_point->stop();
|
||||
if (success) {
|
||||
this->mod->ocpp_stopped = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
bool ocpp_1_6_charge_pointImpl::handle_restart() {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle restart command";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->m);
|
||||
mod->charging_schedules_timer->interval(std::chrono::seconds(this->mod->config.PublishChargingScheduleIntervalS));
|
||||
bool success = mod->charge_point->restart();
|
||||
if (success) {
|
||||
this->mod->ocpp_stopped = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
types::ocpp::KeyValue to_everest(const ocpp::v16::KeyValue& key_value) {
|
||||
types::ocpp::KeyValue _key_value;
|
||||
_key_value.key = key_value.key.get();
|
||||
_key_value.read_only = key_value.readonly;
|
||||
if (key_value.value.has_value()) {
|
||||
_key_value.value = key_value.value.value().get();
|
||||
}
|
||||
return _key_value;
|
||||
}
|
||||
|
||||
types::ocpp::ConfigurationStatus to_everest(const ocpp::v16::ConfigurationStatus status) {
|
||||
switch (status) {
|
||||
case ocpp::v16::ConfigurationStatus::Accepted:
|
||||
return types::ocpp::ConfigurationStatus::Accepted;
|
||||
case ocpp::v16::ConfigurationStatus::Rejected:
|
||||
return types::ocpp::ConfigurationStatus::Rejected;
|
||||
case ocpp::v16::ConfigurationStatus::RebootRequired:
|
||||
return types::ocpp::ConfigurationStatus::RebootRequired;
|
||||
case ocpp::v16::ConfigurationStatus::NotSupported:
|
||||
return types::ocpp::ConfigurationStatus::NotSupported;
|
||||
default:
|
||||
EVLOG_warning << "Could not convert to ConfigurationStatus";
|
||||
return types::ocpp::ConfigurationStatus::Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
types::ocpp::GetConfigurationResponse to_everest(const ocpp::v16::GetConfigurationResponse& response) {
|
||||
types::ocpp::GetConfigurationResponse _response;
|
||||
std::vector<types::ocpp::KeyValue> configuration_keys;
|
||||
std::vector<std::string> unknown_keys;
|
||||
|
||||
if (response.configurationKey.has_value()) {
|
||||
for (const auto& item : response.configurationKey.value()) {
|
||||
configuration_keys.push_back(to_everest(item));
|
||||
}
|
||||
}
|
||||
|
||||
if (response.unknownKey.has_value()) {
|
||||
for (const auto& item : response.unknownKey.value()) {
|
||||
unknown_keys.push_back(item.get());
|
||||
}
|
||||
}
|
||||
|
||||
_response.configuration_keys = configuration_keys;
|
||||
_response.unknown_keys = unknown_keys;
|
||||
return _response;
|
||||
}
|
||||
|
||||
types::ocpp::GetConfigurationResponse ocpp_1_6_charge_pointImpl::handle_get_configuration_key(Array& keys) {
|
||||
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle get configuration key command";
|
||||
types::ocpp::GetConfigurationResponse response;
|
||||
for (const auto& key : keys) {
|
||||
response.unknown_keys.push_back(key);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
ocpp::v16::GetConfigurationRequest request;
|
||||
std::vector<ocpp::CiString<50>> _keys;
|
||||
for (const auto& key : keys) {
|
||||
_keys.push_back(key);
|
||||
}
|
||||
request.key = _keys;
|
||||
|
||||
const auto response = this->mod->charge_point->get_configuration_key(request);
|
||||
return to_everest(response);
|
||||
}
|
||||
|
||||
types::ocpp::ConfigurationStatus ocpp_1_6_charge_pointImpl::handle_set_configuration_key(std::string& key,
|
||||
std::string& value) {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle set configuration key command";
|
||||
return types::ocpp::ConfigurationStatus::Rejected;
|
||||
}
|
||||
const auto response = this->mod->charge_point->set_configuration_key(key, value);
|
||||
return to_everest(response);
|
||||
}
|
||||
|
||||
void ocpp_1_6_charge_pointImpl::handle_monitor_configuration_keys(Array& keys) {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle monitor configuration keys command";
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& key : keys) {
|
||||
this->mod->charge_point->register_configuration_key_changed_callback(
|
||||
key,
|
||||
[this](const ocpp::v16::KeyValue key_value) { this->publish_configuration_key(to_everest(key_value)); });
|
||||
}
|
||||
}
|
||||
|
||||
void ocpp_1_6_charge_pointImpl::handle_security_event(std::string& type, std::string& info) {
|
||||
this->mod->charge_point->on_security_event(type, info);
|
||||
}
|
||||
|
||||
} // namespace main
|
||||
} // namespace module
|
||||
@@ -0,0 +1,68 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef MAIN_OCPP_1_6_CHARGE_POINT_IMPL_HPP
|
||||
#define MAIN_OCPP_1_6_CHARGE_POINT_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ocpp_1_6_charge_point/Implementation.hpp>
|
||||
|
||||
#include "../OCPP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace main {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ocpp_1_6_charge_pointImpl : public ocpp_1_6_charge_pointImplBase {
|
||||
public:
|
||||
ocpp_1_6_charge_pointImpl() = delete;
|
||||
ocpp_1_6_charge_pointImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<OCPP>& mod, Conf& config) :
|
||||
ocpp_1_6_charge_pointImplBase(ev, "main"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual bool handle_stop() override;
|
||||
virtual bool handle_restart() override;
|
||||
virtual types::ocpp::GetConfigurationResponse handle_get_configuration_key(Array& keys) override;
|
||||
virtual types::ocpp::ConfigurationStatus handle_set_configuration_key(std::string& key,
|
||||
std::string& value) override;
|
||||
virtual void handle_monitor_configuration_keys(Array& keys) override;
|
||||
virtual void handle_security_event(std::string& type, std::string& info) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<OCPP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
std::mutex m;
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace main
|
||||
} // namespace module
|
||||
|
||||
#endif // MAIN_OCPP_1_6_CHARGE_POINT_IMPL_HPP
|
||||
134
tools/EVerest-main/modules/EVSE/OCPP/manifest.yaml
Normal file
134
tools/EVerest-main/modules/EVSE/OCPP/manifest.yaml
Normal file
@@ -0,0 +1,134 @@
|
||||
description: A OCPP charge point / charging station module, currently targeting OCPP-J 1.6
|
||||
config:
|
||||
ChargePointConfigPath:
|
||||
description: >-
|
||||
Path to the ocpp configuration file. Libocpp defines a JSON schema for this file. Please refer to the documentation
|
||||
of libocpp for more information about the configuration options.
|
||||
type: string
|
||||
default: ocpp-config.json
|
||||
UserConfigPath:
|
||||
description: >-
|
||||
Path to the file of the OCPP user config. The user config is used as an overlay for the original config defined
|
||||
by the ChargePointConfigPath. Any changes to configuration keys turned out internally or by the CSMS will be
|
||||
written to the user config file.
|
||||
type: string
|
||||
default: user_config.json
|
||||
DatabasePath:
|
||||
description: >-
|
||||
Path to the persistent SQLite database directory. Please refer to the libocpp documentation for more information
|
||||
about the database and its structure.
|
||||
type: string
|
||||
default: /tmp/ocpp_1_6_charge_point
|
||||
EnableExternalWebsocketControl:
|
||||
description: If true websocket can be disconnected and connected externally. This parameter is for debug and testing purposes.
|
||||
type: boolean
|
||||
default: false
|
||||
PublishChargingScheduleIntervalS:
|
||||
description:
|
||||
Interval in seconds in which charging schedules received from OCPP
|
||||
are be published over MQTT and signalled to connected modules. If the value
|
||||
is set to 0, charging schedules are only published when changed by CSMS
|
||||
type: integer
|
||||
default: 30
|
||||
PublishChargingScheduleDurationS:
|
||||
description: Duration in seconds that defines the duration of the requested charging schedules starting from now
|
||||
type: integer
|
||||
default: 600
|
||||
MessageLogPath:
|
||||
description: Path to directory where logs of all OCPP messages are written to
|
||||
type: string
|
||||
default: /tmp/everest_ocpp_logs
|
||||
MessageQueueResumeDelay:
|
||||
description: >-
|
||||
Time (seconds) to delay resuming the message queue after reconnecting. This parameter was introduced because
|
||||
some OCTT test cases require that the first message after a reconnect is sent by the CSMS.
|
||||
type: integer
|
||||
default: 0
|
||||
RequestCompositeScheduleUnit:
|
||||
description: >-
|
||||
Unit in which composite schedules are requested and shared within EVerest. It is recommended to use
|
||||
Amps for AC and Watts for DC charging stations.
|
||||
Allowed values:
|
||||
- 'A' for Amps
|
||||
- 'W' for Watts
|
||||
type: string
|
||||
default: 'A'
|
||||
DelayOcppStart:
|
||||
description: >-
|
||||
Small delay in time (milliseconds) to start the ocpp chargepoint to allow time for the rest of everest to update the connector status.
|
||||
This is only used to prevent issues from passing by availlable before preparing on a restart.
|
||||
type: integer
|
||||
default: 0
|
||||
ResetStopDelay:
|
||||
description: >-
|
||||
Time (seconds) to delay the stopping of the charge point so that the CSMS has enough time to respond
|
||||
to the charge point's last messages before resetting.
|
||||
type: integer
|
||||
default: 0
|
||||
provides:
|
||||
main:
|
||||
description: This is a OCPP 1.6 charge point
|
||||
interface: ocpp_1_6_charge_point
|
||||
auth_validator:
|
||||
description: Validates the provided auth token with OCPP
|
||||
interface: auth_token_validator
|
||||
auth_provider:
|
||||
description: Provides auth tokens from OCPP
|
||||
interface: auth_token_provider
|
||||
data_transfer:
|
||||
description: OCPP data transfer towards the CSMS
|
||||
interface: ocpp_data_transfer
|
||||
ocpp_generic:
|
||||
description: Generic OCPP interface.
|
||||
interface: ocpp
|
||||
session_cost:
|
||||
description: Send session cost
|
||||
interface: session_cost
|
||||
requires:
|
||||
charger_information:
|
||||
interface: charger_information
|
||||
min_connections: 0
|
||||
max_connections: 1
|
||||
evse_manager:
|
||||
interface: evse_manager
|
||||
min_connections: 1
|
||||
max_connections: 128
|
||||
evse_energy_sink:
|
||||
interface: external_energy_limits
|
||||
min_connections: 0
|
||||
max_connections: 129
|
||||
reservation:
|
||||
interface: reservation
|
||||
min_connections: 1
|
||||
max_connections: 1
|
||||
auth:
|
||||
interface: auth
|
||||
min_connections: 1
|
||||
max_connections: 1
|
||||
system:
|
||||
interface: system
|
||||
min_connections: 1
|
||||
max_connections: 1
|
||||
security:
|
||||
interface: evse_security
|
||||
min_connections: 1
|
||||
max_connections: 1
|
||||
data_transfer:
|
||||
interface: ocpp_data_transfer
|
||||
min_connections: 0
|
||||
max_connections: 1
|
||||
display_message:
|
||||
interface: display_message
|
||||
min_connections: 0
|
||||
max_connections: 1
|
||||
extensions_15118:
|
||||
interface: iso15118_extensions
|
||||
min_connections: 0
|
||||
max_connections: 128
|
||||
enable_external_mqtt: true
|
||||
enable_global_errors: true
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- Kai-Uwe Hermann
|
||||
- Piet Gömpel
|
||||
337
tools/EVerest-main/modules/EVSE/OCPP/ocpp_generic/ocppImpl.cpp
Normal file
337
tools/EVerest-main/modules/EVSE/OCPP/ocpp_generic/ocppImpl.cpp
Normal file
@@ -0,0 +1,337 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "ocppImpl.hpp"
|
||||
#include "ocpp/v16/messages/ChangeAvailability.hpp"
|
||||
|
||||
#include <everest/conversions/ocpp/ocpp_conversions.hpp>
|
||||
|
||||
namespace module {
|
||||
namespace ocpp_generic {
|
||||
|
||||
types::ocpp::KeyValue to_everest(const ocpp::v16::KeyValue& key_value) {
|
||||
types::ocpp::KeyValue _key_value;
|
||||
_key_value.key = key_value.key.get();
|
||||
_key_value.read_only = key_value.readonly;
|
||||
if (key_value.value.has_value()) {
|
||||
_key_value.value = key_value.value.value().get();
|
||||
}
|
||||
return _key_value;
|
||||
}
|
||||
|
||||
types::ocpp::ConfigurationStatus to_everest(const ocpp::v16::ConfigurationStatus status) {
|
||||
switch (status) {
|
||||
case ocpp::v16::ConfigurationStatus::Accepted:
|
||||
return types::ocpp::ConfigurationStatus::Accepted;
|
||||
case ocpp::v16::ConfigurationStatus::Rejected:
|
||||
return types::ocpp::ConfigurationStatus::Rejected;
|
||||
case ocpp::v16::ConfigurationStatus::RebootRequired:
|
||||
return types::ocpp::ConfigurationStatus::RebootRequired;
|
||||
case ocpp::v16::ConfigurationStatus::NotSupported:
|
||||
return types::ocpp::ConfigurationStatus::NotSupported;
|
||||
default:
|
||||
EVLOG_warning << "Could not convert to ConfigurationStatus";
|
||||
return types::ocpp::ConfigurationStatus::Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
types::ocpp::GetConfigurationResponse to_everest(const ocpp::v16::GetConfigurationResponse& response) {
|
||||
types::ocpp::GetConfigurationResponse _response;
|
||||
std::vector<types::ocpp::KeyValue> configuration_keys;
|
||||
std::vector<std::string> unknown_keys;
|
||||
|
||||
if (response.configurationKey.has_value()) {
|
||||
for (const auto& item : response.configurationKey.value()) {
|
||||
configuration_keys.push_back(to_everest(item));
|
||||
}
|
||||
}
|
||||
|
||||
if (response.unknownKey.has_value()) {
|
||||
for (const auto& item : response.unknownKey.value()) {
|
||||
unknown_keys.push_back(item.get());
|
||||
}
|
||||
}
|
||||
|
||||
_response.configuration_keys = configuration_keys;
|
||||
_response.unknown_keys = unknown_keys;
|
||||
return _response;
|
||||
}
|
||||
|
||||
ocpp::v16::AvailabilityStatus to_ocpp(const types::ocpp::ChangeAvailabilityStatusEnumType& status) {
|
||||
switch (status) {
|
||||
case types::ocpp::ChangeAvailabilityStatusEnumType::Accepted:
|
||||
return ocpp::v16::AvailabilityStatus::Accepted;
|
||||
case types::ocpp::ChangeAvailabilityStatusEnumType::Rejected:
|
||||
return ocpp::v16::AvailabilityStatus::Rejected;
|
||||
case types::ocpp::ChangeAvailabilityStatusEnumType::Scheduled:
|
||||
return ocpp::v16::AvailabilityStatus::Scheduled;
|
||||
}
|
||||
throw std::out_of_range("unknown ChangeAvailabilityStatusEnumType");
|
||||
}
|
||||
|
||||
types::ocpp::ChangeAvailabilityStatusEnumType to_everest(const ocpp::v16::AvailabilityStatus& status) {
|
||||
switch (status) {
|
||||
case ocpp::v16::AvailabilityStatus::Accepted:
|
||||
return types::ocpp::ChangeAvailabilityStatusEnumType::Accepted;
|
||||
case ocpp::v16::AvailabilityStatus::Rejected:
|
||||
return types::ocpp::ChangeAvailabilityStatusEnumType::Rejected;
|
||||
case ocpp::v16::AvailabilityStatus::Scheduled:
|
||||
return types::ocpp::ChangeAvailabilityStatusEnumType::Scheduled;
|
||||
}
|
||||
throw std::out_of_range("unknown AvailabilityStatus");
|
||||
}
|
||||
|
||||
ocpp::v16::AvailabilityType to_ocpp(const types::ocpp::OperationalStatusEnumType& status) {
|
||||
switch (status) {
|
||||
case types::ocpp::OperationalStatusEnumType::Operative:
|
||||
return ocpp::v16::AvailabilityType::Operative;
|
||||
case types::ocpp::OperationalStatusEnumType::Inoperative:
|
||||
return ocpp::v16::AvailabilityType::Inoperative;
|
||||
}
|
||||
throw std::out_of_range("unknown OperationalStatusEnumType");
|
||||
}
|
||||
|
||||
types::ocpp::ChangeAvailabilityResponse to_everest(const ocpp::v16::ChangeAvailabilityResponse& response) {
|
||||
types::ocpp::ChangeAvailabilityResponse everest_response{};
|
||||
everest_response.status = to_everest(response.status);
|
||||
return everest_response;
|
||||
}
|
||||
|
||||
void ocppImpl::init() {
|
||||
}
|
||||
|
||||
void ocppImpl::ready() {
|
||||
}
|
||||
|
||||
bool ocppImpl::handle_stop() {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle stop command";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->chargepoint_state_mutex);
|
||||
mod->charging_schedules_timer->stop();
|
||||
bool success = mod->charge_point->stop();
|
||||
if (success) {
|
||||
this->mod->ocpp_stopped = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ocppImpl::handle_restart() {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle restart command";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(this->chargepoint_state_mutex);
|
||||
mod->charging_schedules_timer->interval(std::chrono::seconds(this->mod->config.PublishChargingScheduleIntervalS));
|
||||
bool success = mod->charge_point->restart();
|
||||
if (success) {
|
||||
this->mod->ocpp_stopped = false;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void ocppImpl::handle_security_event(types::ocpp::SecurityEvent& event) {
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle security event command";
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<ocpp::DateTime> timestamp;
|
||||
if (event.timestamp.has_value()) {
|
||||
timestamp = ocpp_conversions::to_ocpp_datetime_or_now(event.timestamp.value());
|
||||
}
|
||||
const auto event_type = ocpp::CiString<50>(event.type, ocpp::StringTooLarge::Truncate);
|
||||
std::optional<ocpp::CiString<255>> tech_info;
|
||||
if (event.info.has_value()) {
|
||||
tech_info = ocpp::CiString<255>(event.info.value(), ocpp::StringTooLarge::Truncate);
|
||||
}
|
||||
this->mod->charge_point->on_security_event(event_type, tech_info, event.critical, timestamp);
|
||||
}
|
||||
|
||||
std::vector<types::ocpp::GetVariableResult>
|
||||
ocppImpl::handle_get_variables(std::vector<types::ocpp::GetVariableRequest>& requests) {
|
||||
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not yet initialized. Cannot handle get variables request.";
|
||||
std::vector<types::ocpp::GetVariableResult> results;
|
||||
for (const auto& req : requests) {
|
||||
types::ocpp::GetVariableResult result;
|
||||
result.status = types::ocpp::GetVariableStatusEnumType::Rejected;
|
||||
result.component_variable.component = req.component_variable.component;
|
||||
result.component_variable.variable = req.component_variable.variable;
|
||||
result.attribute_type = req.attribute_type;
|
||||
results.push_back(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<types::ocpp::GetVariableResult> results;
|
||||
|
||||
// prepare ocpp_request to request configuration keys from ocpp::v16::ChargePoint
|
||||
ocpp::v16::GetConfigurationRequest ocpp_request;
|
||||
std::vector<ocpp::CiString<50>> configuration_keys;
|
||||
std::map<std::string, int> configuration_key_indices{};
|
||||
int request_index = 0;
|
||||
for (const auto& request : requests) {
|
||||
// only variable.name is relevant for OCPP1.6
|
||||
configuration_keys.emplace_back(request.component_variable.variable.name);
|
||||
configuration_key_indices[request.component_variable.variable.name] = request_index++;
|
||||
}
|
||||
ocpp_request.key = configuration_keys;
|
||||
|
||||
// request configuration keys from ocpp::v16::ChargePoint
|
||||
const auto ocpp_response = this->mod->charge_point->get_configuration_key(ocpp_request);
|
||||
|
||||
std::map<std::string, types::ocpp::GetVariableRequest> results_map{};
|
||||
if (ocpp_response.configurationKey.has_value()) {
|
||||
for (const auto& key_value : ocpp_response.configurationKey.value()) {
|
||||
// add result for each present configurationKey in the response
|
||||
types::ocpp::GetVariableResult result;
|
||||
result.component_variable = {
|
||||
{""},
|
||||
{key_value.key.get()}}; // we don't care about the component, only about the variable.name in OCPP1.6
|
||||
if (key_value.value.has_value()) {
|
||||
result.value = key_value.value.value().get();
|
||||
result.status = types::ocpp::GetVariableStatusEnumType::Accepted;
|
||||
result.attribute_type = types::ocpp::AttributeEnum::Actual;
|
||||
} else {
|
||||
result.status = types::ocpp::GetVariableStatusEnumType::UnknownVariable;
|
||||
}
|
||||
results.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
if (ocpp_response.unknownKey.has_value()) {
|
||||
for (const auto& key : ocpp_response.unknownKey.value()) {
|
||||
// add result for each unknownKey in the response
|
||||
types::ocpp::GetVariableResult result;
|
||||
result.component_variable = {
|
||||
{""}, {key.get()}}; // we don't care about the component, only about the variable.name in OCPP1.6
|
||||
result.status = types::ocpp::GetVariableStatusEnumType::UnknownVariable;
|
||||
results.push_back(result);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(results.begin(), results.end(),
|
||||
[&configuration_key_indices](const types::ocpp::GetVariableResult& result_a,
|
||||
const types::ocpp::GetVariableResult& result_b) {
|
||||
return configuration_key_indices[result_a.component_variable.variable.name] <
|
||||
configuration_key_indices[result_b.component_variable.variable.name];
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<types::ocpp::SetVariableResult>
|
||||
ocppImpl::handle_set_variables(std::vector<types::ocpp::SetVariableRequest>& requests, std::string& /*source*/) {
|
||||
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not yet initialized. Cannot handle set variables request.";
|
||||
std::vector<types::ocpp::SetVariableResult> results;
|
||||
for (const auto& req : requests) {
|
||||
types::ocpp::SetVariableResult result;
|
||||
result.status = types::ocpp::SetVariableStatusEnumType ::Rejected;
|
||||
result.component_variable.component = req.component_variable.component;
|
||||
result.component_variable.variable = req.component_variable.variable;
|
||||
result.attribute_type = req.attribute_type;
|
||||
results.push_back(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<types::ocpp::SetVariableResult> results;
|
||||
|
||||
for (const auto& request : requests) {
|
||||
// add result for each present SetVariableRequest in the response
|
||||
types::ocpp::SetVariableResult result;
|
||||
result.component_variable = request.component_variable;
|
||||
|
||||
// retrieve key and value from the request
|
||||
auto key = request.component_variable.variable.name;
|
||||
auto value = request.value;
|
||||
auto response = this->mod->charge_point->set_configuration_key(key, value);
|
||||
|
||||
switch (response) {
|
||||
case ocpp::v16::ConfigurationStatus::Accepted:
|
||||
result.status = types::ocpp::SetVariableStatusEnumType::Accepted;
|
||||
break;
|
||||
case ocpp::v16::ConfigurationStatus::RebootRequired:
|
||||
result.status = types::ocpp::SetVariableStatusEnumType::RebootRequired;
|
||||
break;
|
||||
case ocpp::v16::ConfigurationStatus::Rejected:
|
||||
result.status = types::ocpp::SetVariableStatusEnumType::Rejected;
|
||||
break;
|
||||
case ocpp::v16::ConfigurationStatus::NotSupported:
|
||||
// NotSupported in OCPP1.6 means that the configuration key is not known / not supported, so it's best to go
|
||||
// with UnknownVariable
|
||||
result.status = types::ocpp::SetVariableStatusEnumType::UnknownVariable;
|
||||
break;
|
||||
}
|
||||
results.push_back(result);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
void ocppImpl::handle_monitor_variables(std::vector<types::ocpp::ComponentVariable>& component_variables) {
|
||||
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "Could not monitor variables. ChargePoint not initialized";
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& cv : component_variables) {
|
||||
this->mod->charge_point->register_configuration_key_changed_callback(
|
||||
cv.variable.name, // we dont care about the component, only about the variable.name in OCPP1.6
|
||||
[this, cv](const ocpp::v16::KeyValue key_value) {
|
||||
types::ocpp::EventData event_data;
|
||||
event_data.component_variable = cv;
|
||||
event_data.event_id = 0; // irrelevant for OCPP1.6
|
||||
event_data.timestamp = ocpp::DateTime();
|
||||
event_data.trigger = types::ocpp::EventTriggerEnum::Alerting; // default for OCPP1.6
|
||||
event_data.actual_value = key_value.value.value_or("");
|
||||
event_data.event_notification_type =
|
||||
types::ocpp::EventNotificationType::CustomMonitor; // default for OCPP1.6
|
||||
this->publish_event_data(event_data);
|
||||
});
|
||||
}
|
||||
}
|
||||
types::ocpp::ChangeAvailabilityResponse
|
||||
ocppImpl::handle_change_availability(types::ocpp::ChangeAvailabilityRequest& request) {
|
||||
|
||||
if (this->mod->charge_point == nullptr) {
|
||||
EVLOG_warning << "ChargePoint not initialized, cannot handle change availability command";
|
||||
return types::ocpp::ChangeAvailabilityResponse{types::ocpp::ChangeAvailabilityStatusEnumType::Rejected};
|
||||
}
|
||||
|
||||
ocpp::v16::ChangeAvailabilityRequest ocpp_request{};
|
||||
ocpp_request.type = to_ocpp(request.operational_status);
|
||||
if (request.evse.has_value()) {
|
||||
const auto& evse = request.evse.value();
|
||||
if (!evse.connector_id.has_value()) {
|
||||
return types::ocpp::ChangeAvailabilityResponse{
|
||||
types::ocpp::ChangeAvailabilityStatusEnumType::Rejected,
|
||||
types::ocpp::StatusInfoType{"InvalidInput",
|
||||
"No connector id specified; if the whole charging station is supposed to "
|
||||
"be addressed, parameter evse "
|
||||
"must have no value."}};
|
||||
}
|
||||
try {
|
||||
ocpp_request.connectorId = this->mod->get_ocpp_connector_id(evse.id, evse.connector_id.value());
|
||||
} catch (const std::out_of_range&) {
|
||||
return types::ocpp::ChangeAvailabilityResponse{
|
||||
types::ocpp::ChangeAvailabilityStatusEnumType::Rejected,
|
||||
types::ocpp::StatusInfoType{
|
||||
"InvalidInput",
|
||||
"Could not determine OCPP connector id from provided EVerest EVSE and Connector Ids."}};
|
||||
}
|
||||
}
|
||||
auto response = this->mod->charge_point->on_change_availability(ocpp_request);
|
||||
return to_everest(response);
|
||||
}
|
||||
|
||||
} // namespace ocpp_generic
|
||||
} // namespace module
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef OCPP_GENERIC_OCPP_IMPL_HPP
|
||||
#define OCPP_GENERIC_OCPP_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ocpp/Implementation.hpp>
|
||||
|
||||
#include "../OCPP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace ocpp_generic {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ocppImpl : public ocppImplBase {
|
||||
public:
|
||||
ocppImpl() = delete;
|
||||
ocppImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<OCPP>& mod, Conf& config) :
|
||||
ocppImplBase(ev, "ocpp_generic"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// command handler functions (virtual)
|
||||
virtual bool handle_stop() override;
|
||||
virtual bool handle_restart() override;
|
||||
virtual void handle_security_event(types::ocpp::SecurityEvent& event) override;
|
||||
virtual std::vector<types::ocpp::GetVariableResult>
|
||||
handle_get_variables(std::vector<types::ocpp::GetVariableRequest>& requests) override;
|
||||
virtual std::vector<types::ocpp::SetVariableResult>
|
||||
handle_set_variables(std::vector<types::ocpp::SetVariableRequest>& requests, std::string& source) override;
|
||||
virtual types::ocpp::ChangeAvailabilityResponse
|
||||
handle_change_availability(types::ocpp::ChangeAvailabilityRequest& request) override;
|
||||
virtual void handle_monitor_variables(std::vector<types::ocpp::ComponentVariable>& component_variables) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<OCPP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
std::mutex chargepoint_state_mutex; // mutex used for start/stop operations
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace ocpp_generic
|
||||
} // namespace module
|
||||
|
||||
#endif // OCPP_GENERIC_OCPP_IMPL_HPP
|
||||
@@ -0,0 +1,16 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "session_costImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace session_cost {
|
||||
|
||||
void session_costImpl::init() {
|
||||
}
|
||||
|
||||
void session_costImpl::ready() {
|
||||
}
|
||||
|
||||
} // namespace session_cost
|
||||
} // namespace module
|
||||
@@ -0,0 +1,60 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef SESSION_COST_SESSION_COST_IMPL_HPP
|
||||
#define SESSION_COST_SESSION_COST_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/session_cost/Implementation.hpp>
|
||||
|
||||
#include "../OCPP.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace session_cost {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class session_costImpl : public session_costImplBase {
|
||||
public:
|
||||
session_costImpl() = delete;
|
||||
session_costImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<OCPP>& mod, Conf& config) :
|
||||
session_costImplBase(ev, "session_cost"), mod(mod), config(config){};
|
||||
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
// insert your public definitions here
|
||||
// ev@8ea32d28-373f-4c90-ae5e-b4fcc74e2a61:v1
|
||||
|
||||
protected:
|
||||
// no commands defined for this interface
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<OCPP>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
// insert your private definitions here
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
};
|
||||
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
// insert other definitions here
|
||||
// ev@3d7da0ad-02c2-493d-9920-0bbbd56b9876:v1
|
||||
|
||||
} // namespace session_cost
|
||||
} // namespace module
|
||||
|
||||
#endif // SESSION_COST_SESSION_COST_IMPL_HPP
|
||||
Reference in New Issue
Block a user