diff --git a/config/config-sil-dc-isomux-tls.yaml b/config/config-sil-dc-isomux-tls.yaml index d2800a103..e930940d4 100644 --- a/config/config-sil-dc-isomux-tls.yaml +++ b/config/config-sil-dc-isomux-tls.yaml @@ -34,6 +34,12 @@ active_modules: iso20: - module_id: iso15118_20 implementation_id: charger + ext2: + - module_id: iso15118_2 + implementation_id: extensions + ext20: + - module_id: iso15118_20 + implementation_id: extensions iso15118_car: module: PyEvJosev config_module: diff --git a/config/config-sil-dc-isomux.yaml b/config/config-sil-dc-isomux.yaml index 22de15180..f34e8461a 100644 --- a/config/config-sil-dc-isomux.yaml +++ b/config/config-sil-dc-isomux.yaml @@ -34,6 +34,12 @@ active_modules: iso20: - module_id: iso15118_20 implementation_id: charger + ext2: + - module_id: iso15118_2 + implementation_id: extensions + ext20: + - module_id: iso15118_20 + implementation_id: extensions iso15118_car: module: PyEvJosev config_module: diff --git a/config/config-sil-ocpp-pnc.yaml b/config/config-sil-ocpp-pnc.yaml index e5b092279..46a66fe49 100644 --- a/config/config-sil-ocpp-pnc.yaml +++ b/config/config-sil-ocpp-pnc.yaml @@ -176,6 +176,9 @@ active_modules: implementation_id: external_limits - module_id: evse_manager_2_ocpp_sink implementation_id: external_limits + extensions_15118: + - module_id: iso15118_charger + implementation_id: extensions evse_security: module: EvseSecurity config_module: diff --git a/config/config-sil-ocpp201-pnc.yaml b/config/config-sil-ocpp201-pnc.yaml index 7556d44b1..9af336fc5 100644 --- a/config/config-sil-ocpp201-pnc.yaml +++ b/config/config-sil-ocpp201-pnc.yaml @@ -146,6 +146,9 @@ active_modules: reservation: - module_id: auth implementation_id: reservation + extensions_15118: + - module_id: iso15118_charger + implementation_id: extensions evse_security: module: EvseSecurity config_module: diff --git a/interfaces/ISO15118_charger.yaml b/interfaces/ISO15118_charger.yaml index a322aa6e2..30b81468c 100644 --- a/interfaces/ISO15118_charger.yaml +++ b/interfaces/ISO15118_charger.yaml @@ -53,16 +53,6 @@ cmds: connection to an SA for this purpose type: boolean # Response messages to vars: - certificate_response: - description: >- - This message is an async response to a previously published certificate_request. - The new/updated Contract Certificate (including the certificate chain) and the - corresponding encrypted private key are sent via the SECC to the EVCC. - arguments: - exi_stream_status: - description: The response raw EXI stream and the status from the CSMS - type: object - $ref: /iso15118_charger#/ResponseExiStreamStatus authorization_response: description: >- This message is an async response to a previously published require_auth_eim @@ -314,13 +304,6 @@ vars: description: Estimated or calculated time until bulk and full charge is complete type: object $ref: /iso15118_charger#/DcEvRemainingTime - certificate_request: - description: >- - The vehicle requests the SECC to deliver the certificate that belong - to the currently valid contract of the vehicle. - Response will be reported async via set_Get_Certificate_Response - type: object - $ref: /iso15118_charger#/RequestExiStreamSchema dlink_terminate: description: Terminate the data link and become UNMATCHED. type: "null" diff --git a/interfaces/evse_manager.yaml b/interfaces/evse_manager.yaml index 3478d3997..dd5184a8a 100644 --- a/interfaces/evse_manager.yaml +++ b/interfaces/evse_manager.yaml @@ -102,16 +102,6 @@ cmds: result: description: Returns true if unlocking sequence was successfully executed type: boolean - set_get_certificate_response: - description: >- - CertificateInstallationRes/CertificateUpdateRes - Set the new/updated Contract Certificate (including the certificate chain) - and the corresponding encrypted private key. Should be forwared to EVCC. - This is an async response to a previously published iso15118_certificate_request - arguments: - certificate_response: - description: The response raw exi stream and the status from the CSMS system - type: object - $ref: /iso15118_charger#/ResponseExiStreamStatus external_ready_to_start_charging: description: >- There are situations where another module needs to do some initialization after evse manager is in principle ready to start charging. @@ -154,13 +144,6 @@ vars: description: "Hardware capability/limits" type: object $ref: /evse_board_support#/HardwareCapabilities - iso15118_certificate_request: - description: >- - The vehicle requests the SECC to deliver the certificate that belong - to the currently valid contract of the vehicle. - Response will be reported async via set_get_certificate_response - type: object - $ref: /iso15118_charger#/RequestExiStreamSchema enforced_limits: description: Enforced limits for this node (coming from the EnergyManager) type: object diff --git a/interfaces/iso15118_extensions.yaml b/interfaces/iso15118_extensions.yaml new file mode 100644 index 000000000..4f180e350 --- /dev/null +++ b/interfaces/iso15118_extensions.yaml @@ -0,0 +1,20 @@ +description: This interface is used to share data between ISO15118 and OCPP modules to support the requirements of the OCPP protocol +cmds: + set_get_certificate_response: + description: >- + CertificateInstallationRes/CertificateUpdateRes - Set the new/updated Contract Certificate (including the certificate chain) + and the corresponding encrypted private key. Should be forwared to EVCC. + This is an async response to a previously published iso15118_certificate_request + arguments: + certificate_response: + description: The response raw exi stream and the status from the CSMS system + type: object + $ref: /iso15118_charger#/ResponseExiStreamStatus +vars: + iso15118_certificate_request: + description: >- + The vehicle requests the SECC to deliver the certificate that belong + to the currently valid contract of the vehicle. + Response will be reported async via set_get_certificate_response + type: object + $ref: /iso15118_charger#/RequestExiStreamSchema diff --git a/modules/DummyV2G/main/ISO15118_chargerImpl.cpp b/modules/DummyV2G/main/ISO15118_chargerImpl.cpp index 64216fe05..55f3fb6a5 100644 --- a/modules/DummyV2G/main/ISO15118_chargerImpl.cpp +++ b/modules/DummyV2G/main/ISO15118_chargerImpl.cpp @@ -29,11 +29,6 @@ void ISO15118_chargerImpl::handle_session_setup(std::vector& payment_options, bool& supported_certificate_service) override; - virtual void - handle_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& exi_stream_status) 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; diff --git a/modules/Evse15118D20/CMakeLists.txt b/modules/Evse15118D20/CMakeLists.txt index e0a6fc3a7..e4357099f 100644 --- a/modules/Evse15118D20/CMakeLists.txt +++ b/modules/Evse15118D20/CMakeLists.txt @@ -22,6 +22,7 @@ target_link_libraries(${MODULE_NAME} target_sources(${MODULE_NAME} PRIVATE "charger/ISO15118_chargerImpl.cpp" + "extensions/iso15118_extensionsImpl.cpp" ) # ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 diff --git a/modules/Evse15118D20/Evse15118D20.cpp b/modules/Evse15118D20/Evse15118D20.cpp index c139fdbc5..0c186e336 100644 --- a/modules/Evse15118D20/Evse15118D20.cpp +++ b/modules/Evse15118D20/Evse15118D20.cpp @@ -6,10 +6,12 @@ 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 diff --git a/modules/Evse15118D20/Evse15118D20.hpp b/modules/Evse15118D20/Evse15118D20.hpp index 1046f51f0..8f525108b 100644 --- a/modules/Evse15118D20/Evse15118D20.hpp +++ b/modules/Evse15118D20/Evse15118D20.hpp @@ -12,6 +12,7 @@ // headers for provided interface implementations #include +#include // headers for required interface implementations #include @@ -39,10 +40,16 @@ class Evse15118D20 : public Everest::ModuleBase { public: Evse15118D20() = delete; Evse15118D20(const ModuleInfo& info, std::unique_ptr p_charger, + std::unique_ptr p_extensions, std::unique_ptr r_security, Conf& config) : - ModuleBase(info), p_charger(std::move(p_charger)), r_security(std::move(r_security)), config(config){}; + ModuleBase(info), + p_charger(std::move(p_charger)), + p_extensions(std::move(p_extensions)), + r_security(std::move(r_security)), + config(config){}; const std::unique_ptr p_charger; + const std::unique_ptr p_extensions; const std::unique_ptr r_security; const Conf& config; diff --git a/modules/Evse15118D20/charger/ISO15118_chargerImpl.cpp b/modules/Evse15118D20/charger/ISO15118_chargerImpl.cpp index 876845b7f..025b93073 100644 --- a/modules/Evse15118D20/charger/ISO15118_chargerImpl.cpp +++ b/modules/Evse15118D20/charger/ISO15118_chargerImpl.cpp @@ -370,11 +370,6 @@ void ISO15118_chargerImpl::handle_session_setup(std::vector& payment_options, bool& supported_certificate_service) override; - virtual void - handle_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& exi_stream_status) 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; diff --git a/modules/Evse15118D20/extensions/iso15118_extensionsImpl.cpp b/modules/Evse15118D20/extensions/iso15118_extensionsImpl.cpp new file mode 100644 index 000000000..0b1e38c3c --- /dev/null +++ b/modules/Evse15118D20/extensions/iso15118_extensionsImpl.cpp @@ -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_charger::ResponseExiStreamStatus& certificate_response) { + // your code for cmd set_get_certificate_response goes here +} + +} // namespace extensions +} // namespace module diff --git a/modules/Evse15118D20/extensions/iso15118_extensionsImpl.hpp b/modules/Evse15118D20/extensions/iso15118_extensionsImpl.hpp new file mode 100644 index 000000000..730834c68 --- /dev/null +++ b/modules/Evse15118D20/extensions/iso15118_extensionsImpl.hpp @@ -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 + +#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& 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_charger::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& 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 diff --git a/modules/Evse15118D20/manifest.yaml b/modules/Evse15118D20/manifest.yaml index e8d089f8d..7781c4944 100644 --- a/modules/Evse15118D20/manifest.yaml +++ b/modules/Evse15118D20/manifest.yaml @@ -58,6 +58,11 @@ provides: 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 diff --git a/modules/EvseManager/EvseManager.cpp b/modules/EvseManager/EvseManager.cpp index 46b79f8ce..f485934e5 100644 --- a/modules/EvseManager/EvseManager.cpp +++ b/modules/EvseManager/EvseManager.cpp @@ -683,10 +683,6 @@ void EvseManager::ready() { switch_AC_mode(); }); } - - r_hlc[0]->subscribe_certificate_request([this](types::iso15118_charger::RequestExiStreamSchema request) { - p_evse->publish_iso15118_certificate_request(request); - }); } bsp->signal_event.connect([this](const CPEvent event) { diff --git a/modules/EvseManager/evse/evse_managerImpl.cpp b/modules/EvseManager/evse/evse_managerImpl.cpp index e1ba78a83..28eeae655 100644 --- a/modules/EvseManager/evse/evse_managerImpl.cpp +++ b/modules/EvseManager/evse/evse_managerImpl.cpp @@ -448,11 +448,6 @@ bool evse_managerImpl::handle_stop_transaction(types::evse_manager::StopTransact return mod->charger->cancel_transaction(request); }; -void evse_managerImpl::handle_set_get_certificate_response( - types::iso15118_charger::ResponseExiStreamStatus& certificate_reponse) { - mod->r_hlc[0]->call_certificate_response(certificate_reponse); -} - bool evse_managerImpl::handle_external_ready_to_start_charging() { if (mod->config.external_ready_to_start_charging) { EVLOG_info << "Received external ready to start charging command."; diff --git a/modules/EvseManager/evse/evse_managerImpl.hpp b/modules/EvseManager/evse/evse_managerImpl.hpp index e316dd5d2..c45c76947 100644 --- a/modules/EvseManager/evse/evse_managerImpl.hpp +++ b/modules/EvseManager/evse/evse_managerImpl.hpp @@ -48,8 +48,6 @@ class evse_managerImpl : public evse_managerImplBase { virtual bool handle_resume_charging() override; virtual bool handle_stop_transaction(types::evse_manager::StopTransactionRequest& request) override; virtual bool handle_force_unlock(int& connector_id) override; - virtual void handle_set_get_certificate_response( - types::iso15118_charger::ResponseExiStreamStatus& certificate_response) override; virtual bool handle_external_ready_to_start_charging() override; // ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1 diff --git a/modules/EvseManager/tests/EvseManagerStub.hpp b/modules/EvseManager/tests/EvseManagerStub.hpp index 1dee11214..b8148b7be 100644 --- a/modules/EvseManager/tests/EvseManagerStub.hpp +++ b/modules/EvseManager/tests/EvseManagerStub.hpp @@ -59,9 +59,6 @@ struct evse_managerImplStub : public evse_managerImplBase { handle_switch_three_phases_while_charging(bool& three_phases) { return types::evse_manager::SwitchThreePhasesWhileChargingResult::Success; } - virtual void - handle_set_get_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& certificate_response) { - } virtual bool handle_external_ready_to_start_charging() { return true; } diff --git a/modules/EvseV2G/CMakeLists.txt b/modules/EvseV2G/CMakeLists.txt index af18dc458..3cf296421 100644 --- a/modules/EvseV2G/CMakeLists.txt +++ b/modules/EvseV2G/CMakeLists.txt @@ -21,6 +21,7 @@ endif() target_sources(${MODULE_NAME} PRIVATE "charger/ISO15118_chargerImpl.cpp" + "extensions/iso15118_extensionsImpl.cpp" ) # ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 diff --git a/modules/EvseV2G/EvseV2G.cpp b/modules/EvseV2G/EvseV2G.cpp index be9d2f70e..bdbb5a1aa 100644 --- a/modules/EvseV2G/EvseV2G.cpp +++ b/modules/EvseV2G/EvseV2G.cpp @@ -37,7 +37,7 @@ namespace module { void EvseV2G::init() { /* create v2g context */ - v2g_ctx = v2g_ctx_create(&(*p_charger), &(*r_security)); + v2g_ctx = v2g_ctx_create(&(*p_charger), &(*p_extensions), &(*r_security)); if (v2g_ctx == nullptr) return; @@ -49,6 +49,7 @@ void EvseV2G::init() { #endif // EVEREST_MBED_TLS invoke_init(*p_charger); + invoke_init(*p_extensions); } void EvseV2G::ready() { @@ -79,6 +80,7 @@ void EvseV2G::ready() { } invoke_ready(*p_charger); + invoke_ready(*p_extensions); rv = sdp_listen(v2g_ctx); diff --git a/modules/EvseV2G/EvseV2G.hpp b/modules/EvseV2G/EvseV2G.hpp index c1a497e0a..647255867 100644 --- a/modules/EvseV2G/EvseV2G.hpp +++ b/modules/EvseV2G/EvseV2G.hpp @@ -12,6 +12,7 @@ // headers for provided interface implementations #include +#include // headers for required interface implementations #include @@ -45,16 +46,19 @@ class EvseV2G : public Everest::ModuleBase { public: EvseV2G() = delete; EvseV2G(const ModuleInfo& info, Everest::MqttProvider& mqtt_provider, - std::unique_ptr p_charger, std::unique_ptr r_security, + std::unique_ptr p_charger, + std::unique_ptr p_extensions, std::unique_ptr r_security, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), p_charger(std::move(p_charger)), + p_extensions(std::move(p_extensions)), r_security(std::move(r_security)), config(config){}; Everest::MqttProvider& mqtt; const std::unique_ptr p_charger; + const std::unique_ptr p_extensions; const std::unique_ptr r_security; const Conf& config; diff --git a/modules/EvseV2G/charger/ISO15118_chargerImpl.cpp b/modules/EvseV2G/charger/ISO15118_chargerImpl.cpp index a1ca76375..6d48c279a 100644 --- a/modules/EvseV2G/charger/ISO15118_chargerImpl.cpp +++ b/modules/EvseV2G/charger/ISO15118_chargerImpl.cpp @@ -210,19 +210,6 @@ void ISO15118_chargerImpl::handle_session_setup(std::vectormqtt_lock); - if (exi_stream_status.exi_response.has_value() and not exi_stream_status.exi_response.value().empty()) { - v2g_ctx->evse_v2g_data.cert_install_res_b64_buffer = std::string(exi_stream_status.exi_response.value()); - } - v2g_ctx->evse_v2g_data.cert_install_status = - (exi_stream_status.status == types::iso15118_charger::Status::Accepted) ? true : false; - pthread_cond_signal(&v2g_ctx->mqtt_cond); - /* unlock */ - pthread_mutex_unlock(&v2g_ctx->mqtt_lock); -} - void ISO15118_chargerImpl::handle_authorization_response( types::authorization::AuthorizationStatus& authorization_status, types::authorization::CertificateStatus& certificate_status) { diff --git a/modules/EvseV2G/charger/ISO15118_chargerImpl.hpp b/modules/EvseV2G/charger/ISO15118_chargerImpl.hpp index f08233d73..5f7ce5109 100644 --- a/modules/EvseV2G/charger/ISO15118_chargerImpl.hpp +++ b/modules/EvseV2G/charger/ISO15118_chargerImpl.hpp @@ -41,8 +41,6 @@ class ISO15118_chargerImpl : public ISO15118_chargerImplBase { virtual void handle_set_charging_parameters(types::iso15118_charger::SetupPhysicalValues& physical_values) override; virtual void handle_session_setup(std::vector& payment_options, bool& supported_certificate_service) override; - virtual void - handle_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& exi_stream_status) 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; diff --git a/modules/EvseV2G/extensions/iso15118_extensionsImpl.cpp b/modules/EvseV2G/extensions/iso15118_extensionsImpl.cpp new file mode 100644 index 000000000..819f31642 --- /dev/null +++ b/modules/EvseV2G/extensions/iso15118_extensionsImpl.cpp @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Pionix GmbH and Contributors to EVerest +#include "iso15118_extensionsImpl.hpp" +#include "log.hpp" +#include "v2g_ctx.hpp" + +namespace module { +namespace extensions { + +void iso15118_extensionsImpl::init() { + if (!v2g_ctx) { + dlog(DLOG_LEVEL_ERROR, "v2g_ctx not created"); + return; + } +} + +void iso15118_extensionsImpl::ready() { +} + +void iso15118_extensionsImpl::handle_set_get_certificate_response( + types::iso15118_charger::ResponseExiStreamStatus& certificate_response) { + pthread_mutex_lock(&v2g_ctx->mqtt_lock); + if (certificate_response.exi_response.has_value() and not certificate_response.exi_response.value().empty()) { + v2g_ctx->evse_v2g_data.cert_install_res_b64_buffer = std::string(certificate_response.exi_response.value()); + } + v2g_ctx->evse_v2g_data.cert_install_status = + (certificate_response.status == types::iso15118_charger::Status::Accepted) ? true : false; + pthread_cond_signal(&v2g_ctx->mqtt_cond); + /* unlock */ + pthread_mutex_unlock(&v2g_ctx->mqtt_lock); +} + +} // namespace extensions +} // namespace module diff --git a/modules/EvseV2G/extensions/iso15118_extensionsImpl.hpp b/modules/EvseV2G/extensions/iso15118_extensionsImpl.hpp new file mode 100644 index 000000000..5b09cd1a1 --- /dev/null +++ b/modules/EvseV2G/extensions/iso15118_extensionsImpl.hpp @@ -0,0 +1,63 @@ +// 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 + +#include "EvseV2G.hpp" + +// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 +#include "v2g.hpp" +extern struct v2g_context* v2g_ctx; +// 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& 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_charger::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& 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 diff --git a/modules/EvseV2G/iso_server.cpp b/modules/EvseV2G/iso_server.cpp index 21babf8b4..210bee318 100644 --- a/modules/EvseV2G/iso_server.cpp +++ b/modules/EvseV2G/iso_server.cpp @@ -493,7 +493,7 @@ static bool publish_iso_certificate_installation_exi_req(struct v2g_context* ctx certificate_request.iso15118_schema_version = ISO_15118_2013_MSG_DEF; certificate_request.certificate_action = types::iso15118_charger::CertificateActionEnum::Install; - ctx->p_charger->publish_certificate_request(certificate_request); + ctx->p_extensions->publish_iso15118_certificate_request(certificate_request); #ifdef EVEREST_MBED_TLS exit: diff --git a/modules/EvseV2G/manifest.yaml b/modules/EvseV2G/manifest.yaml index cf842ea54..12be984de 100644 --- a/modules/EvseV2G/manifest.yaml +++ b/modules/EvseV2G/manifest.yaml @@ -81,6 +81,11 @@ provides: description: >- This module implements the ISO15118-2 implementation of an AC or DC charger + 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 @@ -91,3 +96,4 @@ metadata: authors: - Fabian Hartung - Mohannad Oraby + - Sebastian Lukas diff --git a/modules/EvseV2G/tests/ISO15118_chargerImplStub.hpp b/modules/EvseV2G/tests/ISO15118_chargerImplStub.hpp index 6093cc446..3a097d045 100644 --- a/modules/EvseV2G/tests/ISO15118_chargerImplStub.hpp +++ b/modules/EvseV2G/tests/ISO15118_chargerImplStub.hpp @@ -36,9 +36,6 @@ struct ISO15118_chargerImplStub : public ISO15118_chargerImplBase { bool& supported_certificate_service) { std::cout << "ISO15118_chargerImplBase::handle_session_setup called" << std::endl; } - virtual void handle_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& exi_stream_status) { - std::cout << "ISO15118_chargerImplBase::handle_certificate_response called" << std::endl; - } virtual void handle_authorization_response(types::authorization::AuthorizationStatus& authorization_status, types::authorization::CertificateStatus& certificate_status) { std::cout << "ISO15118_chargerImplBase::handle_authorization_response called" << std::endl; diff --git a/modules/EvseV2G/tests/iso15118_extensionsImplStub.hpp b/modules/EvseV2G/tests/iso15118_extensionsImplStub.hpp new file mode 100644 index 000000000..2e1a8abb1 --- /dev/null +++ b/modules/EvseV2G/tests/iso15118_extensionsImplStub.hpp @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Pionix GmbH and Contributors to EVerest + +#ifndef ISO15118_EXTENTSIONSIMPLSTUB_H +#define ISO15118_EXTENTSIONSIMPLSTUB_H + +#include + +#include + +//----------------------------------------------------------------------------- +namespace module::stub { + +class iso15118_extensionsImplStub : public iso15118_extensionsImplBase { +public: + iso15118_extensionsImplStub() : iso15118_extensionsImplBase(nullptr, "EvseV2G"){}; + + virtual void init() { + } + virtual void ready() { + } + + virtual void + handle_set_get_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& certificate_response) { + std::cout << "iso15118_extensionsImplBase::handle_set_get_certificate_response called" << std::endl; + } +}; + +} // namespace module::stub + +#endif // ISO15118_EXTENTSIONSIMPLSTUB_H diff --git a/modules/EvseV2G/tests/v2g_ctx_test.cpp b/modules/EvseV2G/tests/v2g_ctx_test.cpp index 3d190d85b..e64e5b407 100644 --- a/modules/EvseV2G/tests/v2g_ctx_test.cpp +++ b/modules/EvseV2G/tests/v2g_ctx_test.cpp @@ -6,6 +6,7 @@ #include "ISO15118_chargerImplStub.hpp" #include "ModuleAdapterStub.hpp" #include "evse_securityIntfStub.hpp" +#include "iso15118_extensionsImplStub.hpp" #include "utest_log.hpp" #include "v2g.hpp" @@ -25,6 +26,7 @@ class V2gCtxTest : public testing::Test { module::stub::QuietModuleAdapterStub adapter; module::stub::ISO15118_chargerImplStub charger; module::stub::evse_securityIntfStub security; + module::stub::iso15118_extensionsImplStub extensions; V2gCtxTest() : charger(adapter), security(adapter) { } @@ -59,7 +61,7 @@ class V2gCtxTest : public testing::Test { } void SetUp() override { - auto ptr = v2g_ctx_create(&charger, &security); + auto ptr = v2g_ctx_create(&charger, &extensions, &security); ctx = std::unique_ptr(ptr, v2g_contextDeleter()); module::stub::clear_logs(); } @@ -162,7 +164,8 @@ TEST(valgrind, memcheck) { module::stub::QuietModuleAdapterStub adapter; module::stub::ISO15118_chargerImplStub charger(adapter); module::stub::evse_securityIntfStub security(adapter); - auto ptr = v2g_ctx_create(&charger, &security); + module::stub::iso15118_extensionsImplStub extensions; + auto ptr = v2g_ctx_create(&charger, &extensions, &security); v2g_ctx_free(ptr); } diff --git a/modules/EvseV2G/tests/v2g_main.cpp b/modules/EvseV2G/tests/v2g_main.cpp index b9312df5d..cbaa120d9 100644 --- a/modules/EvseV2G/tests/v2g_main.cpp +++ b/modules/EvseV2G/tests/v2g_main.cpp @@ -20,6 +20,7 @@ #include "ISO15118_chargerImplStub.hpp" #include "ModuleAdapterStub.hpp" #include "evse_securityIntfStub.hpp" +#include "iso15118_extensionsImplStub.hpp" #include #include @@ -126,8 +127,10 @@ int main(int argc, char** argv) { module::stub::ModuleAdapterStub adapter; module::stub::ISO15118_chargerImplStub charger(adapter); EvseSecurity security(adapter); + module::stub::iso15118_extensionsImplStub extensions; + + auto* ctx = v2g_ctx_create(&charger, &extensions, &security); - auto* ctx = v2g_ctx_create(&charger, &security); if (ctx == nullptr) { std::cerr << "failed to create context" << std::endl; } else { diff --git a/modules/EvseV2G/v2g.hpp b/modules/EvseV2G/v2g.hpp index 9b69a0973..d01ae40c6 100644 --- a/modules/EvseV2G/v2g.hpp +++ b/modules/EvseV2G/v2g.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -188,6 +189,7 @@ struct v2g_context { evse_securityIntf* r_security; ISO15118_chargerImplBase* p_charger; + iso15118_extensionsImplBase* p_extensions; struct event_base* event_base; pthread_t event_thread; diff --git a/modules/EvseV2G/v2g_ctx.cpp b/modules/EvseV2G/v2g_ctx.cpp index 3d9c89c0d..e160859bf 100644 --- a/modules/EvseV2G/v2g_ctx.cpp +++ b/modules/EvseV2G/v2g_ctx.cpp @@ -292,7 +292,8 @@ void v2g_ctx_init_charging_values(struct v2g_context* const ctx) { initialize_once = true; } -struct v2g_context* v2g_ctx_create(ISO15118_chargerImplBase* p_chargerImplBase, evse_securityIntf* r_security) { +struct v2g_context* v2g_ctx_create(ISO15118_chargerImplBase* p_chargerImplBase, + iso15118_extensionsImplBase* p_extensions, evse_securityIntf* r_security) { struct v2g_context* ctx; // TODO There are c++ objects within v2g_context and calloc doesn't call initialisers. @@ -303,6 +304,7 @@ struct v2g_context* v2g_ctx_create(ISO15118_chargerImplBase* p_chargerImplBase, ctx->r_security = r_security; ctx->p_charger = p_chargerImplBase; + ctx->p_extensions = p_extensions; ctx->tls_security = TLS_SECURITY_PROHIBIT; // default diff --git a/modules/EvseV2G/v2g_ctx.hpp b/modules/EvseV2G/v2g_ctx.hpp index 09bd2127b..8bb0b92d9 100644 --- a/modules/EvseV2G/v2g_ctx.hpp +++ b/modules/EvseV2G/v2g_ctx.hpp @@ -17,7 +17,8 @@ static const char* selected_energy_transfer_mode_string[] = { "AC_single_phase_core", "AC_three_phase_core", "DC_core", "DC_extended", "DC_combo_core", "DC_unique", }; -struct v2g_context* v2g_ctx_create(ISO15118_chargerImplBase* p_chargerImplBase, evse_securityIntf* r_security); +struct v2g_context* v2g_ctx_create(ISO15118_chargerImplBase* p_chargerImplBase, + iso15118_extensionsImplBase* p_extensions, evse_securityIntf* r_security); /*! * \brief v2g_ctx_init_charging_session This funcion inits a charging session. diff --git a/modules/IsoMux/CMakeLists.txt b/modules/IsoMux/CMakeLists.txt index 3bae2eb4b..ddb9adc86 100644 --- a/modules/IsoMux/CMakeLists.txt +++ b/modules/IsoMux/CMakeLists.txt @@ -14,6 +14,7 @@ ev_setup_cpp_module() target_sources(${MODULE_NAME} PRIVATE "charger/ISO15118_chargerImpl.cpp" + "extensions/iso15118_extensionsImpl.cpp" ) # ev@c55432ab-152c-45a9-9d2e-7281d50c69c3:v1 diff --git a/modules/IsoMux/IsoMux.cpp b/modules/IsoMux/IsoMux.cpp index f9a4669e7..9e2e5c224 100644 --- a/modules/IsoMux/IsoMux.cpp +++ b/modules/IsoMux/IsoMux.cpp @@ -48,6 +48,7 @@ void IsoMux::init() { v2g_ctx->tls_server = &tls_server; invoke_init(*p_charger); + invoke_init(*p_extensions); } void IsoMux::ready() { @@ -76,6 +77,7 @@ void IsoMux::ready() { } invoke_ready(*p_charger); + invoke_ready(*p_extensions); rv = sdp_listen(v2g_ctx); diff --git a/modules/IsoMux/IsoMux.hpp b/modules/IsoMux/IsoMux.hpp index 02acb8fd0..01e28cead 100644 --- a/modules/IsoMux/IsoMux.hpp +++ b/modules/IsoMux/IsoMux.hpp @@ -12,10 +12,12 @@ // headers for provided interface implementations #include +#include // headers for required interface implementations #include #include +#include // ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 // insert your custom include headers here @@ -38,19 +40,27 @@ class IsoMux : public Everest::ModuleBase { public: IsoMux() = delete; IsoMux(const ModuleInfo& info, std::unique_ptr p_charger, - std::unique_ptr r_security, std::unique_ptr r_iso2, - std::unique_ptr r_iso20, Conf& config) : + std::unique_ptr p_extensions, std::unique_ptr r_security, + std::unique_ptr r_iso2, std::unique_ptr r_iso20, + std::unique_ptr r_ext2, std::unique_ptr r_ext20, + Conf& config) : ModuleBase(info), p_charger(std::move(p_charger)), + p_extensions(std::move(p_extensions)), r_security(std::move(r_security)), r_iso2(std::move(r_iso2)), r_iso20(std::move(r_iso20)), + r_ext2(std::move(r_ext2)), + r_ext20(std::move(r_ext20)), config(config){}; const std::unique_ptr p_charger; + const std::unique_ptr p_extensions; const std::unique_ptr r_security; const std::unique_ptr r_iso2; const std::unique_ptr r_iso20; + const std::unique_ptr r_ext2; + const std::unique_ptr r_ext20; const Conf& config; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 diff --git a/modules/IsoMux/charger/ISO15118_chargerImpl.cpp b/modules/IsoMux/charger/ISO15118_chargerImpl.cpp index 53a045b7c..93c4a8a8c 100644 --- a/modules/IsoMux/charger/ISO15118_chargerImpl.cpp +++ b/modules/IsoMux/charger/ISO15118_chargerImpl.cpp @@ -348,17 +348,6 @@ void ISO15118_chargerImpl::init() { } }); - mod->r_iso2->subscribe_certificate_request([this](const auto o) { - if (not mod->selected_iso20()) { - publish_certificate_request(o); - } - }); - mod->r_iso20->subscribe_certificate_request([this](const auto o) { - if (mod->selected_iso20()) { - publish_certificate_request(o); - } - }); - mod->r_iso2->subscribe_dlink_terminate([this]() { if (not mod->selected_iso20()) { publish_dlink_terminate(nullptr); @@ -490,15 +479,6 @@ void ISO15118_chargerImpl::handle_session_setup(std::vectorr_iso2->call_session_setup(payment_options, supported_certificate_service); } -void ISO15118_chargerImpl::handle_certificate_response( - types::iso15118_charger::ResponseExiStreamStatus& exi_stream_status) { - if (mod->selected_iso20()) { - mod->r_iso20->call_certificate_response(exi_stream_status); - } else { - mod->r_iso2->call_certificate_response(exi_stream_status); - } -} - void ISO15118_chargerImpl::handle_authorization_response( types::authorization::AuthorizationStatus& authorization_status, types::authorization::CertificateStatus& certificate_status) { diff --git a/modules/IsoMux/charger/ISO15118_chargerImpl.hpp b/modules/IsoMux/charger/ISO15118_chargerImpl.hpp index a512ed491..0d3c73770 100644 --- a/modules/IsoMux/charger/ISO15118_chargerImpl.hpp +++ b/modules/IsoMux/charger/ISO15118_chargerImpl.hpp @@ -41,8 +41,6 @@ class ISO15118_chargerImpl : public ISO15118_chargerImplBase { virtual void handle_set_charging_parameters(types::iso15118_charger::SetupPhysicalValues& physical_values) override; virtual void handle_session_setup(std::vector& payment_options, bool& supported_certificate_service) override; - virtual void - handle_certificate_response(types::iso15118_charger::ResponseExiStreamStatus& exi_stream_status) 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; diff --git a/modules/IsoMux/extensions/iso15118_extensionsImpl.cpp b/modules/IsoMux/extensions/iso15118_extensionsImpl.cpp new file mode 100644 index 000000000..7e32f7f6d --- /dev/null +++ b/modules/IsoMux/extensions/iso15118_extensionsImpl.cpp @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Pionix GmbH and Contributors to EVerest + +#include "iso15118_extensionsImpl.hpp" +#include "log.hpp" + +namespace module { +namespace extensions { + +void iso15118_extensionsImpl::init() { + if (!v2g_ctx) { + dlog(DLOG_LEVEL_ERROR, "v2g_ctx not created"); + return; + } + + mod->r_ext2->subscribe_iso15118_certificate_request([this](const auto o) { + if (not mod->selected_iso20()) { + publish_iso15118_certificate_request(o); + } + }); + + mod->r_ext20->subscribe_iso15118_certificate_request([this](const auto o) { + if (mod->selected_iso20()) { + publish_iso15118_certificate_request(o); + } + }); +} + +void iso15118_extensionsImpl::ready() { +} + +void iso15118_extensionsImpl::handle_set_get_certificate_response( + types::iso15118_charger::ResponseExiStreamStatus& certificate_response) { + if (mod->selected_iso20()) { + mod->r_ext20->call_set_get_certificate_response(certificate_response); + } else { + mod->r_ext20->call_set_get_certificate_response(certificate_response); + } +} + +} // namespace extensions +} // namespace module diff --git a/modules/IsoMux/extensions/iso15118_extensionsImpl.hpp b/modules/IsoMux/extensions/iso15118_extensionsImpl.hpp new file mode 100644 index 000000000..63b3113f1 --- /dev/null +++ b/modules/IsoMux/extensions/iso15118_extensionsImpl.hpp @@ -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 + +#include "IsoMux.hpp" + +// ev@75ac1216-19eb-4182-a85c-820f1fc2c091:v1 +extern struct v2g_context* v2g_ctx; +// 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& 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_charger::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& 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 diff --git a/modules/IsoMux/manifest.yaml b/modules/IsoMux/manifest.yaml index 3904f5c69..bb77f0243 100644 --- a/modules/IsoMux/manifest.yaml +++ b/modules/IsoMux/manifest.yaml @@ -45,6 +45,11 @@ provides: description: >- This module implements the ISO15118-2 implementation of an AC or DC charger + 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 @@ -52,6 +57,10 @@ requires: interface: ISO15118_charger iso20: interface: ISO15118_charger + ext2: + interface: iso15118_extensions + ext20: + interface: iso15118_extensions metadata: license: https://opensource.org/licenses/Apache-2.0 authors: diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index b9d8d6d9c..dd3300b7d 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -303,15 +303,18 @@ void OCPP::init_evse_subscriptions() { this->process_session_event(evse_id, session_event); }); + evse_id++; + } - evse->subscribe_iso15118_certificate_request( - [this, evse_id](types::iso15118_charger::RequestExiStreamSchema request) { + int32_t extensions_id = 1; + for (auto& extension : this->r_extensions_15118) { + extension->subscribe_iso15118_certificate_request( + [this, extensions_id](types::iso15118_charger::RequestExiStreamSchema request) { this->charge_point->data_transfer_pnc_get_15118_ev_certificate( - evse_id, request.exi_request, request.iso15118_schema_version, + extensions_id, request.exi_request, request.iso15118_schema_version, conversions::to_ocpp_certificate_action_enum(request.certificate_action)); }); - - evse_id++; + extensions_id++; } } @@ -790,8 +793,7 @@ void OCPP::ready() { response.exi_response.emplace(certificate_response.exiResponse.get()); } - this->r_evse_manager.at(this->connector_evse_index_map.at(connector_id)) - ->call_set_get_certificate_response(response); + this->r_extensions_15118.at(connector_id - 1)->call_set_get_certificate_response(response); }); this->charge_point->register_security_event_callback([this](const std::string& type, const std::string& tech_info) { diff --git a/modules/OCPP/OCPP.hpp b/modules/OCPP/OCPP.hpp index 05df5f132..3022d9004 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -80,7 +81,8 @@ class OCPP : public Everest::ModuleBase { std::unique_ptr r_reservation, std::unique_ptr r_auth, std::unique_ptr r_system, std::unique_ptr r_security, std::vector> r_data_transfer, - std::vector> r_display_message, Conf& config) : + std::vector> r_display_message, + std::vector> r_extensions_15118, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), p_main(std::move(p_main)), @@ -97,8 +99,8 @@ class OCPP : public Everest::ModuleBase { r_security(std::move(r_security)), r_data_transfer(std::move(r_data_transfer)), r_display_message(std::move(r_display_message)), - config(config) { - } + r_extensions_15118(std::move(r_extensions_15118)), + config(config){}; Everest::MqttProvider& mqtt; const std::unique_ptr p_main; @@ -115,6 +117,7 @@ class OCPP : public Everest::ModuleBase { const std::unique_ptr r_security; const std::vector> r_data_transfer; const std::vector> r_display_message; + const std::vector> r_extensions_15118; const Conf& config; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 diff --git a/modules/OCPP/doc.rst b/modules/OCPP/doc.rst index aa038523e..0c1bc5612 100644 --- a/modules/OCPP/doc.rst +++ b/modules/OCPP/doc.rst @@ -112,8 +112,6 @@ This module makes use of the following commands of this interface: publishes the result via the `Provides: ocpp_generic <#provides-ocpp_generic>`_ interface. 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. -* **set_get_certificate_response** to report that the charging station received a **DataTransfer.conf(Get15118EVCertificateResponse)** from - the CSMS (EV Contract installation for Plug&Charge) * **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: @@ -124,7 +122,6 @@ The interface is used to receive the following variables: * **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. -* **iso15118_certificate_request** to trigger a **DataTransfer.req(Get15118EVCertificateRequest)** as part of the Plug&Charge process * **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 @@ -264,6 +261,23 @@ 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 **DataTransfer.req(SetUserPrice)** message to the charging station. +Requires: extensions_15118 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Interface**: `iso15118_extensions <../../interfaces/iso15118_extensions.yaml>`_ + +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 --------------------------------- diff --git a/modules/OCPP/manifest.yaml b/modules/OCPP/manifest.yaml index 46fbbac5c..55bfd18b8 100644 --- a/modules/OCPP/manifest.yaml +++ b/modules/OCPP/manifest.yaml @@ -105,6 +105,10 @@ requires: 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: diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index 0f63b9f65..3cd0a7d7f 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -838,8 +838,24 @@ void OCPP201::ready() { } }); - evse->subscribe_iso15118_certificate_request( - [this, evse_id](const types::iso15118_charger::RequestExiStreamSchema& certificate_request) { + auto fault_handler = [this, evse_id](const Everest::error::Error& error) { + this->charge_point->on_faulted(evse_id, get_connector_id_from_error(error)); + }; + + auto fault_cleared_handler = [this, evse_id](const Everest::error::Error& error) { + this->charge_point->on_fault_cleared(evse_id, get_connector_id_from_error(error)); + }; + + // A permanent fault from the evse requirement indicates that the evse should move to faulted state + evse->subscribe_error(EVSE_MANAGER_INOPERATIVE_ERROR, fault_handler, fault_cleared_handler); + + evse_id++; + } + + int32_t extensions_id = 0; + for (auto& extension : this->r_extensions_15118) { + extension->subscribe_iso15118_certificate_request( + [this, extensions_id](const types::iso15118_charger::RequestExiStreamSchema& certificate_request) { auto ocpp_response = this->charge_point->on_get_15118_ev_certificate_request( conversions::to_ocpp_get_15118_certificate_request(certificate_request)); EVLOG_debug << "Received response from get_15118_ev_certificate_request: " << ocpp_response; @@ -851,22 +867,13 @@ void OCPP201::ready() { // since exi_response is an optional in the EVerest type we only set it when not empty everest_response.exi_response = ocpp_response.exiResponse.get(); } - this->r_evse_manager.at(evse_id - 1)->call_set_get_certificate_response(everest_response); - }); - - auto fault_handler = [this, evse_id](const Everest::error::Error& error) { - this->charge_point->on_faulted(evse_id, get_connector_id_from_error(error)); - }; - - auto fault_cleared_handler = [this, evse_id](const Everest::error::Error& error) { - this->charge_point->on_fault_cleared(evse_id, get_connector_id_from_error(error)); - }; - // A permanent fault from the evse requirement indicates that the evse should move to faulted state - evse->subscribe_error(EVSE_MANAGER_INOPERATIVE_ERROR, fault_handler, fault_cleared_handler); + this->r_extensions_15118.at(extensions_id)->call_set_get_certificate_response(everest_response); + }); - evse_id++; + extensions_id++; } + r_system->subscribe_firmware_update_status([this](const types::system::FirmwareUpdateStatus status) { this->charge_point->on_firmware_update_status_notification( status.request_id, conversions::to_ocpp_firmware_status_enum(status.firmware_update_status)); diff --git a/modules/OCPP201/OCPP201.hpp b/modules/OCPP201/OCPP201.hpp index 42ef16113..8d3c57a41 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -63,7 +64,8 @@ class OCPP201 : public Everest::ModuleBase { std::vector> r_data_transfer, std::unique_ptr r_auth, std::vector> r_evse_energy_sink, std::vector> r_display_message, - std::vector> r_reservation, Conf& config) : + std::vector> r_reservation, + std::vector> r_extensions_15118, Conf& config) : ModuleBase(info), mqtt(mqtt_provider), p_auth_validator(std::move(p_auth_validator)), @@ -79,8 +81,8 @@ class OCPP201 : public Everest::ModuleBase { r_evse_energy_sink(std::move(r_evse_energy_sink)), r_display_message(std::move(r_display_message)), r_reservation(std::move(r_reservation)), - config(config) { - } + r_extensions_15118(std::move(r_extensions_15118)), + config(config){}; Everest::MqttProvider& mqtt; const std::unique_ptr p_auth_validator; @@ -96,6 +98,7 @@ class OCPP201 : public Everest::ModuleBase { const std::vector> r_evse_energy_sink; const std::vector> r_display_message; const std::vector> r_reservation; + const std::vector> r_extensions_15118; const Conf& config; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 diff --git a/modules/OCPP201/doc.rst b/modules/OCPP201/doc.rst index 4aec54fdc..73c86a634 100644 --- a/modules/OCPP201/doc.rst +++ b/modules/OCPP201/doc.rst @@ -113,8 +113,6 @@ This module makes use of the following commands of this interface: **PublishChargingScheduleDurationS** of this module. The configuration parameter **PublishChargingScheduleIntervalS** defines the interval to use to periodically retrieve and publish the composite schedules. The configuration parameter **RequestCompositeScheduleUnit** can be used to specify the unit in which composite schedules are requested and shared within EVerest. -* **set_get_certificate_response** to report that the charging station received a **Get15118EVCertificate.conf** from the CSMS (EV Contract installation -for Plug&Charge) The interface is used to receive the following variables: @@ -124,7 +122,6 @@ The interface is used to receive the following variables: * **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** and **TransactionEvent.req** based on the reported event. This signal drives the state machine and the transaction handling of libocpp. -* **iso15118_certificate_request** to trigger a **DataTransfer.req(Get15118EVCertificateRequest)** as part of the Plug&Charge process * **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 @@ -247,6 +244,23 @@ This module makes use of the following commands of this interface: * **get_display_messages** to forward a **GetDisplayMessage.req** from the CSMS * **clear_display_message** to forward a **ClearDisplayMessage.req** from the CSMS +Requires: extensions_15118 +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Interface**: `iso15118_extensions <../../interfaces/iso15118_extensions.yaml>`_ + +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 + Error Handling -------------- diff --git a/modules/OCPP201/manifest.yaml b/modules/OCPP201/manifest.yaml index 51df9abb6..60b44991a 100644 --- a/modules/OCPP201/manifest.yaml +++ b/modules/OCPP201/manifest.yaml @@ -102,6 +102,10 @@ requires: interface: reservation 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: diff --git a/tests/ocpp_tests/conftest.py b/tests/ocpp_tests/conftest.py index 53bce2875..882cf9818 100644 --- a/tests/ocpp_tests/conftest.py +++ b/tests/ocpp_tests/conftest.py @@ -191,7 +191,7 @@ def probe_module( implement_command( module, skip_implementation, - "ProbeModuleConnectorA", + "ProbeModuleIso15118Extensions", "set_get_certificate_response", lambda arg: None, ) @@ -279,13 +279,6 @@ def probe_module( "force_unlock", lambda arg: True, ) - implement_command( - module, - skip_implementation, - "ProbeModuleConnectorB", - "set_get_certificate_response", - lambda arg: None, - ) implement_command( module, skip_implementation, diff --git a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module-data-transfer.yaml b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module-data-transfer.yaml index b9b76933d..d5e904adf 100644 --- a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module-data-transfer.yaml +++ b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module-data-transfer.yaml @@ -21,5 +21,8 @@ active_modules: data_transfer: - module_id: probe implementation_id: ProbeModuleDataTransfer + extensions_15118: + - module_id: probe + implementation_id: ProbeModuleIso15118Extensions x-module-layout: {} diff --git a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module.yaml b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module.yaml index af26a4c7d..dc76f3e1c 100644 --- a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module.yaml +++ b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-ocpp201-probe-module.yaml @@ -18,6 +18,9 @@ active_modules: security: - module_id: probe implementation_id: ProbeModuleSecurity + extensions_15118: + - module_id: probe + implementation_id: ProbeModuleIso15118Extensions auth: module: Auth config_module: diff --git a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-sil-iso.yaml b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-sil-iso.yaml index d549654ef..7d43cd948 100644 --- a/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-sil-iso.yaml +++ b/tests/ocpp_tests/test_sets/everest-aux/config/everest-config-sil-iso.yaml @@ -105,6 +105,9 @@ active_modules: security: - module_id: evse_security implementation_id: main + extensions_15118: + - module_id: iso15118_charger + implementation_id: extensions evse_security: module: EvseSecurity config_module: diff --git a/tests/ocpp_tests/test_sets/ocpp16/ocpp_generic_interface_integration_tests.py b/tests/ocpp_tests/test_sets/ocpp16/ocpp_generic_interface_integration_tests.py index f78ab7757..6e523161e 100644 --- a/tests/ocpp_tests/test_sets/ocpp16/ocpp_generic_interface_integration_tests.py +++ b/tests/ocpp_tests/test_sets/ocpp16/ocpp_generic_interface_integration_tests.py @@ -95,9 +95,6 @@ def _add_pm_command_mock(implementation_id, command, value, skip_implementation) evse_manager, "stop_transaction", True, skip_implementation ) _add_pm_command_mock(evse_manager, "force_unlock", True, skip_implementation) - _add_pm_command_mock( - evse_manager, "set_get_certificate_response", None, skip_implementation - ) _add_pm_command_mock( evse_manager, "external_ready_to_start_charging", True, skip_implementation ) diff --git a/tests/ocpp_tests/test_sets/ocpp201/iso15118_certificate_management.py b/tests/ocpp_tests/test_sets/ocpp201/iso15118_certificate_management.py index bba8c593a..ec6d8dd96 100644 --- a/tests/ocpp_tests/test_sets/ocpp201/iso15118_certificate_management.py +++ b/tests/ocpp_tests/test_sets/ocpp201/iso15118_certificate_management.py @@ -155,8 +155,7 @@ class TestIso15118CertificateManagementOcppIntegration: "skip_implementation", [ { - "ProbeModuleConnectorA": ["set_get_certificate_response"], - "ProbeModuleConnectorB": ["set_get_certificate_response"], + "ProbeModuleIso15118Extensions": ["set_get_certificate_response"], } ], ) @@ -194,17 +193,15 @@ async def test_m1_m2_certificate_request_ev( Tests Error handling of M01 and M02 Tested requirements: M01.FR.01, MR02.FR.01 """ - connectors = ["ProbeModuleConnectorA", "ProbeModuleConnectorB"] mock_cmd_set_get_certificate_response = {} - for connector_id in connectors: - mock_cmd_set_get_certificate_response[connector_id] = Mock() - mock_cmd_set_get_certificate_response[connector_id].return_value = None - probe_module.implement_command( - connector_id, - "set_get_certificate_response", - mock_cmd_set_get_certificate_response[connector_id], - ) + mock_cmd_set_get_certificate_response["ProbeModuleIso15118Extensions"] = Mock() + mock_cmd_set_get_certificate_response["ProbeModuleIso15118Extensions"].return_value = None + probe_module.implement_command( + "ProbeModuleIso15118Extensions", + "set_get_certificate_response", + mock_cmd_set_get_certificate_response["ProbeModuleIso15118Extensions"], + ) # start and ready probe module EvseManagers and wait for libocpp to connect probe_module.start() @@ -213,74 +210,69 @@ async def test_m1_m2_certificate_request_ev( probe_module.publish_variable("ProbeModuleConnectorB", "ready", True) chargepoint_with_pm = await central_system.wait_for_chargepoint() - # Each connector sends an installation request - for connector_index, calling_connector_id in enumerate(connectors): - # Setup ChargePoint response + # Setup ChargePoint response - exi_response = f"mock exi response for {calling_connector_id}" + exi_response = f"mock exi response for ProbeModuleIso15118Extensions" - central_system.mock.on_get_15118_ev_certificate.side_effect = [ - call_result201.Get15118EVCertificatePayload( - status=response_status, exi_response=exi_response - ) - ] + central_system.mock.on_get_15118_ev_certificate.side_effect = [ + call_result201.Get15118EVCertificatePayload( + status=response_status, exi_response=exi_response + ) + ] - # Act: Publish Install Certificate requeset - mock_certificate_installation_req = base64.b64encode( - f"{calling_connector_id} mock Raw CertificateInstallationReq or CertificateUpdateReq message as exi stream".encode( - "utf-8" - ) - ).decode("utf-8") + # Act: Publish Install Certificate requeset + mock_certificate_installation_req = base64.b64encode( + f"ProbeModuleIso15118Extensions mock Raw CertificateInstallationReq or CertificateUpdateReq message as exi stream".encode( + "utf-8" + ) + ).decode("utf-8") - mock_iso15118_schema_version = f"{calling_connector_id} mock Schema Version" + mock_iso15118_schema_version = f"ProbeModuleIso15118Extensions mock Schema Version" - probe_module.publish_variable( - calling_connector_id, - "iso15118_certificate_request", - { - "exi_request": mock_certificate_installation_req, - "iso15118_schema_version": mock_iso15118_schema_version, - "certificate_action": action, - }, - ) + probe_module.publish_variable( + "ProbeModuleIso15118Extensions", + "iso15118_certificate_request", + { + "exi_request": mock_certificate_installation_req, + "iso15118_schema_version": mock_iso15118_schema_version, + "certificate_action": action, + }, + ) - # Verify: CSMS is called correctly - expected_cp_request = call201.Get15118EVCertificatePayload( - iso15118_schema_version=mock_iso15118_schema_version, - exi_request=mock_certificate_installation_req, - action=action, - ) + # Verify: CSMS is called correctly + expected_cp_request = call201.Get15118EVCertificatePayload( + iso15118_schema_version=mock_iso15118_schema_version, + exi_request=mock_certificate_installation_req, + action=action, + ) - assert await wait_for_and_validate( - test_utility, - chargepoint_with_pm, - exp_action="Get15118EVCertificate", - exp_payload=expected_cp_request, - ) + assert await wait_for_and_validate( + test_utility, + chargepoint_with_pm, + exp_action="Get15118EVCertificate", + exp_payload=expected_cp_request, + ) - # Verify: Certificate response forwarded to correct EVSE manager as commmand - called_mock = mock_cmd_set_get_certificate_response[calling_connector_id] - other_connector_id = connectors[(connector_index + 1) % len(connectors)] - uncalled_mock = mock_cmd_set_get_certificate_response[other_connector_id] + # Verify: Certificate response forwarded to correct EVSE manager as commmand + called_mock = mock_cmd_set_get_certificate_response["ProbeModuleIso15118Extensions"] - await asyncio.wait_for(await_mock_called(called_mock), 3) + await asyncio.wait_for(await_mock_called(called_mock), 3) - assert called_mock.mock_calls == [ - mock_call( - { - "certificate_response": { - "certificate_action": action, - "exi_response": exi_response, - "status": response_status, - } + assert called_mock.mock_calls == [ + mock_call( + { + "certificate_response": { + "certificate_action": action, + "exi_response": exi_response, + "status": response_status, } - ) - ] - assert uncalled_mock.mock_calls == [] + } + ) + ] - for mock in mock_cmd_set_get_certificate_response.values(): - mock.reset_mock() + for mock in mock_cmd_set_get_certificate_response.values(): + mock.reset_mock() # ************************************************************************************************ # Use Case M3: Install CA certificate in a Charging Station