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:
31
tools/EVerest-main/modules/EVSE/Evse15118D20/CMakeLists.txt
Normal file
31
tools/EVerest-main/modules/EVSE/Evse15118D20/CMakeLists.txt
Normal file
@@ -0,0 +1,31 @@
|
||||
#
|
||||
# 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
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
charger/session_logger.cpp
|
||||
charger/utils.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${MODULE_NAME}
|
||||
PRIVATE
|
||||
iso15118::iso15118
|
||||
)
|
||||
# ev@bcc62523-e22b-41d7-ba2f-825b493a3c97:v1
|
||||
|
||||
target_sources(${MODULE_NAME}
|
||||
PRIVATE
|
||||
"charger/ISO15118_chargerImpl.cpp"
|
||||
"extensions/iso15118_extensionsImpl.cpp"
|
||||
)
|
||||
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
# insert other things like install cmds etc here
|
||||
# ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1
|
||||
@@ -0,0 +1,17 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "Evse15118D20.hpp"
|
||||
|
||||
namespace module {
|
||||
|
||||
void Evse15118D20::init() {
|
||||
invoke_init(*p_charger);
|
||||
invoke_init(*p_extensions);
|
||||
}
|
||||
|
||||
void Evse15118D20::ready() {
|
||||
invoke_ready(*p_charger);
|
||||
invoke_ready(*p_extensions);
|
||||
}
|
||||
|
||||
} // namespace module
|
||||
@@ -0,0 +1,88 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef EVSE15118D20_HPP
|
||||
#define EVSE15118D20_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 2
|
||||
//
|
||||
|
||||
#include "ld-ev.hpp"
|
||||
|
||||
// headers for provided interface implementations
|
||||
#include <generated/interfaces/ISO15118_charger/Implementation.hpp>
|
||||
#include <generated/interfaces/iso15118_extensions/Implementation.hpp>
|
||||
|
||||
// headers for required interface implementations
|
||||
#include <generated/interfaces/ISO15118_vas/Interface.hpp>
|
||||
#include <generated/interfaces/evse_security/Interface.hpp>
|
||||
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
// insert your custom include headers here
|
||||
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
|
||||
|
||||
namespace module {
|
||||
|
||||
struct Conf {
|
||||
std::string device;
|
||||
std::string logging_path;
|
||||
std::string tls_negotiation_strategy;
|
||||
bool enforce_tls_1_3;
|
||||
bool enable_ssl_logging;
|
||||
bool enable_tls_key_logging;
|
||||
std::string tls_key_logging_path;
|
||||
bool enable_sdp_server;
|
||||
bool supported_dynamic_mode;
|
||||
bool supported_mobility_needs_mode_provided_by_secc;
|
||||
bool supported_scheduled_mode;
|
||||
std::string custom_protocol_namespace;
|
||||
bool negative_bidirectional_limits;
|
||||
};
|
||||
|
||||
class Evse15118D20 : public Everest::ModuleBase {
|
||||
public:
|
||||
Evse15118D20() = delete;
|
||||
Evse15118D20(const ModuleInfo& info, std::unique_ptr<ISO15118_chargerImplBase> p_charger,
|
||||
std::unique_ptr<iso15118_extensionsImplBase> p_extensions,
|
||||
std::unique_ptr<evse_securityIntf> r_security,
|
||||
std::vector<std::unique_ptr<ISO15118_vasIntf>> r_iso15118_vas, Conf& config) :
|
||||
ModuleBase(info),
|
||||
p_charger(std::move(p_charger)),
|
||||
p_extensions(std::move(p_extensions)),
|
||||
r_security(std::move(r_security)),
|
||||
r_iso15118_vas(std::move(r_iso15118_vas)),
|
||||
config(config){};
|
||||
|
||||
const std::unique_ptr<ISO15118_chargerImplBase> p_charger;
|
||||
const std::unique_ptr<iso15118_extensionsImplBase> p_extensions;
|
||||
const std::unique_ptr<evse_securityIntf> r_security;
|
||||
const std::vector<std::unique_ptr<ISO15118_vasIntf>> r_iso15118_vas;
|
||||
const Conf& config;
|
||||
|
||||
// ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1
|
||||
// insert your public definitions here
|
||||
// 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
|
||||
// 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 // EVSE15118D20_HPP
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,113 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef CHARGER_ISO15118_CHARGER_IMPL_HPP
|
||||
#define CHARGER_ISO15118_CHARGER_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/ISO15118_charger/Implementation.hpp>
|
||||
|
||||
#include "../Evse15118D20.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
#include <bitset>
|
||||
#include <mutex>
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <iso15118/d20/config.hpp>
|
||||
#include <iso15118/session/feedback.hpp>
|
||||
#include <iso15118/tbd_controller.hpp>
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace charger {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class ISO15118_chargerImpl : public ISO15118_chargerImplBase {
|
||||
public:
|
||||
ISO15118_chargerImpl() = delete;
|
||||
ISO15118_chargerImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<Evse15118D20>& mod, Conf& config) :
|
||||
ISO15118_chargerImplBase(ev, "charger"), 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 void handle_setup(types::iso15118::EVSEID& evse_id, types::iso15118::SaeJ2847BidiMode& sae_j2847_mode,
|
||||
bool& debug_mode) override;
|
||||
virtual void handle_set_charging_parameters(types::iso15118::SetupPhysicalValues& physical_values) override;
|
||||
virtual void handle_session_setup(std::vector<types::iso15118::PaymentOption>& payment_options,
|
||||
bool& supported_certificate_service,
|
||||
bool& central_contract_validation_allowed) override;
|
||||
virtual void handle_bpt_setup(types::iso15118::BptSetup& bpt_config) override;
|
||||
virtual void handle_set_powersupply_capabilities(types::power_supply_DC::Capabilities& capabilities) override;
|
||||
virtual void handle_authorization_response(types::authorization::AuthorizationStatus& authorization_status,
|
||||
types::authorization::CertificateStatus& certificate_status) override;
|
||||
virtual void handle_ac_contactor_closed(bool& status) override;
|
||||
virtual void handle_dlink_ready(bool& value) override;
|
||||
virtual void handle_cable_check_finished(bool& status) override;
|
||||
virtual void handle_receipt_is_required(bool& receipt_required) override;
|
||||
virtual void handle_stop_charging(bool& stop) override;
|
||||
virtual void handle_pause_charging(bool& pause) override;
|
||||
virtual void handle_no_energy_pause_charging(types::iso15118::NoEnergyPauseMode& mode) override;
|
||||
virtual bool
|
||||
handle_update_supported_app_protocols(types::iso15118::SupportedAppProtocols& supported_app_protocols) override;
|
||||
virtual void handle_update_energy_transfer_modes(
|
||||
std::vector<types::iso15118::EnergyTransferMode>& supported_energy_transfer_modes) override;
|
||||
virtual void handle_update_ac_max_current(double& max_current) override;
|
||||
virtual void handle_update_ac_parameters(types::iso15118::AcParameters& ac_parameters) override;
|
||||
virtual void handle_update_ac_maximum_limits(types::iso15118::AcEvseMaximumPower& maximum_limits) override;
|
||||
virtual void handle_update_ac_minimum_limits(types::iso15118::AcEvseMinimumPower& minimum_limits) override;
|
||||
virtual void handle_update_ac_target_values(types::iso15118::AcTargetValues& target_values) override;
|
||||
virtual void handle_update_ac_present_power(types::units::Power& present_power) override;
|
||||
virtual void handle_update_dc_maximum_limits(types::iso15118::DcEvseMaximumLimits& maximum_limits) override;
|
||||
virtual void handle_update_dc_minimum_limits(types::iso15118::DcEvseMinimumLimits& minimum_limits) override;
|
||||
virtual void handle_update_isolation_status(types::iso15118::IsolationStatus& isolation_status) override;
|
||||
virtual void
|
||||
handle_update_dc_present_values(types::iso15118::DcEvsePresentVoltageCurrent& present_voltage_current) override;
|
||||
virtual void handle_update_meter_info(types::powermeter::Powermeter& powermeter) override;
|
||||
virtual void handle_send_error(types::iso15118::EvseError& error) override;
|
||||
virtual void handle_reset_error() override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<Evse15118D20>& mod;
|
||||
const Conf& config;
|
||||
|
||||
virtual void init() override;
|
||||
virtual void ready() override;
|
||||
|
||||
// ev@3370e4dd-95f4-47a9-aaec-ea76f34a66c9:v1
|
||||
iso15118::session::feedback::Callbacks create_callbacks();
|
||||
|
||||
std::unique_ptr<iso15118::TbdController> controller;
|
||||
|
||||
iso15118::d20::EvseSetupConfig setup_config;
|
||||
std::bitset<NUMBER_OF_SETUP_STEPS> setup_steps_done{0};
|
||||
|
||||
std::vector<iso15118::d20::SupportedVASs> supported_vas_services_per_provider;
|
||||
std::mutex vas_mutex;
|
||||
|
||||
void update_supported_vas_services();
|
||||
std::optional<size_t> get_vas_provider_index(uint16_t service_id);
|
||||
// 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 charger
|
||||
} // namespace module
|
||||
|
||||
#endif // CHARGER_ISO15118_CHARGER_IMPL_HPP
|
||||
@@ -0,0 +1,141 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "session_logger.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <date/date.h>
|
||||
|
||||
#include <iso15118/session/logger.hpp>
|
||||
|
||||
#include <everest/logging.hpp>
|
||||
|
||||
using LogEvent = iso15118::session::logging::Event;
|
||||
|
||||
std::string get_filename_for_current_time() {
|
||||
const auto now = std::chrono::system_clock::now();
|
||||
const auto now_t = std::chrono::system_clock::to_time_t(now);
|
||||
|
||||
std::tm now_tm;
|
||||
gmtime_r(&now_t, &now_tm);
|
||||
|
||||
char buffer[64];
|
||||
strftime(buffer, sizeof(buffer), "%y%m%d_%H-%M-%S.yaml", &now_tm);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// static auto timepoint_to_string(const iso15118::session::logging::TimePoint& timepoint) {
|
||||
// using namespace date;
|
||||
// return static_cast<std::string>(timepoint);
|
||||
// }
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const iso15118::session::logging::ExiMessageDirection& direction) {
|
||||
using Direction = iso15118::session::logging::ExiMessageDirection;
|
||||
switch (direction) {
|
||||
case Direction::FROM_EV:
|
||||
return os << "FROM_EV";
|
||||
case Direction::TO_EV:
|
||||
return os << "TO_EV";
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
class SessionLog {
|
||||
public:
|
||||
SessionLog(const std::string& file_name) : file(file_name.c_str(), std::ios::out) {
|
||||
if (not file.good()) {
|
||||
throw std::runtime_error("Failed to open file " + file_name + " for writing iso15118 session log");
|
||||
}
|
||||
|
||||
EVLOG_info << "Created logfile at: " << file_name;
|
||||
}
|
||||
void operator()(const iso15118::session::logging::SimpleEvent& event) {
|
||||
file << "- type: INFO\n";
|
||||
add_timestamp(event.time_point);
|
||||
file << " info: \"" << event.info << "\"\n";
|
||||
}
|
||||
|
||||
void operator()(const iso15118::session::logging::ExiMessageEvent& event) {
|
||||
file << "- type: EXI\n";
|
||||
add_timestamp(event.time_point);
|
||||
file << " direction: " << event.direction << "\n";
|
||||
file << " sdp_payload_type: " << event.payload_type << "\n";
|
||||
add_hex_encoded_data(event.data, event.len);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
file.flush();
|
||||
}
|
||||
|
||||
private:
|
||||
std::fstream file;
|
||||
|
||||
void add_timestamp(const iso15118::session::logging::TimePoint& timestamp) {
|
||||
if (not timestamp_initialized) {
|
||||
last_timestamp = timestamp;
|
||||
timestamp_initialized = true;
|
||||
}
|
||||
|
||||
const auto offset_ms = std::chrono::duration_cast<std::chrono::milliseconds>(timestamp - last_timestamp);
|
||||
file << " timestamp_offset: " << offset_ms.count() << "\n";
|
||||
|
||||
const auto dp = date::floor<date::days>(timestamp);
|
||||
const auto time = date::make_time(timestamp - dp);
|
||||
const auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(time.subseconds());
|
||||
file << " timestamp: \"";
|
||||
file << std::setfill('0') << std::setw(2) << time.hours().count() << ":";
|
||||
file << std::setfill('0') << std::setw(2) << time.minutes().count() << ":";
|
||||
file << std::setfill('0') << std::setw(2) << time.seconds().count() << ".";
|
||||
file << std::setfill('0') << std::setw(4) << milliseconds.count();
|
||||
file << "\"\n";
|
||||
|
||||
last_timestamp = timestamp;
|
||||
}
|
||||
|
||||
void add_hex_encoded_data(const uint8_t* data, size_t len) {
|
||||
file << " data: \"";
|
||||
|
||||
const auto flags = file.flags();
|
||||
|
||||
file << std::hex;
|
||||
|
||||
for (int i = 0; i < len; ++i) {
|
||||
file << std::setfill('0') << std::setw(2) << static_cast<int>(data[i]);
|
||||
}
|
||||
|
||||
file.flags(flags);
|
||||
file << "\"\n";
|
||||
}
|
||||
|
||||
iso15118::session::logging::TimePoint last_timestamp;
|
||||
bool timestamp_initialized{false};
|
||||
};
|
||||
|
||||
SessionLogger::SessionLogger(std::filesystem::path output_dir_) : output_dir(std::filesystem::absolute(output_dir_)) {
|
||||
// FIXME (aw): this is quite brute force ...
|
||||
if (not std::filesystem::exists(output_dir)) {
|
||||
std::filesystem::create_directory(output_dir);
|
||||
}
|
||||
|
||||
iso15118::session::logging::set_session_log_callback([this](std::uintptr_t id, const LogEvent& event) {
|
||||
auto log_it = logs.find(id);
|
||||
if (log_it == logs.end()) {
|
||||
const auto log_file_name = output_dir / get_filename_for_current_time();
|
||||
const auto emplaced = logs.emplace(id, std::make_unique<SessionLog>(log_file_name.string()));
|
||||
|
||||
log_it = emplaced.first;
|
||||
}
|
||||
|
||||
auto& log = *log_it->second;
|
||||
|
||||
std::visit(log, event);
|
||||
log.flush();
|
||||
});
|
||||
}
|
||||
|
||||
SessionLogger::~SessionLogger() = default;
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
// forward declare
|
||||
class SessionLog;
|
||||
|
||||
class SessionLogger {
|
||||
public:
|
||||
SessionLogger(std::filesystem::path output_dir);
|
||||
~SessionLogger();
|
||||
|
||||
private:
|
||||
std::filesystem::path output_dir;
|
||||
std::map<std::uintptr_t, std::unique_ptr<SessionLog>> logs;
|
||||
};
|
||||
508
tools/EVerest-main/modules/EVSE/Evse15118D20/charger/utils.cpp
Normal file
508
tools/EVerest-main/modules/EVSE/Evse15118D20/charger/utils.cpp
Normal file
@@ -0,0 +1,508 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#include "utils.hpp"
|
||||
|
||||
#include <everest/logging.hpp>
|
||||
|
||||
#include <iso15118/d20/limits.hpp>
|
||||
#include <iso15118/message/common_types.hpp>
|
||||
#include <iso15118/message/dc_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/schedule_exchange.hpp>
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
|
||||
namespace module::charger {
|
||||
|
||||
namespace dt = iso15118::message_20::datatypes;
|
||||
|
||||
namespace {
|
||||
dt::Parameter convert_parameter(const types::iso15118_vas::Parameter& parameter) {
|
||||
dt::Parameter out;
|
||||
out.name = parameter.name;
|
||||
|
||||
if (parameter.value.bool_value.has_value()) {
|
||||
out.value = parameter.value.bool_value.value();
|
||||
} else if (parameter.value.int_value.has_value()) {
|
||||
out.value = static_cast<int32_t>(parameter.value.int_value.value());
|
||||
} else if (parameter.value.short_value.has_value()) {
|
||||
out.value = static_cast<int16_t>(parameter.value.short_value.value());
|
||||
} else if (parameter.value.byte_value.has_value()) {
|
||||
out.value = static_cast<int8_t>(parameter.value.byte_value.value());
|
||||
} else if (parameter.value.rational_number.has_value()) {
|
||||
out.value = dt::from_float(parameter.value.rational_number.value());
|
||||
} else if (parameter.value.finite_string.has_value()) {
|
||||
out.value = parameter.value.finite_string.value();
|
||||
} else {
|
||||
throw std::invalid_argument("Invalid ParameterValue in convert_parameter: " + parameter.name +
|
||||
" has no value set");
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
dt::ParameterSet convert_parameter_set(const types::iso15118_vas::ParameterSet& parameter_set) {
|
||||
dt::ParameterSet out;
|
||||
out.id = parameter_set.set_id;
|
||||
|
||||
for (const auto& parameter : parameter_set.parameters) {
|
||||
const auto* ptr = out.parameter.try_emplace_back(convert_parameter(parameter));
|
||||
|
||||
if (ptr == nullptr) {
|
||||
EVLOG_warning << "VAS parameter set is bigger then 32";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::optional<float> convert_from_optional(const std::optional<dt::RationalNumber>& in) {
|
||||
return (in.has_value()) ? std::make_optional(dt::from_RationalNumber(*in)) : std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<dt::RationalNumber> convert_from_optional(const std::optional<float>& in) {
|
||||
return (in.has_value()) ? std::make_optional(dt::from_float(*in)) : std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<float> convert_from_optional(const std::optional<uint32_t>& in) {
|
||||
return (in.has_value()) ? std::make_optional(static_cast<float>(*in)) : std::nullopt;
|
||||
}
|
||||
|
||||
types::iso15118::AppProtocol convert_app_protocol(const iso15118::message_20::SupportedAppProtocol& app_protocol) {
|
||||
types::iso15118::AppProtocol result;
|
||||
result.protocol_namespace = app_protocol.protocol_namespace;
|
||||
result.priority = app_protocol.priority;
|
||||
result.schema_id = app_protocol.schema_id;
|
||||
result.version_number_major = static_cast<int32_t>(app_protocol.version_number_major);
|
||||
result.version_number_minor = static_cast<int32_t>(app_protocol.version_number_minor);
|
||||
return result;
|
||||
}
|
||||
|
||||
types::iso15118::EvInformation convert_ev_info(const iso15118::d20::EVInformation& ev_info) {
|
||||
types::iso15118::EvInformation result;
|
||||
result.evcc_id = ev_info.evcc_id;
|
||||
result.selected_protocol = convert_app_protocol(ev_info.selected_app_protocol);
|
||||
result.supported_protocols.Protocols.reserve(ev_info.ev_supported_app_protocols.size());
|
||||
for (const auto& supported_app : ev_info.ev_supported_app_protocols) {
|
||||
result.supported_protocols.Protocols.push_back(convert_app_protocol(supported_app));
|
||||
}
|
||||
result.tls_leaf_certificate = ev_info.ev_tls_leaf_cert;
|
||||
result.tls_sub_ca_1_certificate = ev_info.ev_tls_sub_ca_1_cert;
|
||||
result.tls_sub_ca_2_certificate = ev_info.ev_tls_sub_ca_2_cert;
|
||||
result.tls_root_certificate = ev_info.ev_tls_root_cert;
|
||||
return result;
|
||||
}
|
||||
|
||||
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::Dynamic_DC_CLReqControlMode& in) {
|
||||
return {dt::from_RationalNumber(in.target_energy_request),
|
||||
dt::from_RationalNumber(in.max_energy_request),
|
||||
dt::from_RationalNumber(in.min_energy_request),
|
||||
dt::from_RationalNumber(in.max_charge_power),
|
||||
dt::from_RationalNumber(in.min_charge_power),
|
||||
dt::from_RationalNumber(in.max_charge_current),
|
||||
dt::from_RationalNumber(in.max_voltage),
|
||||
dt::from_RationalNumber(in.min_voltage),
|
||||
convert_from_optional(in.departure_time),
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
std::nullopt,
|
||||
std::nullopt};
|
||||
}
|
||||
|
||||
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::BPT_Dynamic_DC_CLReqControlMode& in) {
|
||||
return {dt::from_RationalNumber(in.target_energy_request), dt::from_RationalNumber(in.max_energy_request),
|
||||
dt::from_RationalNumber(in.min_energy_request), dt::from_RationalNumber(in.max_charge_power),
|
||||
dt::from_RationalNumber(in.min_charge_power), dt::from_RationalNumber(in.max_charge_current),
|
||||
dt::from_RationalNumber(in.max_voltage), dt::from_RationalNumber(in.min_voltage),
|
||||
convert_from_optional(in.departure_time), dt::from_RationalNumber(in.max_discharge_power),
|
||||
dt::from_RationalNumber(in.min_discharge_power), dt::from_RationalNumber(in.max_discharge_current),
|
||||
convert_from_optional(in.max_v2x_energy_request), convert_from_optional(in.min_v2x_energy_request)};
|
||||
}
|
||||
|
||||
template <>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
|
||||
const iso15118::d20::DcTransferLimits& evse_limits,
|
||||
const dt::DC_CPDReqEnergyTransferMode& ev_limits) {
|
||||
// As per the OCPP 2.1 spec (2.109) we should use the MIN/MAX function between EV and EVSE
|
||||
out_params.min_charge_power = std::max(dt::from_RationalNumber(evse_limits.charge_limits.power.min),
|
||||
dt::from_RationalNumber(ev_limits.min_charge_power));
|
||||
out_params.max_charge_power = std::min(dt::from_RationalNumber(evse_limits.charge_limits.power.max),
|
||||
dt::from_RationalNumber(ev_limits.max_charge_power));
|
||||
|
||||
out_params.min_charge_current = std::max(dt::from_RationalNumber(evse_limits.charge_limits.current.min),
|
||||
dt::from_RationalNumber(ev_limits.min_charge_current));
|
||||
out_params.max_charge_current = std::min(dt::from_RationalNumber(evse_limits.charge_limits.current.max),
|
||||
dt::from_RationalNumber(ev_limits.max_charge_current));
|
||||
|
||||
out_params.min_voltage =
|
||||
std::max(dt::from_RationalNumber(evse_limits.voltage.min), dt::from_RationalNumber(ev_limits.min_voltage));
|
||||
out_params.max_voltage =
|
||||
std::min(dt::from_RationalNumber(evse_limits.voltage.max), dt::from_RationalNumber(ev_limits.max_voltage));
|
||||
|
||||
out_params.target_soc = ev_limits.target_soc;
|
||||
}
|
||||
|
||||
template <>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
|
||||
const iso15118::d20::DcTransferLimits& evse_limits,
|
||||
const dt::BPT_DC_CPDReqEnergyTransferMode& ev_limits) {
|
||||
// Fill in the common data
|
||||
fill_v2x_charging_parameters<iso15118::d20::DcTransferLimits, dt::DC_CPDReqEnergyTransferMode>(
|
||||
out_params, evse_limits, static_cast<const dt::DC_CPDReqEnergyTransferMode&>(ev_limits));
|
||||
|
||||
// Fill in the bidi data
|
||||
if (evse_limits.discharge_limits.has_value()) {
|
||||
const auto& evse_discharge_limits = evse_limits.discharge_limits.value();
|
||||
|
||||
out_params.min_discharge_power = std::max(dt::from_RationalNumber(evse_discharge_limits.power.min),
|
||||
dt::from_RationalNumber(ev_limits.min_discharge_power));
|
||||
out_params.max_discharge_power = std::min(dt::from_RationalNumber(evse_discharge_limits.power.max),
|
||||
dt::from_RationalNumber(ev_limits.max_discharge_power));
|
||||
|
||||
out_params.min_discharge_current = std::max(dt::from_RationalNumber(evse_discharge_limits.current.min),
|
||||
dt::from_RationalNumber(ev_limits.min_discharge_current));
|
||||
out_params.max_discharge_current = std::min(dt::from_RationalNumber(evse_discharge_limits.current.max),
|
||||
dt::from_RationalNumber(ev_limits.max_discharge_current));
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
|
||||
const iso15118::d20::AcTransferLimits& evse_limits,
|
||||
const dt::AC_CPDReqEnergyTransferMode& ev_limits) {
|
||||
// As per the OCPP 2.1 spec (2.109) we should use the MIN/MAX function between EV and EVSE
|
||||
out_params.min_charge_power = std::max(dt::from_RationalNumber(evse_limits.charge_power.min),
|
||||
dt::from_RationalNumber(ev_limits.min_charge_power));
|
||||
out_params.max_charge_power = std::min(dt::from_RationalNumber(evse_limits.charge_power.max),
|
||||
dt::from_RationalNumber(ev_limits.max_charge_power));
|
||||
|
||||
if (evse_limits.charge_power_L2.has_value() and ev_limits.max_charge_power_L2.has_value() and
|
||||
ev_limits.min_charge_power_L2.has_value()) {
|
||||
out_params.min_charge_power_l2 = std::max(dt::from_RationalNumber(evse_limits.charge_power_L2.value().min),
|
||||
dt::from_RationalNumber(ev_limits.min_charge_power_L2.value()));
|
||||
out_params.max_charge_power_l2 = std::min(dt::from_RationalNumber(evse_limits.charge_power_L2.value().max),
|
||||
dt::from_RationalNumber(ev_limits.max_charge_power_L2.value()));
|
||||
}
|
||||
|
||||
if (evse_limits.charge_power_L3.has_value() and ev_limits.max_charge_power_L3.has_value() and
|
||||
ev_limits.min_charge_power_L3.has_value()) {
|
||||
out_params.min_charge_power_l3 = std::max(dt::from_RationalNumber(evse_limits.charge_power_L3.value().min),
|
||||
dt::from_RationalNumber(ev_limits.min_charge_power_L3.value()));
|
||||
out_params.max_charge_power_l3 = std::min(dt::from_RationalNumber(evse_limits.charge_power_L3.value().max),
|
||||
dt::from_RationalNumber(ev_limits.max_charge_power_L3.value()));
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
|
||||
const iso15118::d20::AcTransferLimits& evse_limits,
|
||||
const dt::BPT_AC_CPDReqEnergyTransferMode& ev_limits) {
|
||||
// Fill in the common data
|
||||
fill_v2x_charging_parameters<iso15118::d20::AcTransferLimits, dt::AC_CPDReqEnergyTransferMode>(
|
||||
out_params, evse_limits, static_cast<const dt::AC_CPDReqEnergyTransferMode&>(ev_limits));
|
||||
|
||||
if (evse_limits.discharge_power.has_value()) {
|
||||
const auto& evse_discharge_limits = evse_limits.discharge_power.value();
|
||||
|
||||
out_params.min_discharge_power = std::max(dt::from_RationalNumber(evse_discharge_limits.min),
|
||||
dt::from_RationalNumber(ev_limits.min_discharge_power));
|
||||
out_params.max_discharge_power = std::min(dt::from_RationalNumber(evse_discharge_limits.max),
|
||||
dt::from_RationalNumber(ev_limits.max_discharge_power));
|
||||
}
|
||||
|
||||
if (evse_limits.discharge_power_L2.has_value() && ev_limits.min_discharge_power_L2.has_value() &&
|
||||
ev_limits.max_discharge_power_L2.has_value()) {
|
||||
const auto& evse_discharge_limits = evse_limits.discharge_power_L2.value();
|
||||
|
||||
out_params.min_discharge_power_l2 = std::max(dt::from_RationalNumber(evse_discharge_limits.min),
|
||||
dt::from_RationalNumber(ev_limits.min_discharge_power_L2.value()));
|
||||
out_params.max_discharge_power_l2 = std::min(dt::from_RationalNumber(evse_discharge_limits.max),
|
||||
dt::from_RationalNumber(ev_limits.max_discharge_power_L2.value()));
|
||||
}
|
||||
|
||||
if (evse_limits.discharge_power_L3.has_value() && ev_limits.min_discharge_power_L3.has_value() &&
|
||||
ev_limits.max_discharge_power_L3.has_value()) {
|
||||
const auto& evse_discharge_limits = evse_limits.discharge_power_L3.value();
|
||||
|
||||
out_params.min_discharge_power_l3 = std::max(dt::from_RationalNumber(evse_discharge_limits.min),
|
||||
dt::from_RationalNumber(ev_limits.min_discharge_power_L3.value()));
|
||||
out_params.max_discharge_power_l3 = std::min(dt::from_RationalNumber(evse_discharge_limits.max),
|
||||
dt::from_RationalNumber(ev_limits.max_discharge_power_L3.value()));
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
|
||||
const dt::Scheduled_SEReqControlMode& ev_control_mode) {
|
||||
out_params.ev_target_energy_request = convert_from_optional(ev_control_mode.target_energy);
|
||||
out_params.ev_min_energy_request = convert_from_optional(ev_control_mode.min_energy);
|
||||
out_params.ev_max_energy_request = convert_from_optional(ev_control_mode.max_energy);
|
||||
}
|
||||
|
||||
template <>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params,
|
||||
const dt::Dynamic_SEReqControlMode& ev_control_mode) {
|
||||
out_params.ev_target_energy_request = dt::from_RationalNumber(ev_control_mode.target_energy);
|
||||
out_params.ev_min_energy_request = dt::from_RationalNumber(ev_control_mode.min_energy);
|
||||
out_params.ev_max_energy_request = dt::from_RationalNumber(ev_control_mode.max_energy);
|
||||
|
||||
out_params.ev_min_v2xenergy_request = convert_from_optional(ev_control_mode.min_v2x_energy);
|
||||
out_params.ev_max_v2xenergy_request = convert_from_optional(ev_control_mode.max_v2x_energy);
|
||||
}
|
||||
|
||||
everest::lib::util::fixed_vector<dt::ParameterSet, 32>
|
||||
convert_parameter_set_list(const std::vector<types::iso15118_vas::ParameterSet>& parameter_set_list) {
|
||||
everest::lib::util::fixed_vector<dt::ParameterSet, 32> out;
|
||||
for (const auto& parameter_set : parameter_set_list) {
|
||||
const auto* ptr = out.try_emplace_back(convert_parameter_set(parameter_set));
|
||||
|
||||
if (ptr == nullptr) {
|
||||
EVLOG_warning << "VAS parameter set list is bigger then 32";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::AC_CPDReqEnergyTransferMode& mode) {
|
||||
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
|
||||
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
|
||||
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
|
||||
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
|
||||
|
||||
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
|
||||
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
|
||||
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
|
||||
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
|
||||
|
||||
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
|
||||
|
||||
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
|
||||
max_charge_L3};
|
||||
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
|
||||
min_charge_L3};
|
||||
|
||||
return ac_ev_power_limits;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_AC_CPDReqEnergyTransferMode& mode) {
|
||||
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
|
||||
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
|
||||
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
|
||||
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
|
||||
|
||||
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
|
||||
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
|
||||
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
|
||||
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
|
||||
|
||||
const auto max_discharge_L1 = dt::from_RationalNumber(mode.max_discharge_power);
|
||||
const auto max_discharge_L2 = convert_from_optional(mode.max_discharge_power_L2);
|
||||
const auto max_discharge_L3 = convert_from_optional(mode.max_discharge_power_L3);
|
||||
const auto max_discharge_total = max_discharge_L1 + max_discharge_L2.value_or(0.0) + max_discharge_L3.value_or(0.0);
|
||||
|
||||
const auto min_discharge_L1 = dt::from_RationalNumber(mode.min_discharge_power);
|
||||
const auto min_discharge_L2 = convert_from_optional(mode.min_discharge_power_L2);
|
||||
const auto min_discharge_L3 = convert_from_optional(mode.min_discharge_power_L3);
|
||||
const auto min_discharge_total = min_discharge_L1 + min_discharge_L2.value_or(0.0) + min_discharge_L3.value_or(0.0);
|
||||
|
||||
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
|
||||
|
||||
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
|
||||
max_charge_L3};
|
||||
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
|
||||
min_charge_L3};
|
||||
ac_ev_power_limits.max_discharge_power = {max_discharge_total, std::make_optional<float>(max_discharge_L1),
|
||||
max_discharge_L2, max_discharge_L3};
|
||||
ac_ev_power_limits.min_discharge_power = {min_discharge_total, std::make_optional<float>(min_discharge_L1),
|
||||
min_discharge_L2, min_discharge_L3};
|
||||
|
||||
return ac_ev_power_limits;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Dynamic_AC_CLReqControlMode& mode) {
|
||||
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
|
||||
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
|
||||
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
|
||||
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
|
||||
|
||||
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
|
||||
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
|
||||
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
|
||||
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
|
||||
|
||||
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
|
||||
|
||||
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
|
||||
max_charge_L3};
|
||||
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
|
||||
min_charge_L3};
|
||||
|
||||
return ac_ev_power_limits;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Dynamic_AC_CLReqControlMode& mode) {
|
||||
const auto max_charge_L1 = dt::from_RationalNumber(mode.max_charge_power);
|
||||
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
|
||||
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
|
||||
const auto max_charge_total = max_charge_L1 + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
|
||||
|
||||
const auto min_charge_L1 = dt::from_RationalNumber(mode.min_charge_power);
|
||||
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
|
||||
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
|
||||
const auto min_charge_total = min_charge_L1 + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
|
||||
|
||||
const auto max_discharge_L1 = dt::from_RationalNumber(mode.max_discharge_power);
|
||||
const auto max_discharge_L2 = convert_from_optional(mode.max_discharge_power_L2);
|
||||
const auto max_discharge_L3 = convert_from_optional(mode.max_discharge_power_L3);
|
||||
const auto max_discharge_total = max_discharge_L1 + max_discharge_L2.value_or(0.0) + max_discharge_L3.value_or(0.0);
|
||||
|
||||
const auto min_discharge_L1 = dt::from_RationalNumber(mode.min_discharge_power);
|
||||
const auto min_discharge_L2 = convert_from_optional(mode.min_discharge_power_L2);
|
||||
const auto min_discharge_L3 = convert_from_optional(mode.min_discharge_power_L3);
|
||||
const auto min_discharge_total = min_discharge_L1 + min_discharge_L2.value_or(0.0) + min_discharge_L3.value_or(0.0);
|
||||
|
||||
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
|
||||
|
||||
ac_ev_power_limits.max_charge_power = {max_charge_total, std::make_optional<float>(max_charge_L1), max_charge_L2,
|
||||
max_charge_L3};
|
||||
ac_ev_power_limits.min_charge_power = {min_charge_total, std::make_optional<float>(min_charge_L1), min_charge_L2,
|
||||
min_charge_L3};
|
||||
ac_ev_power_limits.max_discharge_power = {max_discharge_total, std::make_optional<float>(max_discharge_L1),
|
||||
max_discharge_L2, max_discharge_L3};
|
||||
ac_ev_power_limits.min_discharge_power = {min_discharge_total, std::make_optional<float>(min_discharge_L1),
|
||||
min_discharge_L2, min_discharge_L3};
|
||||
|
||||
return ac_ev_power_limits;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Scheduled_AC_CLReqControlMode& mode) {
|
||||
const auto max_charge_L1 = convert_from_optional(mode.max_charge_power);
|
||||
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
|
||||
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
|
||||
const auto max_charge_total =
|
||||
max_charge_L1.value_or(0.0) + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
|
||||
|
||||
const auto min_charge_L1 = convert_from_optional(mode.min_charge_power);
|
||||
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
|
||||
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
|
||||
const auto min_charge_total =
|
||||
min_charge_L1.value_or(0.0) + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
|
||||
|
||||
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
|
||||
|
||||
ac_ev_power_limits.max_charge_power =
|
||||
(max_charge_L1.has_value() or max_charge_L2.has_value() or max_charge_L3.has_value())
|
||||
? std::make_optional<types::units::Power>({max_charge_total, max_charge_L1, max_charge_L2, max_charge_L3})
|
||||
: std::nullopt;
|
||||
ac_ev_power_limits.min_charge_power =
|
||||
(max_charge_L1.has_value() or max_charge_L2.has_value() or max_charge_L3.has_value())
|
||||
? std::make_optional<types::units::Power>({min_charge_total, min_charge_L1, min_charge_L2, min_charge_L3})
|
||||
: std::nullopt;
|
||||
|
||||
return ac_ev_power_limits;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Scheduled_AC_CLReqControlMode& mode) {
|
||||
const auto max_charge_L1 = convert_from_optional(mode.max_charge_power);
|
||||
const auto max_charge_L2 = convert_from_optional(mode.max_charge_power_L2);
|
||||
const auto max_charge_L3 = convert_from_optional(mode.max_charge_power_L3);
|
||||
const auto max_charge_total =
|
||||
max_charge_L1.value_or(0.0) + max_charge_L2.value_or(0.0) + max_charge_L3.value_or(0.0);
|
||||
|
||||
const auto min_charge_L1 = convert_from_optional(mode.min_charge_power);
|
||||
const auto min_charge_L2 = convert_from_optional(mode.min_charge_power_L2);
|
||||
const auto min_charge_L3 = convert_from_optional(mode.min_charge_power_L3);
|
||||
const auto min_charge_total =
|
||||
min_charge_L1.value_or(0.0) + min_charge_L2.value_or(0.0) + min_charge_L3.value_or(0.0);
|
||||
|
||||
const auto max_discharge_L1 = convert_from_optional(mode.max_discharge_power);
|
||||
const auto max_discharge_L2 = convert_from_optional(mode.max_discharge_power_L2);
|
||||
const auto max_discharge_L3 = convert_from_optional(mode.max_discharge_power_L3);
|
||||
const auto max_discharge_total =
|
||||
max_discharge_L1.value_or(0.0) + max_discharge_L2.value_or(0.0) + max_discharge_L3.value_or(0.0);
|
||||
|
||||
const auto min_discharge_L1 = convert_from_optional(mode.min_discharge_power);
|
||||
const auto min_discharge_L2 = convert_from_optional(mode.min_discharge_power_L2);
|
||||
const auto min_discharge_L3 = convert_from_optional(mode.min_discharge_power_L3);
|
||||
const auto min_discharge_total =
|
||||
min_discharge_L1.value_or(0.0) + min_discharge_L2.value_or(0.0) + min_discharge_L3.value_or(0.0);
|
||||
|
||||
types::iso15118::AcEvPowerLimits ac_ev_power_limits;
|
||||
|
||||
ac_ev_power_limits.max_charge_power =
|
||||
(max_charge_L1.has_value() or max_charge_L2.has_value() or max_charge_L3.has_value())
|
||||
? std::make_optional<types::units::Power>({max_charge_total, max_charge_L1, max_charge_L2, max_charge_L3})
|
||||
: std::nullopt;
|
||||
ac_ev_power_limits.min_charge_power =
|
||||
(min_charge_L1.has_value() or min_charge_L2.has_value() or min_charge_L3.has_value())
|
||||
? std::make_optional<types::units::Power>({min_charge_total, min_charge_L1, min_charge_L2, min_charge_L3})
|
||||
: std::nullopt;
|
||||
ac_ev_power_limits.max_discharge_power =
|
||||
(max_discharge_L1.has_value() or max_discharge_L2.has_value() or max_discharge_L3.has_value())
|
||||
? std::make_optional<types::units::Power>(
|
||||
{max_discharge_total, max_discharge_L1, max_discharge_L2, max_discharge_L3})
|
||||
: std::nullopt;
|
||||
ac_ev_power_limits.min_discharge_power =
|
||||
(min_discharge_L1.has_value() or min_discharge_L2.has_value() or min_discharge_L3.has_value())
|
||||
? std::make_optional<types::units::Power>(
|
||||
{min_discharge_total, min_discharge_L1, min_discharge_L2, min_discharge_L3})
|
||||
: std::nullopt;
|
||||
return ac_ev_power_limits;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Dynamic_AC_CLReqControlMode& mode) {
|
||||
types::iso15118::AcEvPresentPowerValues present_values{};
|
||||
|
||||
const auto present_active_power_L1 = dt::from_RationalNumber(mode.present_active_power);
|
||||
const auto present_active_power_L2 = convert_from_optional(mode.present_active_power_L2);
|
||||
const auto present_active_power_L3 = convert_from_optional(mode.present_active_power_L3);
|
||||
const auto present_active_power_total =
|
||||
present_active_power_L1 + present_active_power_L2.value_or(0.0) + present_active_power_L3.value_or(0.0);
|
||||
|
||||
const auto present_reactive_power_L1 = dt::from_RationalNumber(mode.present_reactive_power);
|
||||
const auto present_reactive_power_L2 = convert_from_optional(mode.present_reactive_power_L2);
|
||||
const auto present_reactive_power_L3 = convert_from_optional(mode.present_reactive_power_L3);
|
||||
const auto present_reactive_power_total =
|
||||
present_reactive_power_L1 + present_reactive_power_L2.value_or(0.0) + present_reactive_power_L3.value_or(0.0);
|
||||
|
||||
present_values.present_active_power = {present_active_power_total, present_active_power_L1, present_active_power_L2,
|
||||
present_active_power_L3};
|
||||
|
||||
present_values.present_reactive_power = {present_reactive_power_total, present_reactive_power_L1,
|
||||
present_reactive_power_L2, present_reactive_power_L3};
|
||||
|
||||
return present_values;
|
||||
}
|
||||
|
||||
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Scheduled_AC_CLReqControlMode& mode) {
|
||||
types::iso15118::AcEvPresentPowerValues present_values{};
|
||||
|
||||
const auto present_active_power_L1 = dt::from_RationalNumber(mode.present_active_power);
|
||||
const auto present_active_power_L2 = convert_from_optional(mode.present_active_power_L2);
|
||||
const auto present_active_power_L3 = convert_from_optional(mode.present_active_power_L3);
|
||||
const auto present_active_power_total =
|
||||
present_active_power_L1 + present_active_power_L2.value_or(0.0) + present_active_power_L3.value_or(0.0);
|
||||
|
||||
const auto present_reactive_power_L1 = convert_from_optional(mode.present_reactive_power);
|
||||
const auto present_reactive_power_L2 = convert_from_optional(mode.present_reactive_power_L2);
|
||||
const auto present_reactive_power_L3 = convert_from_optional(mode.present_reactive_power_L3);
|
||||
const auto present_reactive_power_total = present_reactive_power_L1.value_or(0.0) +
|
||||
present_reactive_power_L2.value_or(0.0) +
|
||||
present_reactive_power_L3.value_or(0.0);
|
||||
|
||||
present_values.present_active_power = {present_active_power_total, present_active_power_L1, present_active_power_L2,
|
||||
present_active_power_L3};
|
||||
|
||||
present_values.present_reactive_power =
|
||||
(present_reactive_power_L1.has_value() or present_reactive_power_L2.has_value() or
|
||||
present_reactive_power_L3.has_value())
|
||||
? std::make_optional<types::units::Power>({present_reactive_power_total, present_reactive_power_L1,
|
||||
present_reactive_power_L2, present_reactive_power_L3})
|
||||
: std::nullopt;
|
||||
|
||||
return present_values;
|
||||
}
|
||||
|
||||
} // namespace module::charger
|
||||
152
tools/EVerest-main/modules/EVSE/Evse15118D20/charger/utils.hpp
Normal file
152
tools/EVerest-main/modules/EVSE/Evse15118D20/charger/utils.hpp
Normal file
@@ -0,0 +1,152 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <generated/types/iso15118.hpp>
|
||||
#include <generated/types/iso15118_vas.hpp>
|
||||
|
||||
#include <iso15118/d20/ev_information.hpp>
|
||||
#include <iso15118/message/ac_charge_loop.hpp>
|
||||
#include <iso15118/message/ac_charge_parameter_discovery.hpp>
|
||||
#include <iso15118/message/dc_charge_loop.hpp>
|
||||
#include <iso15118/message/service_detail.hpp>
|
||||
#include <iso15118/message/type.hpp>
|
||||
|
||||
#include <everest/util/vector/fixed_vector.hpp>
|
||||
|
||||
static constexpr auto NUMBER_OF_SETUP_STEPS = 5;
|
||||
|
||||
namespace module::charger {
|
||||
|
||||
namespace dt = iso15118::message_20::datatypes;
|
||||
|
||||
enum class SetupStep : std::uint8_t {
|
||||
SETUP,
|
||||
ENERGY_SERVICE,
|
||||
AUTH_SETUP,
|
||||
MAX_LIMITS,
|
||||
MIN_LIMITS,
|
||||
};
|
||||
|
||||
template <typename T> constexpr auto to_underlying_value(T t) {
|
||||
return static_cast<std::underlying_type_t<T>>(t);
|
||||
}
|
||||
|
||||
static_assert(NUMBER_OF_SETUP_STEPS == to_underlying_value(SetupStep::MIN_LIMITS) + 1,
|
||||
"NUMBER_OF_SETUP_STEPS should be in sync with the SetupStep enum definition");
|
||||
|
||||
constexpr types::iso15118::V2gMessageId convert_v2g_message_type(iso15118::message_20::Type type) {
|
||||
|
||||
using Type = iso15118::message_20::Type;
|
||||
using Id = types::iso15118::V2gMessageId;
|
||||
|
||||
switch (type) {
|
||||
case Type::None:
|
||||
return Id::UnknownMessage;
|
||||
case Type::SupportedAppProtocolReq:
|
||||
return Id::SupportedAppProtocolReq;
|
||||
case Type::SupportedAppProtocolRes:
|
||||
return Id::SupportedAppProtocolRes;
|
||||
case Type::SessionSetupReq:
|
||||
return Id::SessionSetupReq;
|
||||
case Type::SessionSetupRes:
|
||||
return Id::SessionSetupRes;
|
||||
case Type::AuthorizationSetupReq:
|
||||
return Id::AuthorizationSetupReq;
|
||||
case Type::AuthorizationSetupRes:
|
||||
return Id::AuthorizationSetupRes;
|
||||
case Type::AuthorizationReq:
|
||||
return Id::AuthorizationReq;
|
||||
case Type::AuthorizationRes:
|
||||
return Id::AuthorizationRes;
|
||||
case Type::ServiceDiscoveryReq:
|
||||
return Id::ServiceDiscoveryReq;
|
||||
case Type::ServiceDiscoveryRes:
|
||||
return Id::ServiceDiscoveryRes;
|
||||
case Type::ServiceDetailReq:
|
||||
return Id::ServiceDetailReq;
|
||||
case Type::ServiceDetailRes:
|
||||
return Id::ServiceDetailRes;
|
||||
case Type::ServiceSelectionReq:
|
||||
return Id::ServiceSelectionReq;
|
||||
case Type::ServiceSelectionRes:
|
||||
return Id::ServiceSelectionRes;
|
||||
case Type::DC_ChargeParameterDiscoveryReq:
|
||||
return Id::DcChargeParameterDiscoveryReq;
|
||||
case Type::DC_ChargeParameterDiscoveryRes:
|
||||
return Id::DcChargeParameterDiscoveryRes;
|
||||
case Type::ScheduleExchangeReq:
|
||||
return Id::ScheduleExchangeReq;
|
||||
case Type::ScheduleExchangeRes:
|
||||
return Id::ScheduleExchangeRes;
|
||||
case Type::DC_CableCheckReq:
|
||||
return Id::DcCableCheckReq;
|
||||
case Type::DC_CableCheckRes:
|
||||
return Id::DcCableCheckRes;
|
||||
case Type::DC_PreChargeReq:
|
||||
return Id::DcPreChargeReq;
|
||||
case Type::DC_PreChargeRes:
|
||||
return Id::DcPreChargeRes;
|
||||
case Type::PowerDeliveryReq:
|
||||
return Id::PowerDeliveryReq;
|
||||
case Type::PowerDeliveryRes:
|
||||
return Id::PowerDeliveryRes;
|
||||
case Type::DC_ChargeLoopReq:
|
||||
return Id::DcChargeLoopReq;
|
||||
case Type::DC_ChargeLoopRes:
|
||||
return Id::DcChargeLoopRes;
|
||||
case Type::DC_WeldingDetectionReq:
|
||||
return Id::DcWeldingDetectionReq;
|
||||
case Type::DC_WeldingDetectionRes:
|
||||
return Id::DcWeldingDetectionRes;
|
||||
case Type::SessionStopReq:
|
||||
return Id::SessionStopReq;
|
||||
case Type::SessionStopRes:
|
||||
return Id::SessionStopRes;
|
||||
case Type::AC_ChargeParameterDiscoveryReq:
|
||||
return Id::AcChargeParameterDiscoveryReq;
|
||||
case Type::AC_ChargeParameterDiscoveryRes:
|
||||
return Id::AcChargeParameterDiscoveryRes;
|
||||
case Type::AC_ChargeLoopReq:
|
||||
return Id::AcChargeLoopReq;
|
||||
case Type::AC_ChargeLoopRes:
|
||||
return Id::AcChargeLoopRes;
|
||||
}
|
||||
|
||||
return Id::UnknownMessage;
|
||||
}
|
||||
|
||||
std::optional<float> convert_from_optional(const std::optional<dt::RationalNumber>& in);
|
||||
std::optional<dt::RationalNumber> convert_from_optional(const std::optional<float>& in);
|
||||
std::optional<float> convert_from_optional(const std::optional<uint32_t>& in);
|
||||
|
||||
types::iso15118::AppProtocol convert_app_protocol(const iso15118::message_20::SupportedAppProtocol& app_protocol);
|
||||
types::iso15118::EvInformation convert_ev_info(const iso15118::d20::EVInformation& ev_info);
|
||||
|
||||
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::Dynamic_DC_CLReqControlMode& in);
|
||||
types::iso15118::DcChargeDynamicModeValues convert_dynamic_values(const dt::BPT_Dynamic_DC_CLReqControlMode& in);
|
||||
|
||||
template <typename EVSE, typename EV>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params, const EVSE& evse_limits,
|
||||
const EV& ev_limits);
|
||||
template <typename In>
|
||||
void fill_v2x_charging_parameters(types::iso15118::V2XChargingParameters& out_params, const In& data);
|
||||
|
||||
everest::lib::util::fixed_vector<dt::ParameterSet, 32>
|
||||
convert_parameter_set_list(const std::vector<types::iso15118_vas::ParameterSet>& parameter_set_list);
|
||||
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::AC_CPDReqEnergyTransferMode& mode);
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_AC_CPDReqEnergyTransferMode& mode);
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Dynamic_AC_CLReqControlMode& mode);
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Dynamic_AC_CLReqControlMode& mode);
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::Scheduled_AC_CLReqControlMode& mode);
|
||||
types::iso15118::AcEvPowerLimits fill_ac_ev_power_limits(const dt::BPT_Scheduled_AC_CLReqControlMode& mode);
|
||||
|
||||
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Dynamic_AC_CLReqControlMode& mode);
|
||||
types::iso15118::AcEvPresentPowerValues fill_ac_ev_present_power_values(const dt::Scheduled_AC_CLReqControlMode& mode);
|
||||
|
||||
} // namespace module::charger
|
||||
@@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#include "iso15118_extensionsImpl.hpp"
|
||||
|
||||
namespace module {
|
||||
namespace extensions {
|
||||
|
||||
void iso15118_extensionsImpl::init() {
|
||||
}
|
||||
|
||||
void iso15118_extensionsImpl::ready() {
|
||||
}
|
||||
|
||||
void iso15118_extensionsImpl::handle_set_get_certificate_response(
|
||||
types::iso15118::ResponseExiStreamStatus& certificate_response) {
|
||||
// your code for cmd set_get_certificate_response goes here
|
||||
}
|
||||
|
||||
} // namespace extensions
|
||||
} // namespace module
|
||||
@@ -0,0 +1,62 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
#ifndef EXTENSIONS_ISO15118_EXTENSIONS_IMPL_HPP
|
||||
#define EXTENSIONS_ISO15118_EXTENSIONS_IMPL_HPP
|
||||
|
||||
//
|
||||
// AUTO GENERATED - MARKED REGIONS WILL BE KEPT
|
||||
// template version 3
|
||||
//
|
||||
|
||||
#include <generated/interfaces/iso15118_extensions/Implementation.hpp>
|
||||
|
||||
#include "../Evse15118D20.hpp"
|
||||
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
// insert your custom include headers here
|
||||
// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1
|
||||
|
||||
namespace module {
|
||||
namespace extensions {
|
||||
|
||||
struct Conf {};
|
||||
|
||||
class iso15118_extensionsImpl : public iso15118_extensionsImplBase {
|
||||
public:
|
||||
iso15118_extensionsImpl() = delete;
|
||||
iso15118_extensionsImpl(Everest::ModuleAdapter* ev, const Everest::PtrContainer<Evse15118D20>& mod, Conf& config) :
|
||||
iso15118_extensionsImplBase(ev, "extensions"), 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 void
|
||||
handle_set_get_certificate_response(types::iso15118::ResponseExiStreamStatus& certificate_response) override;
|
||||
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
// insert your protected definitions here
|
||||
// ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1
|
||||
|
||||
private:
|
||||
const Everest::PtrContainer<Evse15118D20>& 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 extensions
|
||||
} // namespace module
|
||||
|
||||
#endif // EXTENSIONS_ISO15118_EXTENSIONS_IMPL_HPP
|
||||
93
tools/EVerest-main/modules/EVSE/Evse15118D20/manifest.yaml
Normal file
93
tools/EVerest-main/modules/EVSE/Evse15118D20/manifest.yaml
Normal file
@@ -0,0 +1,93 @@
|
||||
description: >-
|
||||
This module is a draft implementation of iso15118-20 for the EVSE side
|
||||
config:
|
||||
device:
|
||||
description: >-
|
||||
Ethernet device used for HLC. Any local interface that has an ipv6
|
||||
link-local and a MAC addr will work
|
||||
type: string
|
||||
default: eth0
|
||||
logging_path:
|
||||
description: Path to logging directory (will be created if non existent)
|
||||
type: string
|
||||
default: "."
|
||||
tls_negotiation_strategy:
|
||||
description: Select strategy on how to negotiate connection encryption
|
||||
type: string
|
||||
enum:
|
||||
- ACCEPT_CLIENT_OFFER
|
||||
- ENFORCE_TLS
|
||||
- ENFORCE_NO_TLS
|
||||
default: ACCEPT_CLIENT_OFFER
|
||||
enforce_tls_1_3:
|
||||
description: Enforcing tls version 1.3. Only applies if tls_negotiation_strategy is ENFORCE_TLS.
|
||||
type: boolean
|
||||
default: false
|
||||
enable_ssl_logging:
|
||||
description: Verbosely log the ssl/tls connection
|
||||
type: boolean
|
||||
default: false
|
||||
enable_tls_key_logging:
|
||||
description: >-
|
||||
Enable/Disable the export of TLS session keys (pre-master-secret)
|
||||
during a TLS handshake. Note that this option is for testing and
|
||||
simulation purpose only
|
||||
type: boolean
|
||||
default: false
|
||||
tls_key_logging_path:
|
||||
description: >-
|
||||
Output directory for the TLS key log file
|
||||
type: string
|
||||
default: /tmp
|
||||
enable_sdp_server:
|
||||
description: >-
|
||||
Enable the built-in SDP server
|
||||
type: boolean
|
||||
default: true
|
||||
supported_dynamic_mode:
|
||||
description: The EVSE should support dynamic mode
|
||||
type: boolean
|
||||
default: true
|
||||
supported_mobility_needs_mode_provided_by_secc:
|
||||
description: >-
|
||||
The EVSE should support the mobility needs mode provided by the SECC.
|
||||
Mobility needs mode provided by the EVCC is always provided.
|
||||
type: boolean
|
||||
default: false
|
||||
supported_scheduled_mode:
|
||||
description: The EVSE should support scheduled mode
|
||||
type: boolean
|
||||
default: false
|
||||
custom_protocol_namespace:
|
||||
description: Providing a custom protocol namespace.
|
||||
type: string
|
||||
default: ""
|
||||
negative_bidirectional_limits:
|
||||
description: >-
|
||||
Some cars send or expect negative discharge limits. However, it is not clear from the standard
|
||||
whether the discharge limits should be negative. Until this is clarified, the positive limits
|
||||
can be converted using this option.
|
||||
type: boolean
|
||||
default: false
|
||||
provides:
|
||||
charger:
|
||||
interface: ISO15118_charger
|
||||
description: >-
|
||||
This interface provides limited access to iso15118-20
|
||||
extensions:
|
||||
interface: iso15118_extensions
|
||||
description: >-
|
||||
This interface is used to share data between ISO15118 and OCPP modules
|
||||
to support the requirements of the OCPP protocol
|
||||
requires:
|
||||
security:
|
||||
interface: evse_security
|
||||
iso15118_vas:
|
||||
interface: ISO15118_vas
|
||||
min_connections: 0
|
||||
max_connections: 128
|
||||
metadata:
|
||||
license: https://opensource.org/licenses/Apache-2.0
|
||||
authors:
|
||||
- aw@pionix.de
|
||||
- Sebastian Lukas
|
||||
Reference in New Issue
Block a user