From 10f1b87291db281559ebd70b9355306f3f2a5d22 Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Fri, 8 Nov 2024 11:53:35 +0100 Subject: [PATCH 01/15] Add autoconnect option to connectivity manager and charge_point Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 7 ++++--- include/ocpp/v201/connectivity_manager.hpp | 3 ++- lib/ocpp/v201/charge_point.cpp | 4 ++-- lib/ocpp/v201/connectivity_manager.cpp | 7 ++++++- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 11e971403..8988e1c94 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -99,8 +99,9 @@ class ChargePointInterface { virtual ~ChargePointInterface() = default; /// \brief Starts the ChargePoint, initializes and connects to the Websocket endpoint - /// \param bootreason Optional bootreason (default: PowerUp). - virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp) = 0; + /// \param bootreason Optional bootreason (default: PowerUp). + /// \param autoconnect Set to false if you only want to initialize and not connect yet and use connect_websocket() to actually connect + virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool autoconnect = true) = 0; /// \brief Stops the ChargePoint. Disconnects the websocket connection and stops MessageQueue and all timers virtual void stop() = 0; @@ -863,7 +864,7 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa ~ChargePoint(); - void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp) override; + void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool autoconnect = true) override; void stop() override; diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 03c45bc6f..1828ba7e2 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -109,8 +109,9 @@ class ConnectivityManager { bool is_websocket_connected(); /// \brief Start the connectivity manager + /// \param autoconnect Set to false if you only want to initialize and not connect yet and use connect() to connect /// - void start(); + void start(bool autoconnect = true); /// \brief Stop the connectivity manager /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 16c2465fc..770410f77 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -111,7 +111,7 @@ ChargePoint::~ChargePoint() { this->auth_cache_cleanup_thread.join(); } -void ChargePoint::start(BootReasonEnum bootreason) { +void ChargePoint::start(BootReasonEnum bootreason, bool autoconnect) { this->message_queue->start(); this->bootreason = bootreason; @@ -123,7 +123,7 @@ void ChargePoint::start(BootReasonEnum bootreason) { this->boot_notification_req(bootreason); // call clear_invalid_charging_profiles when system boots this->clear_invalid_charging_profiles(); - this->connectivity_manager->start(); + this->connectivity_manager->start(autoconnect); const std::string firmware_version = this->device_model->get_value(ControllerComponentVariables::FirmwareVersion); diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index a35f7965f..345728a24 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -103,7 +103,12 @@ bool ConnectivityManager::is_websocket_connected() { return this->websocket != nullptr && this->websocket->is_connected(); } -void ConnectivityManager::start() { +void ConnectivityManager::start(bool autoconnect) { + if (!autoconnect) { + // Only cache the network profiles, starting the websocket is done by calling connect() later + this->cache_network_connection_profiles(); + return; + } init_websocket(); if (websocket != nullptr) { this->disable_automatic_websocket_reconnects = false; From be1caa980ab1d53e4df1ec2b0937283b26dfa5ba Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Fri, 8 Nov 2024 13:15:15 +0100 Subject: [PATCH 02/15] Refactor init_websocket logic Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 3 +- include/ocpp/v201/connectivity_manager.hpp | 2 +- lib/ocpp/v201/connectivity_manager.cpp | 33 ++++++++++++++-------- 3 files changed, 25 insertions(+), 13 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 8988e1c94..49443008b 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -100,7 +100,8 @@ class ChargePointInterface { /// \brief Starts the ChargePoint, initializes and connects to the Websocket endpoint /// \param bootreason Optional bootreason (default: PowerUp). - /// \param autoconnect Set to false if you only want to initialize and not connect yet and use connect_websocket() to actually connect + /// \param autoconnect Set to false if you only want to initialize and not connect yet and use connect_websocket() + /// to actually connect virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool autoconnect = true) = 0; /// \brief Stops the ChargePoint. Disconnects the websocket connection and stops MessageQueue and all timers diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 1828ba7e2..2bf9dcf24 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -161,7 +161,7 @@ class ConnectivityManager { private: /// \brief Init the websocket /// - void init_websocket(); + bool init_websocket(); /// \brief Get the current websocket connection options /// \returns the current websocket connection options diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 345728a24..529aef85a 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -109,27 +109,27 @@ void ConnectivityManager::start(bool autoconnect) { this->cache_network_connection_profiles(); return; } - init_websocket(); - if (websocket != nullptr) { + if (init_websocket() && websocket != nullptr) { this->disable_automatic_websocket_reconnects = false; websocket->connect(); } } void ConnectivityManager::stop() { - this->websocket_timer.stop(); disconnect_websocket(WebsocketCloseReason::Normal); } void ConnectivityManager::connect() { if (this->websocket != nullptr and !this->websocket->is_connected()) { this->disable_automatic_websocket_reconnects = false; - this->init_websocket(); - this->websocket->connect(); + if (this->init_websocket()) { + this->websocket->connect(); + } } } void ConnectivityManager::disconnect_websocket(WebsocketCloseReason code) { + this->websocket_timer.stop(); if (this->websocket != nullptr) { if (code != WebsocketCloseReason::ServiceRestart) { this->disable_automatic_websocket_reconnects = true; @@ -156,6 +156,7 @@ void ConnectivityManager::on_network_disconnected(int32_t configuration_slot) { } else if (configuration_slot == actual_configuration_slot) { // Since there is no connection anymore: disconnect the websocket, the manager will try to connect with the next // available network connection profile as we enable reconnects. + EVLOG_info << "ConnectivityManager::on_network_disconnected"; this->disconnect_websocket(ocpp::WebsocketCloseReason::GoingAway); this->disable_automatic_websocket_reconnects = false; } @@ -172,15 +173,16 @@ void ConnectivityManager::on_network_disconnected(OCPPInterfaceEnum ocpp_interfa } else if (ocpp_interface == network_connection_profile.value().ocppInterface) { // Since there is no connection anymore: disconnect the websocket, the manager will try to connect with the next // available network connection profile as we enable reconnects. + EVLOG_info << "ConnectivityManager::on_network_disconnected"; this->disconnect_websocket(ocpp::WebsocketCloseReason::GoingAway); this->disable_automatic_websocket_reconnects = false; } } bool ConnectivityManager::on_try_switch_network_connection_profile(const int32_t configuration_slot) { - if (!is_higher_priority_profile(configuration_slot)) { - return false; - } + // if (!is_higher_priority_profile(configuration_slot)) { + // return false; + // } EVLOG_info << "Trying to connect with higher priority network connection profile (configuration slots: " << this->get_active_network_configuration_slot() << " --> " << configuration_slot << ")."; @@ -197,7 +199,8 @@ bool ConnectivityManager::on_try_switch_network_connection_profile(const int32_t return true; } -void ConnectivityManager::init_websocket() { +bool ConnectivityManager::init_websocket() { + EVLOG_info << "ConnectivityManager::init_websocket()"; if (this->device_model.get_value(ControllerComponentVariables::ChargePointId).find(':') != std::string::npos) { EVLOG_AND_THROW(std::runtime_error("ChargePointId must not contain \':\'")); @@ -206,7 +209,7 @@ void ConnectivityManager::init_websocket() { // cache the network profiles on initialization if (!cache_network_connection_profiles()) { EVLOG_warning << "No network connection profiles configured, aborting websocket connection."; - return; + return false; } const int config_slot_int = this->get_active_network_configuration_slot(); @@ -253,13 +256,20 @@ void ConnectivityManager::init_websocket() { } if (!can_use_connection_profile) { + EVLOG_info << "websocket_timer set_timeout"; + if (this->disable_automatic_websocket_reconnects) { + return false; + } + this->websocket_timer.timeout( [this]() { + EVLOG_info << "websocket_timer.timeout 1"; this->next_network_configuration_priority(); this->start(); }, WEBSOCKET_INIT_DELAY); - return; + + return true; } EVLOG_info << "Open websocket with NetworkConfigurationPriority: " << this->network_configuration_priority + 1 @@ -299,6 +309,7 @@ void ConnectivityManager::init_websocket() { } this->websocket->register_message_callback([this](const std::string& message) { this->message_callback(message); }); + return true; } WebsocketConnectionOptions ConnectivityManager::get_ws_connection_options(const int32_t configuration_slot) { From cd4d2f92db56e36b349b1cf2a2ca299e7acaada4 Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Tue, 12 Nov 2024 17:02:17 +0100 Subject: [PATCH 03/15] Add check security profile while initializing the websocket Signed-off-by: Marc Emmers --- lib/ocpp/v201/connectivity_manager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 529aef85a..b4a3d334a 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -222,6 +222,11 @@ bool ConnectivityManager::init_websocket() { if (!network_connection_profile.has_value()) { EVLOG_warning << "No network connection profile configured for " << config_slot_int; can_use_connection_profile = false; + } else if (const auto& security_profile_cv = ControllerComponentVariables::SecurityProfile; + network_connection_profile.value().securityProfile < + this->device_model.get_value(security_profile_cv)) { + EVLOG_info << "Slot #" << config_slot_int << " has a lower security profile than current security profile"; + can_use_connection_profile = false; } else if (this->configure_network_connection_profile_callback.has_value()) { EVLOG_debug << "Request to configure network connection profile " << config_slot_int; From 5e09aeb36abd2ed7b14827cc23d37241be2ca5cc Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Wed, 13 Nov 2024 15:35:31 +0100 Subject: [PATCH 04/15] Some fixes with false connection to websocket Signed-off-by: Marc Emmers --- include/ocpp/v201/connectivity_manager.hpp | 2 +- lib/ocpp/v201/connectivity_manager.cpp | 121 ++++++++++++--------- 2 files changed, 68 insertions(+), 55 deletions(-) diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 2bf9dcf24..e0f29afdd 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -166,7 +166,7 @@ class ConnectivityManager { /// \brief Get the current websocket connection options /// \returns the current websocket connection options /// - WebsocketConnectionOptions get_ws_connection_options(const int32_t configuration_slot); + std::optional get_ws_connection_options(const int32_t configuration_slot); /// \brief Function invoked when the web socket connected with the \p security_profile /// diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index b4a3d334a..e717dc286 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -46,7 +46,9 @@ void ConnectivityManager::set_websocket_connection_options(const WebsocketConnec void ConnectivityManager::set_websocket_connection_options_without_reconnect() { const int configuration_slot = get_active_network_configuration_slot(); const auto connection_options = this->get_ws_connection_options(configuration_slot); - this->set_websocket_connection_options(connection_options); + if (connection_options.has_value()) { + this->set_websocket_connection_options(connection_options.value()); + } } void ConnectivityManager::set_websocket_connected_callback(WebsocketConnectionCallback callback) { @@ -109,8 +111,8 @@ void ConnectivityManager::start(bool autoconnect) { this->cache_network_connection_profiles(); return; } + this->disable_automatic_websocket_reconnects = false; if (init_websocket() && websocket != nullptr) { - this->disable_automatic_websocket_reconnects = false; websocket->connect(); } } @@ -130,10 +132,10 @@ void ConnectivityManager::connect() { void ConnectivityManager::disconnect_websocket(WebsocketCloseReason code) { this->websocket_timer.stop(); + if (code != WebsocketCloseReason::ServiceRestart) { + this->disable_automatic_websocket_reconnects = true; + } if (this->websocket != nullptr) { - if (code != WebsocketCloseReason::ServiceRestart) { - this->disable_automatic_websocket_reconnects = true; - } this->websocket->disconnect(code); } } @@ -222,6 +224,9 @@ bool ConnectivityManager::init_websocket() { if (!network_connection_profile.has_value()) { EVLOG_warning << "No network connection profile configured for " << config_slot_int; can_use_connection_profile = false; + } else if (!connection_options.has_value()) { + EVLOG_warning << "Connection profile configured for " << config_slot_int << " failed: not valid URL"; + can_use_connection_profile = false; } else if (const auto& security_profile_cv = ControllerComponentVariables::SecurityProfile; network_connection_profile.value().securityProfile < this->device_model.get_value(security_profile_cv)) { @@ -250,7 +255,7 @@ bool ConnectivityManager::init_websocket() { if (result.success and result.network_profile_slot == config_slot_int) { EVLOG_debug << "Config slot " << config_slot_int << " is configured"; // Set interface or ip to connection options. - connection_options.iface = result.interface_address; + connection_options->iface = result.interface_address; } else { EVLOG_warning << "Could not configure config slot " << config_slot_int; can_use_connection_profile = false; @@ -262,19 +267,18 @@ bool ConnectivityManager::init_websocket() { if (!can_use_connection_profile) { EVLOG_info << "websocket_timer set_timeout"; - if (this->disable_automatic_websocket_reconnects) { - return false; + if (!this->disable_automatic_websocket_reconnects) { + // if we are not going to hibernate + this->websocket_timer.timeout( + [this]() { + EVLOG_info << "websocket_timer.timeout 1"; + this->next_network_configuration_priority(); + this->start(); + }, + WEBSOCKET_INIT_DELAY); } - this->websocket_timer.timeout( - [this]() { - EVLOG_info << "websocket_timer.timeout 1"; - this->next_network_configuration_priority(); - this->start(); - }, - WEBSOCKET_INIT_DELAY); - - return true; + return false; } EVLOG_info << "Open websocket with NetworkConfigurationPriority: " << this->network_configuration_priority + 1 @@ -296,7 +300,7 @@ bool ConnectivityManager::init_websocket() { } if (this->websocket == nullptr) { - this->websocket = std::make_unique(connection_options, this->evse_security, this->logging); + this->websocket = std::make_unique(connection_options.value(), this->evse_security, this->logging); this->websocket->register_connected_callback( std::bind(&ConnectivityManager::on_websocket_connected, this, std::placeholders::_1)); @@ -305,7 +309,7 @@ bool ConnectivityManager::init_websocket() { this->websocket->register_closed_callback( std::bind(&ConnectivityManager::on_websocket_closed, this, std::placeholders::_1)); } else { - this->websocket->set_connection_options(connection_options); + this->websocket->set_connection_options(connection_options.value()); } // Attach external callbacks everytime since they might have changed @@ -317,7 +321,8 @@ bool ConnectivityManager::init_websocket() { return true; } -WebsocketConnectionOptions ConnectivityManager::get_ws_connection_options(const int32_t configuration_slot) { +std::optional +ConnectivityManager::get_ws_connection_options(const int32_t configuration_slot) { const auto network_connection_profile_opt = this->get_network_connection_profile(configuration_slot); if (!network_connection_profile_opt.has_value()) { @@ -327,40 +332,48 @@ WebsocketConnectionOptions ConnectivityManager::get_ws_connection_options(const const auto network_connection_profile = network_connection_profile_opt.value(); - auto uri = Uri::parse_and_validate( - network_connection_profile.ocppCsmsUrl.get(), - this->device_model.get_value(ControllerComponentVariables::SecurityCtrlrIdentity), - network_connection_profile.securityProfile); - - WebsocketConnectionOptions connection_options{ - OcppProtocolVersion::v201, - uri, - network_connection_profile.securityProfile, - this->device_model.get_optional_value(ControllerComponentVariables::BasicAuthPassword), - this->device_model.get_value(ControllerComponentVariables::RetryBackOffRandomRange), - this->device_model.get_value(ControllerComponentVariables::RetryBackOffRepeatTimes), - this->device_model.get_value(ControllerComponentVariables::RetryBackOffWaitMinimum), - this->device_model.get_value(ControllerComponentVariables::NetworkProfileConnectionAttempts), - this->device_model.get_value(ControllerComponentVariables::SupportedCiphers12), - this->device_model.get_value(ControllerComponentVariables::SupportedCiphers13), - this->device_model.get_value(ControllerComponentVariables::WebSocketPingInterval), - this->device_model.get_optional_value(ControllerComponentVariables::WebsocketPingPayload) - .value_or("payload"), - this->device_model.get_optional_value(ControllerComponentVariables::WebsocketPongTimeout).value_or(5), - this->device_model.get_optional_value(ControllerComponentVariables::UseSslDefaultVerifyPaths) - .value_or(true), - this->device_model.get_optional_value(ControllerComponentVariables::AdditionalRootCertificateCheck) - .value_or(false), - std::nullopt, // hostName - this->device_model.get_optional_value(ControllerComponentVariables::VerifyCsmsCommonName).value_or(true), - this->device_model.get_optional_value(ControllerComponentVariables::UseTPM).value_or(false), - this->device_model.get_optional_value(ControllerComponentVariables::VerifyCsmsAllowWildcards) - .value_or(false), - this->device_model.get_optional_value(ControllerComponentVariables::IFace), - this->device_model.get_optional_value(ControllerComponentVariables::EnableTLSKeylog).value_or(false), - this->device_model.get_optional_value(ControllerComponentVariables::TLSKeylogFile)}; - - return connection_options; + try { + auto uri = Uri::parse_and_validate( + network_connection_profile.ocppCsmsUrl.get(), + this->device_model.get_value(ControllerComponentVariables::SecurityCtrlrIdentity), + network_connection_profile.securityProfile); + + WebsocketConnectionOptions connection_options{ + OcppProtocolVersion::v201, + uri, + network_connection_profile.securityProfile, + this->device_model.get_optional_value(ControllerComponentVariables::BasicAuthPassword), + this->device_model.get_value(ControllerComponentVariables::RetryBackOffRandomRange), + this->device_model.get_value(ControllerComponentVariables::RetryBackOffRepeatTimes), + this->device_model.get_value(ControllerComponentVariables::RetryBackOffWaitMinimum), + this->device_model.get_value(ControllerComponentVariables::NetworkProfileConnectionAttempts), + this->device_model.get_value(ControllerComponentVariables::SupportedCiphers12), + this->device_model.get_value(ControllerComponentVariables::SupportedCiphers13), + this->device_model.get_value(ControllerComponentVariables::WebSocketPingInterval), + this->device_model.get_optional_value(ControllerComponentVariables::WebsocketPingPayload) + .value_or("payload"), + this->device_model.get_optional_value(ControllerComponentVariables::WebsocketPongTimeout).value_or(5), + this->device_model.get_optional_value(ControllerComponentVariables::UseSslDefaultVerifyPaths) + .value_or(true), + this->device_model.get_optional_value(ControllerComponentVariables::AdditionalRootCertificateCheck) + .value_or(false), + std::nullopt, // hostName + this->device_model.get_optional_value(ControllerComponentVariables::VerifyCsmsCommonName) + .value_or(true), + this->device_model.get_optional_value(ControllerComponentVariables::UseTPM).value_or(false), + this->device_model.get_optional_value(ControllerComponentVariables::VerifyCsmsAllowWildcards) + .value_or(false), + this->device_model.get_optional_value(ControllerComponentVariables::IFace), + this->device_model.get_optional_value(ControllerComponentVariables::EnableTLSKeylog).value_or(false), + this->device_model.get_optional_value(ControllerComponentVariables::TLSKeylogFile)}; + + return connection_options; + + } catch (const std::invalid_argument& e) { + EVLOG_error << "Could not configure the connection options: " << e.what(); + } + + return std::nullopt; } void ConnectivityManager::on_websocket_connected([[maybe_unused]] int security_profile) { From 346be356839f27a2bce49a8d03c36330bad45eaa Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Fri, 15 Nov 2024 14:25:03 +0100 Subject: [PATCH 05/15] Move removal of invalid profiles to conn manager, also remove on reconnect Signed-off-by: Marc Emmers --- include/ocpp/v201/connectivity_manager.hpp | 2 + lib/ocpp/v201/charge_point.cpp | 97 +++++----------------- lib/ocpp/v201/connectivity_manager.cpp | 69 ++++++++++++++- 3 files changed, 91 insertions(+), 77 deletions(-) diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index e0f29afdd..81acc362e 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -158,6 +158,8 @@ class ConnectivityManager { /// \return true if the switch is possible. bool on_try_switch_network_connection_profile(const int32_t configuration_slot); + void confirm_successfull_connection(); + private: /// \brief Init the websocket /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 770410f77..1c968d0b2 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -1207,53 +1207,6 @@ void ChargePoint::init_certificate_expiration_check_timers() { .value_or(60))); } -void ChargePoint::remove_network_connection_profiles_below_actual_security_profile() { - // Remove all the profiles that are a lower security level than security_level - const auto security_level = this->device_model->get_value(ControllerComponentVariables::SecurityProfile); - - auto network_connection_profiles = json::parse( - this->device_model->get_value(ControllerComponentVariables::NetworkConnectionProfiles)); - - auto is_lower_security_level = [security_level](const SetNetworkProfileRequest& item) { - return item.connectionData.securityProfile < security_level; - }; - - network_connection_profiles.erase( - std::remove_if(network_connection_profiles.begin(), network_connection_profiles.end(), is_lower_security_level), - network_connection_profiles.end()); - - this->device_model->set_value(ControllerComponentVariables::NetworkConnectionProfiles.component, - ControllerComponentVariables::NetworkConnectionProfiles.variable.value(), - AttributeEnum::Actual, network_connection_profiles.dump(), - VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); - - // Update the NetworkConfigurationPriority so only remaining profiles are in there - const auto network_priority = ocpp::split_string( - this->device_model->get_value(ControllerComponentVariables::NetworkConfigurationPriority), ','); - - auto in_network_profiles = [&network_connection_profiles](const std::string& item) { - auto is_same_slot = [&item](const SetNetworkProfileRequest& profile) { - return std::to_string(profile.configurationSlot) == item; - }; - return std::any_of(network_connection_profiles.begin(), network_connection_profiles.end(), is_same_slot); - }; - - std::string new_network_priority; - for (const auto& item : network_priority) { - if (in_network_profiles(item)) { - if (!new_network_priority.empty()) { - new_network_priority += ','; - } - new_network_priority += item; - } - } - - this->device_model->set_value(ControllerComponentVariables::NetworkConfigurationPriority.component, - ControllerComponentVariables::NetworkConfigurationPriority.variable.value(), - AttributeEnum::Actual, new_network_priority, - VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); -} - void ChargePoint::handle_message(const EnhancedMessage& message) { const auto& json_message = message.message; try { @@ -2459,7 +2412,7 @@ void ChargePoint::handle_boot_notification_response(CallResultcallbacks.time_sync_callback.value()(msg.currentTime); } - this->remove_network_connection_profiles_below_actual_security_profile(); + this->connectivity_manager->confirm_successfull_connection(); // set timers if (msg.interval > 0) { @@ -4173,33 +4126,29 @@ void ChargePoint::websocket_connected_callback(const int configuration_slot, const NetworkConnectionProfile& network_connection_profile) { this->message_queue->resume(this->message_queue_resume_delay); - const auto& security_profile_cv = ControllerComponentVariables::SecurityProfile; - if (security_profile_cv.variable.has_value()) { - this->device_model->set_read_only_value( - security_profile_cv.component, security_profile_cv.variable.value(), AttributeEnum::Actual, - std::to_string(network_connection_profile.securityProfile), VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); - } - - if (this->registration_status == RegistrationStatusEnum::Accepted and - this->time_disconnected.time_since_epoch() != 0s) { - // handle offline threshold - // Get the current time point using steady_clock - auto offline_duration = std::chrono::steady_clock::now() - this->time_disconnected; - - // B04.FR.01 - // If offline period exceeds offline threshold then send the status notification for all connectors - if (offline_duration > - std::chrono::seconds(this->device_model->get_value(ControllerComponentVariables::OfflineThreshold))) { - EVLOG_debug << "offline for more than offline threshold "; - this->component_state_manager->send_status_notification_all_connectors(); - } else { - // B04.FR.02 - // If offline period doesn't exceed offline threshold then send the status notification for all - // connectors that changed state - EVLOG_debug << "offline for less than offline threshold "; - this->component_state_manager->send_status_notification_changed_connectors(); + if (this->registration_status == RegistrationStatusEnum::Accepted) { + this->connectivity_manager->confirm_successfull_connection(); + + if (this->time_disconnected.time_since_epoch() != 0s) { + // handle offline threshold + // Get the current time point using steady_clock + auto offline_duration = std::chrono::steady_clock::now() - this->time_disconnected; + + // B04.FR.01 + // If offline period exceeds offline threshold then send the status notification for all connectors + if (offline_duration > std::chrono::seconds(this->device_model->get_value( + ControllerComponentVariables::OfflineThreshold))) { + EVLOG_debug << "offline for more than offline threshold "; + this->component_state_manager->send_status_notification_all_connectors(); + } else { + // B04.FR.02 + // If offline period doesn't exceed offline threshold then send the status notification for all + // connectors that changed state + EVLOG_debug << "offline for less than offline threshold "; + this->component_state_manager->send_status_notification_changed_connectors(); + } + this->init_certificate_expiration_check_timers(); // re-init as timers are stopped on disconnect } - this->init_certificate_expiration_check_timers(); // re-init as timers are stopped on disconnect } this->time_disconnected = std::chrono::time_point(); diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index e717dc286..688f3e203 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -71,7 +71,7 @@ void ConnectivityManager::set_configure_network_connection_profile_callback( std::optional ConnectivityManager::get_network_connection_profile(const int32_t configuration_slot) { - for (const auto& network_profile : this->network_connection_profiles) { + for (const auto& network_profile : this->cached_network_connection_profiles) { if (network_profile.configurationSlot == configuration_slot) { switch (auto security_profile = network_profile.connectionData.securityProfile) { case security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION: @@ -201,6 +201,69 @@ bool ConnectivityManager::on_try_switch_network_connection_profile(const int32_t return true; } +void ConnectivityManager::remove_network_connection_profiles_below_actual_security_profile() { + // Remove all the profiles that are a lower security level than security_level + const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); + + auto network_connection_profiles = json::parse( + this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); + + auto is_lower_security_level = [security_level](const SetNetworkProfileRequest& item) { + return item.connectionData.securityProfile < security_level; + }; + + network_connection_profiles.erase( + std::remove_if(network_connection_profiles.begin(), network_connection_profiles.end(), is_lower_security_level), + network_connection_profiles.end()); + + this->device_model.set_value(ControllerComponentVariables::NetworkConnectionProfiles.component, + ControllerComponentVariables::NetworkConnectionProfiles.variable.value(), + AttributeEnum::Actual, network_connection_profiles.dump(), + VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); + + // Update the NetworkConfigurationPriority so only remaining profiles are in there + const auto network_priority = ocpp::split_string( + this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority), ','); + + auto in_network_profiles = [&network_connection_profiles](const std::string& item) { + auto is_same_slot = [&item](const SetNetworkProfileRequest& profile) { + return std::to_string(profile.configurationSlot) == item; + }; + return std::any_of(network_connection_profiles.begin(), network_connection_profiles.end(), is_same_slot); + }; + + std::string new_network_priority; + for (const auto& item : network_priority) { + if (in_network_profiles(item)) { + if (!new_network_priority.empty()) { + new_network_priority += ','; + } + new_network_priority += item; + } + } + + this->device_model.set_value(ControllerComponentVariables::NetworkConfigurationPriority.component, + ControllerComponentVariables::NetworkConfigurationPriority.variable.value(), + AttributeEnum::Actual, new_network_priority, + VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); +} + +void ConnectivityManager::confirm_successfull_connection() { + const int config_slot_int = this->get_active_network_configuration_slot(); + + const auto network_connection_profile = this->get_network_connection_profile(config_slot_int); + + if (const auto& security_profile_cv = ControllerComponentVariables::SecurityProfile; + security_profile_cv.variable.has_value()) { + this->device_model.set_read_only_value(security_profile_cv.component, security_profile_cv.variable.value(), + AttributeEnum::Actual, + std::to_string(network_connection_profile.value().securityProfile), + VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); + } + + this->remove_network_connection_profiles_below_actual_security_profile(); +} + bool ConnectivityManager::init_websocket() { EVLOG_info << "ConnectivityManager::init_websocket()"; if (this->device_model.get_value(ControllerComponentVariables::ChargePointId).find(':') != @@ -469,13 +532,13 @@ void ConnectivityManager::next_network_configuration_priority() { bool ConnectivityManager::cache_network_connection_profiles() { - if (!this->network_connection_profiles.empty()) { + if (!this->cached_network_connection_profiles.empty()) { EVLOG_debug << " Network connection profiles already cached"; return true; } // get all the network connection profiles from the device model and cache them - this->network_connection_profiles = + this->cached_network_connection_profiles = json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); for (const std::string& str : ocpp::split_string( From c9e0273b5261f3f62dff2cc4f690cd48798cf099 Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Fri, 15 Nov 2024 14:28:53 +0100 Subject: [PATCH 06/15] Add clearing of cache if security level increased Signed-off-by: Marc Emmers --- include/ocpp/v201/connectivity_manager.hpp | 7 ++- lib/ocpp/v201/connectivity_manager.cpp | 54 ++++++++++++++++------ 2 files changed, 47 insertions(+), 14 deletions(-) diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 81acc362e..b3ad58e19 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -46,11 +46,13 @@ class ConnectivityManager { bool disable_automatic_websocket_reconnects; int network_configuration_priority; /// @brief Local cached network connection profiles - std::vector network_connection_profiles; + std::vector cached_network_connection_profiles; /// @brief local cached network connection priorities std::vector network_connection_priorities; WebsocketConnectionOptions current_connection_options{}; + int last_security_level{0}; + public: ConnectivityManager(DeviceModel& device_model, std::shared_ptr evse_security, std::shared_ptr logging, @@ -159,6 +161,7 @@ class ConnectivityManager { bool on_try_switch_network_connection_profile(const int32_t configuration_slot); void confirm_successfull_connection(); + void remove_network_connection_profiles_below_actual_security_profile(); private: /// \brief Init the websocket @@ -207,6 +210,8 @@ class ConnectivityManager { /// @brief Cache all the network connection profiles. Must be called once during initialization /// \return True if the network connection profiles could be cached, else False. bool cache_network_connection_profiles(); + + void check_cache_for_invalid_security_profiles(); }; } // namespace v201 diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 688f3e203..a94d47063 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -201,6 +201,43 @@ bool ConnectivityManager::on_try_switch_network_connection_profile(const int32_t return true; } +void ConnectivityManager::check_cache_for_invalid_security_profiles() { + const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); + + if (this->last_security_level == security_level) { + return; + } + this->last_security_level = security_level; + + auto before_slot = this->get_active_network_configuration_slot(); + + EVLOG_info << "Before cleanup"; + for (auto slot: this->network_connection_priorities) { + EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; + } + + auto is_lower_security_level = [this, security_level](const int slot) { + const auto opt_profile = this->get_network_connection_profile(slot); + return !opt_profile.has_value() || opt_profile->securityProfile < security_level; + }; + + this->network_connection_priorities.erase( + std::remove_if(this->network_connection_priorities.begin(), this->network_connection_priorities.end(), is_lower_security_level), + this->network_connection_priorities.end()); + + EVLOG_info << "After cleanup"; + for (auto slot: this->network_connection_priorities) { + EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; + } + + auto opt_priority = this->get_configuration_slot_priority(before_slot); + if (opt_priority) { + this->network_configuration_priority = *opt_priority; + } else { + this->next_network_configuration_priority(); + } +} + void ConnectivityManager::remove_network_connection_profiles_below_actual_security_profile() { // Remove all the profiles that are a lower security level than security_level const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); @@ -262,6 +299,7 @@ void ConnectivityManager::confirm_successfull_connection() { } this->remove_network_connection_profiles_below_actual_security_profile(); + this->check_cache_for_invalid_security_profiles(); } bool ConnectivityManager::init_websocket() { @@ -277,6 +315,9 @@ bool ConnectivityManager::init_websocket() { return false; } + // Check the cache runtime since security profile might change async + this->check_cache_for_invalid_security_profiles(); + const int config_slot_int = this->get_active_network_configuration_slot(); const auto network_connection_profile = this->get_network_connection_profile(config_slot_int); @@ -290,11 +331,6 @@ bool ConnectivityManager::init_websocket() { } else if (!connection_options.has_value()) { EVLOG_warning << "Connection profile configured for " << config_slot_int << " failed: not valid URL"; can_use_connection_profile = false; - } else if (const auto& security_profile_cv = ControllerComponentVariables::SecurityProfile; - network_connection_profile.value().securityProfile < - this->device_model.get_value(security_profile_cv)) { - EVLOG_info << "Slot #" << config_slot_int << " has a lower security profile than current security profile"; - can_use_connection_profile = false; } else if (this->configure_network_connection_profile_callback.has_value()) { EVLOG_debug << "Request to configure network connection profile " << config_slot_int; @@ -354,14 +390,6 @@ bool ConnectivityManager::init_websocket() { std::to_string(config_slot_int), VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); } - if (const auto& security_profile_cv = ControllerComponentVariables::SecurityProfile; - security_profile_cv.variable.has_value()) { - this->device_model.set_read_only_value(security_profile_cv.component, security_profile_cv.variable.value(), - AttributeEnum::Actual, - std::to_string(network_connection_profile.value().securityProfile), - VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); - } - if (this->websocket == nullptr) { this->websocket = std::make_unique(connection_options.value(), this->evse_security, this->logging); From ac2648403d621981fb21c7a083930eb593b89941 Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Fri, 15 Nov 2024 16:55:03 +0100 Subject: [PATCH 07/15] Refactor logic of connectivity manager Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 42 +-- include/ocpp/v201/connectivity_manager.hpp | 87 ++--- lib/ocpp/v201/charge_point.cpp | 27 +- lib/ocpp/v201/connectivity_manager.cpp | 363 ++++++++------------- 4 files changed, 201 insertions(+), 318 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 49443008b..70651623b 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -110,6 +110,13 @@ class ChargePointInterface { /// \brief Initializes the websocket and connects to CSMS if it is not yet connected virtual void connect_websocket() = 0; + /// \brief Initializes the websocket and connects to CSMS + /// a specific network connection profile given the configuration slot + /// if it is not yet connected. + /// + /// \param configuration_slot Slot in which the configuration is stored + virtual void connect_websocket(const int32_t configuration_slot) = 0; + /// \brief Disconnects the the websocket connection to the CSMS if it is connected virtual void disconnect_websocket() = 0; @@ -121,16 +128,6 @@ class ChargePointInterface { /// The handlers /// @{ - /// - /// \brief Can be called when a network is disconnected, for example when an ethernet cable is removed. - /// - /// This is introduced because the websocket can take several minutes to timeout when a network interface becomes - /// unavailable, whereas the system can detect this sooner. - /// - /// \param configuration_slot The slot of the network connection profile that is disconnected. - /// - virtual void on_network_disconnected(int32_t configuration_slot) = 0; - /// /// \brief Can be called when a network is disconnected, for example when an ethernet cable is removed. /// @@ -141,14 +138,6 @@ class ChargePointInterface { /// virtual void on_network_disconnected(OCPPInterfaceEnum ocpp_interface) = 0; - /// \brief Switch to a specific network connection profile given the configuration slot. - /// - /// Switch will only be done when the configuration slot has a higher priority. - /// - /// \param configuration_slot Slot in which the configuration is stored - /// \return true if the switch is possible. - virtual bool on_try_switch_network_connection_profile(const int32_t configuration_slot) = 0; - /// \brief Chargepoint notifies about new firmware update status firmware_update_status. This function should be /// called during a Firmware Update to indicate the current firmware_update_status. /// \param request_id The request_id. When it is -1, it will not be included in the request. @@ -372,14 +361,14 @@ class ChargePointInterface { /// \param configuration_slot The configuration slot to get the priority from. /// \return The priority if the configuration slot exists. /// - virtual std::optional get_configuration_slot_priority(const int configuration_slot) = 0; + virtual std::optional get_priority_from_configuration_slot(const int configuration_slot) = 0; - /// @brief Get the network connection priorities. + /// @brief Get the network connection slots sorted by priority. /// Each item in the vector contains the configured configuration slots, where the slot with index 0 has the highest /// priority. - /// @return The network connection priorities + /// @return The network connection slots /// - virtual const std::vector& get_network_connection_priorities() const = 0; + virtual const std::vector& get_network_connection_slots() const = 0; }; /// \brief Class implements OCPP2.0.1 Charging Station @@ -870,14 +859,11 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void stop() override; virtual void connect_websocket() override; + void connect_websocket(const int32_t configuration_slot) override; virtual void disconnect_websocket() override; - void on_network_disconnected(int32_t configuration_slot) override; - void on_network_disconnected(OCPPInterfaceEnum ocpp_interface) override; - bool on_try_switch_network_connection_profile(const int32_t configuration_slot) override; - void on_firmware_update_status_notification(int32_t request_id, const FirmwareStatusEnum& firmware_update_status) override; @@ -964,9 +950,9 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa std::optional get_network_connection_profile(const int32_t configuration_slot) override; - std::optional get_configuration_slot_priority(const int configuration_slot) override; + std::optional get_priority_from_configuration_slot(const int configuration_slot) override; - const std::vector& get_network_connection_priorities() const override; + const std::vector& get_network_connection_slots() const override; /// \brief Requests a value of a VariableAttribute specified by combination of \p component_id and \p variable_id /// from the device model diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index b3ad58e19..c77379c7c 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -43,13 +43,13 @@ class ConnectivityManager { std::optional configure_network_connection_profile_callback; Everest::SteadyTimer websocket_timer; - bool disable_automatic_websocket_reconnects; - int network_configuration_priority; + std::optional pending_configuration_slot; + bool disconnect_triggered; + int32_t active_network_configuration_priority; /// @brief Local cached network connection profiles std::vector cached_network_connection_profiles; /// @brief local cached network connection priorities - std::vector network_connection_priorities; - WebsocketConnectionOptions current_connection_options{}; + std::vector network_connection_slots; int last_security_level{0}; @@ -89,59 +89,41 @@ class ConnectivityManager { /// \brief Gets the configured NetworkConnectionProfile based on the given \p configuration_slot . The /// central system uri of the connection options will not contain ws:// or wss:// because this method removes it if /// present. This returns the value from the cached network connection profiles. \param - /// network_configuration_priority \return + /// active_network_configuration_priority \return std::optional get_network_connection_profile(const int32_t configuration_slot); /// \brief Get the priority of the given configuration slot. /// \param configuration_slot The configuration slot to get the priority from. /// \return The priority if the configuration slot exists. /// - std::optional get_configuration_slot_priority(const int configuration_slot); + std::optional get_priority_from_configuration_slot(const int configuration_slot); - /// @brief Get the network connection priorities. + /// @brief Get the network connection slots sorted by priority. /// Each item in the vector contains the configured configuration slots, where the slot with index 0 has the highest /// priority. - /// @return The network connection priorities + /// @return The network connection slots /// - const std::vector& get_network_connection_priorities() const; + const std::vector& get_network_connection_slots() const; /// \brief Check if the websocket is connected /// \return True is the websocket is connected, else false /// bool is_websocket_connected(); - /// \brief Start the connectivity manager - /// \param autoconnect Set to false if you only want to initialize and not connect yet and use connect() to connect - /// - void start(bool autoconnect = true); - - /// \brief Stop the connectivity manager - /// - void stop(); - /// \brief Connect to the websocket + /// \param configuration_slot The configuration slot to get the priority from. /// - void connect(); + void connect(std::optional configuration_slot = std::nullopt); - /// \brief Disconnect the websocket with a specific \p reason + /// \brief Disconnect the websocket /// - void disconnect_websocket(WebsocketCloseReason code = WebsocketCloseReason::Normal); + void disconnect(); /// \brief send a \p message over the websocket /// \returns true if the message was sent successfully /// bool send_to_websocket(const std::string& message); - /// - /// \brief Can be called when a network is disconnected, for example when an ethernet cable is removed. - /// - /// This is introduced because the websocket can take several minutes to timeout when a network interface becomes - /// unavailable, whereas the system can detect this sooner. - /// - /// \param configuration_slot The slot of the network connection profile that is disconnected. - /// - void on_network_disconnected(int32_t configuration_slot); - /// /// \brief Can be called when a network is disconnected, for example when an ethernet cable is removed. /// @@ -152,21 +134,17 @@ class ConnectivityManager { /// void on_network_disconnected(OCPPInterfaceEnum ocpp_interface); - /// \brief Switch to a specific network connection profile given the configuration slot. - /// - /// Switch will only be done when the configuration slot has a higher priority. + /// \brief Called when the chargin station certificate is changed /// - /// \param configuration_slot Slot in which the configuration is stored - /// \return true if the switch is possible. - bool on_try_switch_network_connection_profile(const int32_t configuration_slot); + void on_reconfiguration_of_security_parameters(); void confirm_successfull_connection(); void remove_network_connection_profiles_below_actual_security_profile(); private: - /// \brief Init the websocket + /// \brief Initializes the websocket and tries to connect /// - bool init_websocket(); + void try_connect_websocket(); /// \brief Get the current websocket connection options /// \returns the current websocket connection options @@ -185,31 +163,28 @@ class ConnectivityManager { /// void on_websocket_closed(ocpp::WebsocketCloseReason reason); - /// \brief Reconnect with the give websocket \p reason - /// - void reconnect(WebsocketCloseReason reason, std::optional next_priority = std::nullopt); - - /// - /// \brief Returns true if the provided configuration slot is of higher priority compared to the one currently - /// in use. - /// \param new_configuration_slot The configuration slot to check. - /// \return True when given slot is of higher priority. - /// - bool is_higher_priority_profile(const int new_configuration_slot); - /// /// \brief Get the active network configuration slot in use. /// \return The active slot the network is connected to or the pending slot. /// int get_active_network_configuration_slot(); - /// \brief Moves websocket network_configuration_priority to next profile /// - void next_network_configuration_priority(); + /// \brief Get the network configuration slot of the given priority. + /// \param priority The priority to get the configuration slot. + /// \return The configuration slot. + /// + int get_configuration_slot_from_priority(const int priority); + + /// + /// \brief Get the next prioritized network configuration slot of the given configuration slot. + /// \param configuration_slot The current configuration slot. + /// \return The next prioritized configuration slot. + /// + int get_next_configuration_slot(int32_t configuration_slot); - /// @brief Cache all the network connection profiles. Must be called once during initialization - /// \return True if the network connection profiles could be cached, else False. - bool cache_network_connection_profiles(); + /// @brief Cache all the network connection profiles + void cache_network_connection_profiles(); void check_cache_for_invalid_security_profiles(); }; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 1c968d0b2..e61ee3ed6 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -123,7 +123,9 @@ void ChargePoint::start(BootReasonEnum bootreason, bool autoconnect) { this->boot_notification_req(bootreason); // call clear_invalid_charging_profiles when system boots this->clear_invalid_charging_profiles(); - this->connectivity_manager->start(autoconnect); + if (autoconnect) { + this->connectivity_manager->connect(); + } const std::string firmware_version = this->device_model->get_value(ControllerComponentVariables::FirmwareVersion); @@ -157,7 +159,7 @@ void ChargePoint::stop() { this->heartbeat_timer.stop(); this->boot_notification_timer.stop(); this->certificate_signed_timer.stop(); - this->connectivity_manager->stop(); + this->connectivity_manager->disconnect(); this->client_certificate_expiration_check_timer.stop(); this->v2g_certificate_expiration_check_timer.stop(); this->monitoring_updater.stop_monitoring(); @@ -169,19 +171,15 @@ void ChargePoint::connect_websocket() { } void ChargePoint::disconnect_websocket() { - this->connectivity_manager->disconnect_websocket(); -} - -void ChargePoint::on_network_disconnected(int32_t configuration_slot) { - this->connectivity_manager->on_network_disconnected(configuration_slot); + this->connectivity_manager->disconnect(); } void ChargePoint::on_network_disconnected(OCPPInterfaceEnum ocpp_interface) { this->connectivity_manager->on_network_disconnected(ocpp_interface); } -bool ChargePoint::on_try_switch_network_connection_profile(const int32_t configuration_slot) { - return this->connectivity_manager->on_try_switch_network_connection_profile(configuration_slot); +void ChargePoint::connect_websocket(const int32_t configuration_slot) { + this->connectivity_manager->connect(configuration_slot); } void ChargePoint::on_firmware_update_status_notification(int32_t request_id, @@ -1748,7 +1746,6 @@ void ChargePoint::handle_variable_changed(const SetVariableData& set_variable_da if (this->device_model->get_value(ControllerComponentVariables::SecurityProfile) < 3) { // TODO: A01.FR.11 log the change of BasicAuth in Security Log this->connectivity_manager->set_websocket_authorization_key(set_variable_data.attributeValue.get()); - this->connectivity_manager->disconnect_websocket(WebsocketCloseReason::ServiceRestart); } } if (component_variable == ControllerComponentVariables::HeartbeatInterval and @@ -2330,7 +2327,7 @@ void ChargePoint::handle_certificate_signed_req(Call c if (response.status == CertificateSignedStatusEnum::Accepted and cert_signing_use == ocpp::CertificateSigningUseEnum::ChargingStationCertificate and this->device_model->get_value(ControllerComponentVariables::SecurityProfile) == 3) { - this->connectivity_manager->disconnect_websocket(WebsocketCloseReason::ServiceRestart); + this->connectivity_manager->on_reconfiguration_of_security_parameters(); const auto& security_event = ocpp::security_events::RECONFIGURATIONOFSECURITYPARAMETERS; std::string tech_info = "Changed charging station certificate"; @@ -4464,12 +4461,12 @@ std::optional ChargePoint::get_network_connection_prof return this->connectivity_manager->get_network_connection_profile(configuration_slot); } -std::optional ChargePoint::get_configuration_slot_priority(const int configuration_slot) { - return this->connectivity_manager->get_configuration_slot_priority(configuration_slot); +std::optional ChargePoint::get_priority_from_configuration_slot(const int configuration_slot) { + return this->connectivity_manager->get_priority_from_configuration_slot(configuration_slot); } -const std::vector& ChargePoint::get_network_connection_priorities() const { - return this->connectivity_manager->get_network_connection_priorities(); +const std::vector& ChargePoint::get_network_connection_slots() const { + return this->connectivity_manager->get_network_connection_slots(); } // Static functions diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index a94d47063..c2be1d6a1 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -26,18 +26,19 @@ ConnectivityManager::ConnectivityManager(DeviceModel& device_model, std::shared_ logging{logging}, websocket{nullptr}, message_callback{message_callback}, - disable_automatic_websocket_reconnects{false}, - network_configuration_priority{0} { + disconnect_triggered{false}, + active_network_configuration_priority{0} { + cache_network_connection_profiles(); } void ConnectivityManager::set_websocket_authorization_key(const std::string& authorization_key) { if (this->websocket != nullptr) { this->websocket->set_authorization_key(authorization_key); + this->websocket->disconnect(WebsocketCloseReason::ServiceRestart); } } void ConnectivityManager::set_websocket_connection_options(const WebsocketConnectionOptions& connection_options) { - this->current_connection_options = connection_options; if (this->websocket != nullptr) { this->websocket->set_connection_options(connection_options); } @@ -87,118 +88,47 @@ ConnectivityManager::get_network_connection_profile(const int32_t configuration_ return std::nullopt; } -std::optional ConnectivityManager::get_configuration_slot_priority(const int configuration_slot) { - auto it = std::find(this->network_connection_priorities.begin(), this->network_connection_priorities.end(), - configuration_slot); - if (it != network_connection_priorities.end()) { +std::optional ConnectivityManager::get_priority_from_configuration_slot(const int configuration_slot) { + auto it = + std::find(this->network_connection_slots.begin(), this->network_connection_slots.end(), configuration_slot); + if (it != network_connection_slots.end()) { // Index is iterator - begin iterator - return it - network_connection_priorities.begin(); + return it - network_connection_slots.begin(); } return std::nullopt; } -const std::vector& ConnectivityManager::get_network_connection_priorities() const { - return this->network_connection_priorities; -} - -bool ConnectivityManager::is_websocket_connected() { - return this->websocket != nullptr && this->websocket->is_connected(); -} - -void ConnectivityManager::start(bool autoconnect) { - if (!autoconnect) { - // Only cache the network profiles, starting the websocket is done by calling connect() later - this->cache_network_connection_profiles(); - return; - } - this->disable_automatic_websocket_reconnects = false; - if (init_websocket() && websocket != nullptr) { - websocket->connect(); - } -} - -void ConnectivityManager::stop() { - disconnect_websocket(WebsocketCloseReason::Normal); -} - -void ConnectivityManager::connect() { - if (this->websocket != nullptr and !this->websocket->is_connected()) { - this->disable_automatic_websocket_reconnects = false; - if (this->init_websocket()) { - this->websocket->connect(); - } - } -} - -void ConnectivityManager::disconnect_websocket(WebsocketCloseReason code) { - this->websocket_timer.stop(); - if (code != WebsocketCloseReason::ServiceRestart) { - this->disable_automatic_websocket_reconnects = true; - } - if (this->websocket != nullptr) { - this->websocket->disconnect(code); - } +int ConnectivityManager::get_active_network_configuration_slot() { + return this->network_connection_slots.at(this->active_network_configuration_priority); } -bool ConnectivityManager::send_to_websocket(const std::string& message) { - if (this->websocket == nullptr) { - return false; - } - - return this->websocket->send(message); +int ConnectivityManager::get_configuration_slot_from_priority(const int priority) { + return this->network_connection_slots.at(priority); } -void ConnectivityManager::on_network_disconnected(int32_t configuration_slot) { - const int actual_configuration_slot = get_active_network_configuration_slot(); - std::optional network_connection_profile = - this->get_network_connection_profile(actual_configuration_slot); - - if (!network_connection_profile.has_value()) { - EVLOG_warning << "Network disconnected. No network connection profile configured"; - } else if (configuration_slot == actual_configuration_slot) { - // Since there is no connection anymore: disconnect the websocket, the manager will try to connect with the next - // available network connection profile as we enable reconnects. - EVLOG_info << "ConnectivityManager::on_network_disconnected"; - this->disconnect_websocket(ocpp::WebsocketCloseReason::GoingAway); - this->disable_automatic_websocket_reconnects = false; - } +const std::vector& ConnectivityManager::get_network_connection_slots() const { + return this->network_connection_slots; } -void ConnectivityManager::on_network_disconnected(OCPPInterfaceEnum ocpp_interface) { - - const int actual_configuration_slot = get_active_network_configuration_slot(); - std::optional network_connection_profile = - this->get_network_connection_profile(actual_configuration_slot); - - if (!network_connection_profile.has_value()) { - EVLOG_warning << "Network disconnected. No network connection profile configured"; - } else if (ocpp_interface == network_connection_profile.value().ocppInterface) { - // Since there is no connection anymore: disconnect the websocket, the manager will try to connect with the next - // available network connection profile as we enable reconnects. - EVLOG_info << "ConnectivityManager::on_network_disconnected"; - this->disconnect_websocket(ocpp::WebsocketCloseReason::GoingAway); - this->disable_automatic_websocket_reconnects = false; - } +bool ConnectivityManager::is_websocket_connected() { + return this->websocket != nullptr && this->websocket->is_connected(); } -bool ConnectivityManager::on_try_switch_network_connection_profile(const int32_t configuration_slot) { - // if (!is_higher_priority_profile(configuration_slot)) { - // return false; - // } - - EVLOG_info << "Trying to connect with higher priority network connection profile (configuration slots: " - << this->get_active_network_configuration_slot() << " --> " << configuration_slot << ")."; - +void ConnectivityManager::connect(std::optional configuration_slot_opt) { + const int32_t configuration_slot = configuration_slot_opt.value_or(1); const std::optional network_connection_profile_opt = this->get_network_connection_profile(configuration_slot); if (!network_connection_profile_opt.has_value()) { EVLOG_warning << "Could not find network connection profile belonging to configuration slot " << configuration_slot; - return false; + return; + } + this->pending_configuration_slot = configuration_slot; + if (this->is_websocket_connected()) { + this->websocket->disconnect(WebsocketCloseReason::ServiceRestart); + } else { + this->try_connect_websocket(); } - this->disconnect_websocket(WebsocketCloseReason::Normal); - reconnect(WebsocketCloseReason::Normal, get_configuration_slot_priority(configuration_slot)); - return true; } void ConnectivityManager::check_cache_for_invalid_security_profiles() { @@ -209,10 +139,10 @@ void ConnectivityManager::check_cache_for_invalid_security_profiles() { } this->last_security_level = security_level; - auto before_slot = this->get_active_network_configuration_slot(); + auto before_slot = this->pending_configuration_slot.value_or(this->get_active_network_configuration_slot()); EVLOG_info << "Before cleanup"; - for (auto slot: this->network_connection_priorities) { + for (auto slot : this->network_connection_slots) { EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; } @@ -221,20 +151,20 @@ void ConnectivityManager::check_cache_for_invalid_security_profiles() { return !opt_profile.has_value() || opt_profile->securityProfile < security_level; }; - this->network_connection_priorities.erase( - std::remove_if(this->network_connection_priorities.begin(), this->network_connection_priorities.end(), is_lower_security_level), - this->network_connection_priorities.end()); + this->network_connection_slots.erase(std::remove_if(this->network_connection_slots.begin(), + this->network_connection_slots.end(), is_lower_security_level), + this->network_connection_slots.end()); EVLOG_info << "After cleanup"; - for (auto slot: this->network_connection_priorities) { + for (auto slot : this->network_connection_slots) { EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; } - auto opt_priority = this->get_configuration_slot_priority(before_slot); + auto opt_priority = this->get_priority_from_configuration_slot(before_slot); if (opt_priority) { - this->network_configuration_priority = *opt_priority; + this->pending_configuration_slot = before_slot; } else { - this->next_network_configuration_priority(); + this->pending_configuration_slot = this->get_next_configuration_slot(before_slot); } } @@ -242,8 +172,8 @@ void ConnectivityManager::remove_network_connection_profiles_below_actual_securi // Remove all the profiles that are a lower security level than security_level const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); - auto network_connection_profiles = json::parse( - this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); + auto network_connection_profiles = + json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); auto is_lower_security_level = [security_level](const SetNetworkProfileRequest& item) { return item.connectionData.securityProfile < security_level; @@ -254,9 +184,9 @@ void ConnectivityManager::remove_network_connection_profiles_below_actual_securi network_connection_profiles.end()); this->device_model.set_value(ControllerComponentVariables::NetworkConnectionProfiles.component, - ControllerComponentVariables::NetworkConnectionProfiles.variable.value(), - AttributeEnum::Actual, network_connection_profiles.dump(), - VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); + ControllerComponentVariables::NetworkConnectionProfiles.variable.value(), + AttributeEnum::Actual, network_connection_profiles.dump(), + VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); // Update the NetworkConfigurationPriority so only remaining profiles are in there const auto network_priority = ocpp::split_string( @@ -280,9 +210,8 @@ void ConnectivityManager::remove_network_connection_profiles_below_actual_securi } this->device_model.set_value(ControllerComponentVariables::NetworkConfigurationPriority.component, - ControllerComponentVariables::NetworkConfigurationPriority.variable.value(), - AttributeEnum::Actual, new_network_priority, - VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); + ControllerComponentVariables::NetworkConfigurationPriority.variable.value(), + AttributeEnum::Actual, new_network_priority, VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); } void ConnectivityManager::confirm_successfull_connection() { @@ -302,40 +231,41 @@ void ConnectivityManager::confirm_successfull_connection() { this->check_cache_for_invalid_security_profiles(); } -bool ConnectivityManager::init_websocket() { - EVLOG_info << "ConnectivityManager::init_websocket()"; +void ConnectivityManager::try_connect_websocket() { + + this->disconnect_triggered = false; + if (this->device_model.get_value(ControllerComponentVariables::ChargePointId).find(':') != std::string::npos) { EVLOG_AND_THROW(std::runtime_error("ChargePointId must not contain \':\'")); } - // cache the network profiles on initialization - if (!cache_network_connection_profiles()) { + if (this->network_connection_slots.empty()) { EVLOG_warning << "No network connection profiles configured, aborting websocket connection."; - return false; + return; } // Check the cache runtime since security profile might change async this->check_cache_for_invalid_security_profiles(); - const int config_slot_int = this->get_active_network_configuration_slot(); - - const auto network_connection_profile = this->get_network_connection_profile(config_slot_int); + const int configuration_slot_to_set = + this->pending_configuration_slot.value_or(this->get_active_network_configuration_slot()); + const auto network_connection_profile = this->get_network_connection_profile(configuration_slot_to_set); // Not const as the iface member can be set by the configure network connection profile callback - auto connection_options = this->get_ws_connection_options(config_slot_int); + auto connection_options = this->get_ws_connection_options(configuration_slot_to_set); bool can_use_connection_profile = true; if (!network_connection_profile.has_value()) { - EVLOG_warning << "No network connection profile configured for " << config_slot_int; + EVLOG_warning << "No network connection profile configured for " << configuration_slot_to_set; can_use_connection_profile = false; } else if (!connection_options.has_value()) { - EVLOG_warning << "Connection profile configured for " << config_slot_int << " failed: not valid URL"; + EVLOG_warning << "Connection profile configured for " << configuration_slot_to_set << " failed: not valid URL"; can_use_connection_profile = false; } else if (this->configure_network_connection_profile_callback.has_value()) { - EVLOG_debug << "Request to configure network connection profile " << config_slot_int; + EVLOG_debug << "Request to configure network connection profile " << configuration_slot_to_set; std::future config_status = this->configure_network_connection_profile_callback.value()( - config_slot_int, network_connection_profile.value()); + configuration_slot_to_set, network_connection_profile.value()); const int32_t config_timeout = this->device_model.get_optional_value(ControllerComponentVariables::NetworkConfigTimeout) .value_or(default_network_config_timeout_seconds); @@ -345,18 +275,18 @@ bool ConnectivityManager::init_websocket() { switch (status) { case std::future_status::deferred: case std::future_status::timeout: { - EVLOG_warning << "Timeout configuring config slot: " << config_slot_int; + EVLOG_warning << "Timeout configuring config slot: " << configuration_slot_to_set; can_use_connection_profile = false; break; } case std::future_status::ready: { ConfigNetworkResult result = config_status.get(); - if (result.success and result.network_profile_slot == config_slot_int) { - EVLOG_debug << "Config slot " << config_slot_int << " is configured"; + if (result.success and result.network_profile_slot == configuration_slot_to_set) { + EVLOG_debug << "Config slot " << configuration_slot_to_set << " is configured"; // Set interface or ip to connection options. connection_options->iface = result.interface_address; } else { - EVLOG_warning << "Could not configure config slot " << config_slot_int; + EVLOG_warning << "Could not configure config slot " << configuration_slot_to_set; can_use_connection_profile = false; } break; @@ -365,29 +295,30 @@ bool ConnectivityManager::init_websocket() { } if (!can_use_connection_profile) { - EVLOG_info << "websocket_timer set_timeout"; - if (!this->disable_automatic_websocket_reconnects) { - // if we are not going to hibernate + if (!this->disconnect_triggered) { this->websocket_timer.timeout( - [this]() { - EVLOG_info << "websocket_timer.timeout 1"; - this->next_network_configuration_priority(); - this->start(); + [this, configuration_slot_to_set] { + this->pending_configuration_slot = get_next_configuration_slot(configuration_slot_to_set); + this->try_connect_websocket(); }, WEBSOCKET_INIT_DELAY); } - - return false; + return; } - EVLOG_info << "Open websocket with NetworkConfigurationPriority: " << this->network_configuration_priority + 1 - << " which is configurationSlot " << config_slot_int; + this->pending_configuration_slot.reset(); + this->active_network_configuration_priority = + get_priority_from_configuration_slot(configuration_slot_to_set).value(); + + EVLOG_info << "Open websocket with NetworkConfigurationPriority: " + << this->active_network_configuration_priority + 1 << " which is configurationSlot " + << configuration_slot_to_set; if (const auto& active_network_profile_cv = ControllerComponentVariables::ActiveNetworkProfile; active_network_profile_cv.variable.has_value()) { this->device_model.set_read_only_value( active_network_profile_cv.component, active_network_profile_cv.variable.value(), AttributeEnum::Actual, - std::to_string(config_slot_int), VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); + std::to_string(configuration_slot_to_set), VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); } if (this->websocket == nullptr) { @@ -409,7 +340,61 @@ bool ConnectivityManager::init_websocket() { } this->websocket->register_message_callback([this](const std::string& message) { this->message_callback(message); }); - return true; + + this->websocket->connect(); +} + +void ConnectivityManager::disconnect() { + this->websocket_timer.stop(); + if (this->websocket != nullptr) { + this->disconnect_triggered = true; + this->websocket->disconnect(WebsocketCloseReason::Normal); + } +} + +int ConnectivityManager::get_next_configuration_slot(int32_t configuration_slot) { + + if (this->network_connection_slots.size() > 1) { + EVLOG_info << "Switching to next network configuration priority"; + } + const auto network_configuration_priority_opt = get_priority_from_configuration_slot(configuration_slot); + + const int network_configuration_priority = + network_configuration_priority_opt.has_value() + ? (network_configuration_priority_opt.value() + 1) % (this->network_connection_slots.size()) + : 0; + + return get_configuration_slot_from_priority(network_configuration_priority); +} + +bool ConnectivityManager::send_to_websocket(const std::string& message) { + if (this->websocket == nullptr) { + return false; + } + + return this->websocket->send(message); +} + +void ConnectivityManager::on_network_disconnected(OCPPInterfaceEnum ocpp_interface) { + + const int actual_configuration_slot = get_active_network_configuration_slot(); + std::optional network_connection_profile = + this->get_network_connection_profile(actual_configuration_slot); + + if (!network_connection_profile.has_value()) { + EVLOG_warning << "Network disconnected. No network connection profile configured"; + } else if (ocpp_interface == network_connection_profile.value().ocppInterface) { + // Since there is no connection anymore: disconnect the websocket, the manager will try to connect with the next + // available network connection profile as we enable reconnects. + EVLOG_info << "ConnectivityManager::on_network_disconnected"; + this->websocket->disconnect(ocpp::WebsocketCloseReason::GoingAway); + } +} + +void ConnectivityManager::on_reconfiguration_of_security_parameters() { + if (this->websocket != nullptr) { + this->websocket->disconnect(WebsocketCloseReason::ServiceRestart); + } } std::optional @@ -488,83 +473,24 @@ void ConnectivityManager::on_websocket_disconnected() { } void ConnectivityManager::on_websocket_closed(ocpp::WebsocketCloseReason reason) { - EVLOG_warning << "Closed websocket of NetworkConfigurationPriority: " << this->network_configuration_priority + 1 - << " which is configurationSlot " << this->get_active_network_configuration_slot(); - - if (!this->disable_automatic_websocket_reconnects) { - reconnect(reason); - } -} - -void ConnectivityManager::reconnect(WebsocketCloseReason reason, std::optional next_priority) { - this->websocket_timer.timeout( - [this, reason, next_priority]() { - if (reason != WebsocketCloseReason::ServiceRestart) { - if (!next_priority.has_value()) { - this->next_network_configuration_priority(); - } else { - this->network_configuration_priority = next_priority.value(); + EVLOG_warning << "Closed websocket of NetworkConfigurationPriority: " + << this->active_network_configuration_priority + 1 << " which is configurationSlot " + << this->get_active_network_configuration_slot(); + + if (!this->disconnect_triggered) { + this->websocket_timer.timeout( + [this, reason] { + if (reason != WebsocketCloseReason::ServiceRestart) { + this->pending_configuration_slot = + get_next_configuration_slot(get_active_network_configuration_slot()); } - } - this->start(); - }, - WEBSOCKET_INIT_DELAY); -} - -bool ConnectivityManager::is_higher_priority_profile(const int new_configuration_slot) { - - const int current_slot = get_active_network_configuration_slot(); - if (current_slot == 0) { - // No slot in use, new is always higher priority. - return true; - } - - if (current_slot == new_configuration_slot) { - // Slot is the same, probably already connected - return false; - } - - const std::optional new_priority = get_configuration_slot_priority(new_configuration_slot); - if (!new_priority.has_value()) { - // Slot not found. - return false; - } - - const std::optional current_priority = get_configuration_slot_priority(current_slot); - if (!current_priority.has_value()) { - // Slot not found. - return false; - } - - if (new_priority.value() < current_priority.value()) { - // Priority is indeed higher (lower index means higher priority) - return true; - } - - return false; -} - -int ConnectivityManager::get_active_network_configuration_slot() { - return this->network_connection_priorities.at(this->network_configuration_priority); -} - -void ConnectivityManager::next_network_configuration_priority() { - - // retrieve priorities from cache - if (this->network_connection_priorities.size() > 1) { - EVLOG_info << "Switching to next network configuration priority"; + this->try_connect_websocket(); + }, + WEBSOCKET_INIT_DELAY); } - this->network_configuration_priority = - (this->network_configuration_priority + 1) % (this->network_connection_priorities.size()); } -bool ConnectivityManager::cache_network_connection_profiles() { - - if (!this->cached_network_connection_profiles.empty()) { - EVLOG_debug << " Network connection profiles already cached"; - return true; - } - +void ConnectivityManager::cache_network_connection_profiles() { // get all the network connection profiles from the device model and cache them this->cached_network_connection_profiles = json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); @@ -573,10 +499,9 @@ bool ConnectivityManager::cache_network_connection_profiles() { this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority), ',')) { int num = std::stoi(str); - this->network_connection_priorities.push_back(num); + this->network_connection_slots.push_back(num); } - - return !this->network_connection_priorities.empty(); } + } // namespace v201 } // namespace ocpp From 3bce63bb9bbe35f19b534901180839e8cc345ac2 Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Mon, 18 Nov 2024 13:50:05 +0100 Subject: [PATCH 08/15] Change the start method parameters Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 12 +++++++----- lib/ocpp/v201/charge_point.cpp | 6 ++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 70651623b..173f81618 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -100,9 +100,10 @@ class ChargePointInterface { /// \brief Starts the ChargePoint, initializes and connects to the Websocket endpoint /// \param bootreason Optional bootreason (default: PowerUp). - /// \param autoconnect Set to false if you only want to initialize and not connect yet and use connect_websocket() - /// to actually connect - virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool autoconnect = true) = 0; + /// \param configuration_slot Configuration slot used to connect websocket + + virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, + std::optional configuration_slot = std::nullopt) = 0; /// \brief Stops the ChargePoint. Disconnects the websocket connection and stops MessageQueue and all timers virtual void stop() = 0; @@ -114,7 +115,7 @@ class ChargePointInterface { /// a specific network connection profile given the configuration slot /// if it is not yet connected. /// - /// \param configuration_slot Slot in which the configuration is stored + /// \param configuration_slot Configuration slot used to connect websocket virtual void connect_websocket(const int32_t configuration_slot) = 0; /// \brief Disconnects the the websocket connection to the CSMS if it is connected @@ -854,7 +855,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa ~ChargePoint(); - void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool autoconnect = true) override; + void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, + std::optional configuration_slot = std::nullopt) override; void stop() override; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index e61ee3ed6..a223a387c 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -111,7 +111,7 @@ ChargePoint::~ChargePoint() { this->auth_cache_cleanup_thread.join(); } -void ChargePoint::start(BootReasonEnum bootreason, bool autoconnect) { +void ChargePoint::start(BootReasonEnum bootreason, std::optional configuration_slot) { this->message_queue->start(); this->bootreason = bootreason; @@ -123,9 +123,7 @@ void ChargePoint::start(BootReasonEnum bootreason, bool autoconnect) { this->boot_notification_req(bootreason); // call clear_invalid_charging_profiles when system boots this->clear_invalid_charging_profiles(); - if (autoconnect) { - this->connectivity_manager->connect(); - } + this->connectivity_manager->connect(configuration_slot); const std::string firmware_version = this->device_model->get_value(ControllerComponentVariables::FirmwareVersion); From ef8a1a50683268e4c1bf35e6aa658605406143fd Mon Sep 17 00:00:00 2001 From: Ivan Rogach Date: Mon, 18 Nov 2024 14:16:12 +0100 Subject: [PATCH 09/15] Small fixes Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 12 ++---------- lib/ocpp/v201/charge_point.cpp | 6 +----- lib/ocpp/v201/connectivity_manager.cpp | 2 +- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 173f81618..20868754f 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -108,15 +108,12 @@ class ChargePointInterface { /// \brief Stops the ChargePoint. Disconnects the websocket connection and stops MessageQueue and all timers virtual void stop() = 0; - /// \brief Initializes the websocket and connects to CSMS if it is not yet connected - virtual void connect_websocket() = 0; - /// \brief Initializes the websocket and connects to CSMS /// a specific network connection profile given the configuration slot /// if it is not yet connected. /// /// \param configuration_slot Configuration slot used to connect websocket - virtual void connect_websocket(const int32_t configuration_slot) = 0; + virtual void connect_websocket(std::optional configuration_slot = std::nullopt) = 0; /// \brief Disconnects the the websocket connection to the CSMS if it is connected virtual void disconnect_websocket() = 0; @@ -483,10 +480,6 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa get_composite_schedule_internal(const GetCompositeScheduleRequest& request, const std::set& profiles_to_ignore = {}); - /// \brief Removes all network connection profiles below the actual security profile and stores the new list in the - /// device model - void remove_network_connection_profiles_below_actual_security_profile(); - void message_callback(const std::string& message); void update_aligned_data_interval(); @@ -860,8 +853,7 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa void stop() override; - virtual void connect_websocket() override; - void connect_websocket(const int32_t configuration_slot) override; + void connect_websocket(std::optional configuration_slot = std::nullopt) override; virtual void disconnect_websocket() override; void on_network_disconnected(OCPPInterfaceEnum ocpp_interface) override; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index a223a387c..cbedff9b9 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -164,10 +164,6 @@ void ChargePoint::stop() { this->message_queue->stop(); } -void ChargePoint::connect_websocket() { - this->connectivity_manager->connect(); -} - void ChargePoint::disconnect_websocket() { this->connectivity_manager->disconnect(); } @@ -176,7 +172,7 @@ void ChargePoint::on_network_disconnected(OCPPInterfaceEnum ocpp_interface) { this->connectivity_manager->on_network_disconnected(ocpp_interface); } -void ChargePoint::connect_websocket(const int32_t configuration_slot) { +void ChargePoint::connect_websocket(std::optional configuration_slot) { this->connectivity_manager->connect(configuration_slot); } diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index c2be1d6a1..5edb5c5d8 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -115,7 +115,7 @@ bool ConnectivityManager::is_websocket_connected() { } void ConnectivityManager::connect(std::optional configuration_slot_opt) { - const int32_t configuration_slot = configuration_slot_opt.value_or(1); + const int32_t configuration_slot = configuration_slot_opt.value_or(this->get_active_network_configuration_slot()); const std::optional network_connection_profile_opt = this->get_network_connection_profile(configuration_slot); if (!network_connection_profile_opt.has_value()) { From 644342641507c78a9aa637059d2a98e6d5533f88 Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Tue, 19 Nov 2024 12:34:08 +0100 Subject: [PATCH 10/15] Reorder functions a bit, move check for empty slots to connect() Signed-off-by: Marc Emmers --- include/ocpp/v201/connectivity_manager.hpp | 2 +- lib/ocpp/v201/charge_point.cpp | 4 +- lib/ocpp/v201/connectivity_manager.cpp | 190 +++++++++++---------- 3 files changed, 99 insertions(+), 97 deletions(-) diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index c77379c7c..51e120c21 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -138,7 +138,7 @@ class ConnectivityManager { /// void on_reconfiguration_of_security_parameters(); - void confirm_successfull_connection(); + void confirm_successful_connection(); void remove_network_connection_profiles_below_actual_security_profile(); private: diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index cbedff9b9..0f18e3aab 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -2403,7 +2403,7 @@ void ChargePoint::handle_boot_notification_response(CallResultcallbacks.time_sync_callback.value()(msg.currentTime); } - this->connectivity_manager->confirm_successfull_connection(); + this->connectivity_manager->confirm_successful_connection(); // set timers if (msg.interval > 0) { @@ -4118,7 +4118,7 @@ void ChargePoint::websocket_connected_callback(const int configuration_slot, this->message_queue->resume(this->message_queue_resume_delay); if (this->registration_status == RegistrationStatusEnum::Accepted) { - this->connectivity_manager->confirm_successfull_connection(); + this->connectivity_manager->confirm_successful_connection(); if (this->time_disconnected.time_since_epoch() != 0s) { // handle offline threshold diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 5edb5c5d8..cc1055ec7 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -115,6 +115,11 @@ bool ConnectivityManager::is_websocket_connected() { } void ConnectivityManager::connect(std::optional configuration_slot_opt) { + if (this->network_connection_slots.empty()) { + EVLOG_warning << "No network connection profiles configured, aborting websocket connection."; + return; + } + const int32_t configuration_slot = configuration_slot_opt.value_or(this->get_active_network_configuration_slot()); const std::optional network_connection_profile_opt = this->get_network_connection_profile(configuration_slot); @@ -131,90 +136,15 @@ void ConnectivityManager::connect(std::optional configuration_slot_opt) } } -void ConnectivityManager::check_cache_for_invalid_security_profiles() { - const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); - - if (this->last_security_level == security_level) { - return; - } - this->last_security_level = security_level; - - auto before_slot = this->pending_configuration_slot.value_or(this->get_active_network_configuration_slot()); - - EVLOG_info << "Before cleanup"; - for (auto slot : this->network_connection_slots) { - EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; - } - - auto is_lower_security_level = [this, security_level](const int slot) { - const auto opt_profile = this->get_network_connection_profile(slot); - return !opt_profile.has_value() || opt_profile->securityProfile < security_level; - }; - - this->network_connection_slots.erase(std::remove_if(this->network_connection_slots.begin(), - this->network_connection_slots.end(), is_lower_security_level), - this->network_connection_slots.end()); - - EVLOG_info << "After cleanup"; - for (auto slot : this->network_connection_slots) { - EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; - } - - auto opt_priority = this->get_priority_from_configuration_slot(before_slot); - if (opt_priority) { - this->pending_configuration_slot = before_slot; - } else { - this->pending_configuration_slot = this->get_next_configuration_slot(before_slot); - } -} - -void ConnectivityManager::remove_network_connection_profiles_below_actual_security_profile() { - // Remove all the profiles that are a lower security level than security_level - const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); - - auto network_connection_profiles = - json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); - - auto is_lower_security_level = [security_level](const SetNetworkProfileRequest& item) { - return item.connectionData.securityProfile < security_level; - }; - - network_connection_profiles.erase( - std::remove_if(network_connection_profiles.begin(), network_connection_profiles.end(), is_lower_security_level), - network_connection_profiles.end()); - - this->device_model.set_value(ControllerComponentVariables::NetworkConnectionProfiles.component, - ControllerComponentVariables::NetworkConnectionProfiles.variable.value(), - AttributeEnum::Actual, network_connection_profiles.dump(), - VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); - - // Update the NetworkConfigurationPriority so only remaining profiles are in there - const auto network_priority = ocpp::split_string( - this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority), ','); - - auto in_network_profiles = [&network_connection_profiles](const std::string& item) { - auto is_same_slot = [&item](const SetNetworkProfileRequest& profile) { - return std::to_string(profile.configurationSlot) == item; - }; - return std::any_of(network_connection_profiles.begin(), network_connection_profiles.end(), is_same_slot); - }; - - std::string new_network_priority; - for (const auto& item : network_priority) { - if (in_network_profiles(item)) { - if (!new_network_priority.empty()) { - new_network_priority += ','; - } - new_network_priority += item; - } +void ConnectivityManager::disconnect() { + this->websocket_timer.stop(); + if (this->websocket != nullptr) { + this->disconnect_triggered = true; + this->websocket->disconnect(WebsocketCloseReason::Normal); } - - this->device_model.set_value(ControllerComponentVariables::NetworkConfigurationPriority.component, - ControllerComponentVariables::NetworkConfigurationPriority.variable.value(), - AttributeEnum::Actual, new_network_priority, VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); } -void ConnectivityManager::confirm_successfull_connection() { +void ConnectivityManager::confirm_successful_connection() { const int config_slot_int = this->get_active_network_configuration_slot(); const auto network_connection_profile = this->get_network_connection_profile(config_slot_int); @@ -240,11 +170,6 @@ void ConnectivityManager::try_connect_websocket() { EVLOG_AND_THROW(std::runtime_error("ChargePointId must not contain \':\'")); } - if (this->network_connection_slots.empty()) { - EVLOG_warning << "No network connection profiles configured, aborting websocket connection."; - return; - } - // Check the cache runtime since security profile might change async this->check_cache_for_invalid_security_profiles(); @@ -344,14 +269,6 @@ void ConnectivityManager::try_connect_websocket() { this->websocket->connect(); } -void ConnectivityManager::disconnect() { - this->websocket_timer.stop(); - if (this->websocket != nullptr) { - this->disconnect_triggered = true; - this->websocket->disconnect(WebsocketCloseReason::Normal); - } -} - int ConnectivityManager::get_next_configuration_slot(int32_t configuration_slot) { if (this->network_connection_slots.size() > 1) { @@ -503,5 +420,90 @@ void ConnectivityManager::cache_network_connection_profiles() { } } +void ConnectivityManager::check_cache_for_invalid_security_profiles() { + const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); + + if (this->last_security_level == security_level) { + return; + } + this->last_security_level = security_level; + + // Use active slot + auto before_slot = this->pending_configuration_slot.value_or(this->get_active_network_configuration_slot()); + + EVLOG_info << "Before cleanup"; + for (auto slot : this->network_connection_slots) { + EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; + } + + auto is_lower_security_level = [this, security_level](const int slot) { + const auto opt_profile = this->get_network_connection_profile(slot); + return !opt_profile.has_value() || opt_profile->securityProfile < security_level; + }; + + this->network_connection_slots.erase(std::remove_if(this->network_connection_slots.begin(), + this->network_connection_slots.end(), is_lower_security_level), + this->network_connection_slots.end()); + + EVLOG_info << "After cleanup"; + for (auto slot : this->network_connection_slots) { + EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; + } + + // Use the active slot and if not valid any longer use the next one + auto opt_priority = this->get_priority_from_configuration_slot(before_slot); + if (opt_priority) { + this->pending_configuration_slot = before_slot; + } else { + this->pending_configuration_slot = this->get_next_configuration_slot(before_slot); + } +} + +void ConnectivityManager::remove_network_connection_profiles_below_actual_security_profile() { + // Remove all the profiles that are a lower security level than security_level + const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); + + auto network_connection_profiles = + json::parse(this->device_model.get_value(ControllerComponentVariables::NetworkConnectionProfiles)); + + auto is_lower_security_level = [security_level](const SetNetworkProfileRequest& item) { + return item.connectionData.securityProfile < security_level; + }; + + network_connection_profiles.erase( + std::remove_if(network_connection_profiles.begin(), network_connection_profiles.end(), is_lower_security_level), + network_connection_profiles.end()); + + this->device_model.set_value(ControllerComponentVariables::NetworkConnectionProfiles.component, + ControllerComponentVariables::NetworkConnectionProfiles.variable.value(), + AttributeEnum::Actual, network_connection_profiles.dump(), + VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); + + // Update the NetworkConfigurationPriority so only remaining profiles are in there + const auto network_priority = ocpp::split_string( + this->device_model.get_value(ControllerComponentVariables::NetworkConfigurationPriority), ','); + + auto in_network_profiles = [&network_connection_profiles](const std::string& item) { + auto is_same_slot = [&item](const SetNetworkProfileRequest& profile) { + return std::to_string(profile.configurationSlot) == item; + }; + return std::any_of(network_connection_profiles.begin(), network_connection_profiles.end(), is_same_slot); + }; + + std::string new_network_priority; + for (const auto& item : network_priority) { + if (in_network_profiles(item)) { + if (!new_network_priority.empty()) { + new_network_priority += ','; + } + new_network_priority += item; + } + } + + this->device_model.set_value(ControllerComponentVariables::NetworkConfigurationPriority.component, + ControllerComponentVariables::NetworkConfigurationPriority.variable.value(), + AttributeEnum::Actual, new_network_priority, VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL); +} + } // namespace v201 } // namespace ocpp From 29ad96893dd3c520096fb1f66b1b7ae613a1cbea Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Wed, 20 Nov 2024 12:52:34 +0100 Subject: [PATCH 11/15] Clean up of some changes we made, remove slot from confignetwork Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 22 ++-- include/ocpp/v201/connectivity_manager.hpp | 32 ++++-- include/ocpp/v201/ocpp_types.hpp | 1 - lib/ocpp/v201/charge_point.cpp | 10 +- lib/ocpp/v201/connectivity_manager.cpp | 117 ++++++++++----------- 5 files changed, 96 insertions(+), 86 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 20868754f..1c9de4017 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -100,20 +100,19 @@ class ChargePointInterface { /// \brief Starts the ChargePoint, initializes and connects to the Websocket endpoint /// \param bootreason Optional bootreason (default: PowerUp). - /// \param configuration_slot Configuration slot used to connect websocket - - virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, - std::optional configuration_slot = std::nullopt) = 0; + /// \param start_connecting Optional, set to false to initialize but not start connecting. Otherwise will connect to + /// the first network profile. (default: true) + virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool start_connecting = true) = 0; /// \brief Stops the ChargePoint. Disconnects the websocket connection and stops MessageQueue and all timers virtual void stop() = 0; - /// \brief Initializes the websocket and connects to CSMS - /// a specific network connection profile given the configuration slot - /// if it is not yet connected. + /// \brief Initializes the websocket and connects to a CSMS. Provide a network_profile_slot to connect to that + /// specific slot. /// - /// \param configuration_slot Configuration slot used to connect websocket - virtual void connect_websocket(std::optional configuration_slot = std::nullopt) = 0; + /// \param network_profile_slot Optional slot to use when connecting. std::nullopt means the slot will be determined + /// automatically. + virtual void connect_websocket(std::optional network_profile_slot = std::nullopt) = 0; /// \brief Disconnects the the websocket connection to the CSMS if it is connected virtual void disconnect_websocket() = 0; @@ -848,12 +847,11 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa ~ChargePoint(); - void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, - std::optional configuration_slot = std::nullopt) override; + void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool start_connecting = true) override; void stop() override; - void connect_websocket(std::optional configuration_slot = std::nullopt) override; + void connect_websocket(std::optional network_profile_slot = std::nullopt) override; virtual void disconnect_websocket() override; void on_network_disconnected(OCPPInterfaceEnum ocpp_interface) override; diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 51e120c21..526c5a4bd 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -44,15 +44,14 @@ class ConnectivityManager { Everest::SteadyTimer websocket_timer; std::optional pending_configuration_slot; - bool disconnect_triggered; + bool wants_to_be_connected; int32_t active_network_configuration_priority; + int last_known_security_level; /// @brief Local cached network connection profiles std::vector cached_network_connection_profiles; /// @brief local cached network connection priorities std::vector network_connection_slots; - int last_security_level{0}; - public: ConnectivityManager(DeviceModel& device_model, std::shared_ptr evse_security, std::shared_ptr logging, @@ -111,9 +110,10 @@ class ConnectivityManager { bool is_websocket_connected(); /// \brief Connect to the websocket - /// \param configuration_slot The configuration slot to get the priority from. + /// \param configuration_slot Optional the network_profile_slot to connect to. std::nullopt will select the slot + /// internally. /// - void connect(std::optional configuration_slot = std::nullopt); + void connect(std::optional network_profile_slot = std::nullopt); /// \brief Disconnect the websocket /// @@ -134,12 +134,12 @@ class ConnectivityManager { /// void on_network_disconnected(OCPPInterfaceEnum ocpp_interface); - /// \brief Called when the chargin station certificate is changed + /// \brief Called when the charging station certificate is changed /// void on_reconfiguration_of_security_parameters(); + /// \brief Confirms the connection is successful so the security profile requirements can be handled void confirm_successful_connection(); - void remove_network_connection_profiles_below_actual_security_profile(); private: /// \brief Initializes the websocket and tries to connect @@ -147,10 +147,18 @@ class ConnectivityManager { void try_connect_websocket(); /// \brief Get the current websocket connection options - /// \returns the current websocket connection options + /// \return the current websocket connection options /// std::optional get_ws_connection_options(const int32_t configuration_slot); + /// \brief Calls the configuration callback to get the interface to use, if there is a callback + /// \param slot The configuration slot to get the interface for + /// \param profile The network connection profile to get the interface for + /// + /// \return A string containing the network interface to use, nullptr if the request failed or the callback is not + /// configured + std::optional get_network_configuration_interface(int slot, const NetworkConnectionProfile& profile); + /// \brief Function invoked when the web socket connected with the \p security_profile /// void on_websocket_connected(const int security_profile); @@ -183,10 +191,16 @@ class ConnectivityManager { /// int get_next_configuration_slot(int32_t configuration_slot); - /// @brief Cache all the network connection profiles + /// \brief Cache all the network connection profiles void cache_network_connection_profiles(); + /// \brief Removes all connection profiles from the cache that have a security profile lower than the currently + /// connected security profile void check_cache_for_invalid_security_profiles(); + + /// \brief Removes all connection profiles from the database that have a security profile lower than the currently + /// connected security profile + void remove_network_connection_profiles_below_actual_security_profile(); }; } // namespace v201 diff --git a/include/ocpp/v201/ocpp_types.hpp b/include/ocpp/v201/ocpp_types.hpp index 5c76097e8..0676cb74a 100644 --- a/include/ocpp/v201/ocpp_types.hpp +++ b/include/ocpp/v201/ocpp_types.hpp @@ -891,7 +891,6 @@ std::ostream& operator<<(std::ostream& os, const SetMonitoringResult& k); /// @brief The result of a configuration of a network profile. struct ConfigNetworkResult { - uint8_t network_profile_slot; ///< @brief Network profile slot. std::optional interface_address; ///< ip address or interface string bool success; ///< true if the configuration was successful }; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 0f18e3aab..5eaaf6e6b 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -111,7 +111,7 @@ ChargePoint::~ChargePoint() { this->auth_cache_cleanup_thread.join(); } -void ChargePoint::start(BootReasonEnum bootreason, std::optional configuration_slot) { +void ChargePoint::start(BootReasonEnum bootreason, bool start_connecting) { this->message_queue->start(); this->bootreason = bootreason; @@ -123,7 +123,9 @@ void ChargePoint::start(BootReasonEnum bootreason, std::optional config this->boot_notification_req(bootreason); // call clear_invalid_charging_profiles when system boots this->clear_invalid_charging_profiles(); - this->connectivity_manager->connect(configuration_slot); + if (start_connecting) { + this->connectivity_manager->connect(); + } const std::string firmware_version = this->device_model->get_value(ControllerComponentVariables::FirmwareVersion); @@ -172,8 +174,8 @@ void ChargePoint::on_network_disconnected(OCPPInterfaceEnum ocpp_interface) { this->connectivity_manager->on_network_disconnected(ocpp_interface); } -void ChargePoint::connect_websocket(std::optional configuration_slot) { - this->connectivity_manager->connect(configuration_slot); +void ChargePoint::connect_websocket(std::optional network_profile_slot) { + this->connectivity_manager->connect(network_profile_slot); } void ChargePoint::on_firmware_update_status_notification(int32_t request_id, diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index cc1055ec7..7abd4ebc7 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -26,8 +26,9 @@ ConnectivityManager::ConnectivityManager(DeviceModel& device_model, std::shared_ logging{logging}, websocket{nullptr}, message_callback{message_callback}, - disconnect_triggered{false}, - active_network_configuration_priority{0} { + wants_to_be_connected{false}, + active_network_configuration_priority{0}, + last_known_security_level{0} { cache_network_connection_profiles(); } @@ -74,12 +75,11 @@ ConnectivityManager::get_network_connection_profile(const int32_t configuration_ for (const auto& network_profile : this->cached_network_connection_profiles) { if (network_profile.configurationSlot == configuration_slot) { - switch (auto security_profile = network_profile.connectionData.securityProfile) { - case security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION: - throw std::invalid_argument("security_profile = " + std::to_string(security_profile) + - " not officially allowed in OCPP 2.0.1"); - default: - break; + if (network_profile.connectionData.securityProfile == + security::OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION) { + throw std::invalid_argument( + "security_profile = " + std::to_string(network_profile.connectionData.securityProfile) + + " not officially allowed in OCPP 2.0.1"); } return network_profile.connectionData; @@ -91,9 +91,9 @@ ConnectivityManager::get_network_connection_profile(const int32_t configuration_ std::optional ConnectivityManager::get_priority_from_configuration_slot(const int configuration_slot) { auto it = std::find(this->network_connection_slots.begin(), this->network_connection_slots.end(), configuration_slot); - if (it != network_connection_slots.end()) { + if (it != this->network_connection_slots.end()) { // Index is iterator - begin iterator - return it - network_connection_slots.begin(); + return it - this->network_connection_slots.begin(); } return std::nullopt; } @@ -121,15 +121,16 @@ void ConnectivityManager::connect(std::optional configuration_slot_opt) } const int32_t configuration_slot = configuration_slot_opt.value_or(this->get_active_network_configuration_slot()); - const std::optional network_connection_profile_opt = - this->get_network_connection_profile(configuration_slot); - if (!network_connection_profile_opt.has_value()) { + if (!this->get_network_connection_profile(configuration_slot).has_value()) { EVLOG_warning << "Could not find network connection profile belonging to configuration slot " << configuration_slot; return; } + + this->wants_to_be_connected = true; this->pending_configuration_slot = configuration_slot; if (this->is_websocket_connected()) { + // After the websocket gets closed a reconnect will be triggered this->websocket->disconnect(WebsocketCloseReason::ServiceRestart); } else { this->try_connect_websocket(); @@ -137,9 +138,9 @@ void ConnectivityManager::connect(std::optional configuration_slot_opt) } void ConnectivityManager::disconnect() { + this->wants_to_be_connected = false; this->websocket_timer.stop(); if (this->websocket != nullptr) { - this->disconnect_triggered = true; this->websocket->disconnect(WebsocketCloseReason::Normal); } } @@ -162,9 +163,6 @@ void ConnectivityManager::confirm_successful_connection() { } void ConnectivityManager::try_connect_websocket() { - - this->disconnect_triggered = false; - if (this->device_model.get_value(ControllerComponentVariables::ChargePointId).find(':') != std::string::npos) { EVLOG_AND_THROW(std::runtime_error("ChargePointId must not contain \':\'")); @@ -187,40 +185,17 @@ void ConnectivityManager::try_connect_websocket() { EVLOG_warning << "Connection profile configured for " << configuration_slot_to_set << " failed: not valid URL"; can_use_connection_profile = false; } else if (this->configure_network_connection_profile_callback.has_value()) { - EVLOG_debug << "Request to configure network connection profile " << configuration_slot_to_set; - - std::future config_status = this->configure_network_connection_profile_callback.value()( - configuration_slot_to_set, network_connection_profile.value()); - const int32_t config_timeout = - this->device_model.get_optional_value(ControllerComponentVariables::NetworkConfigTimeout) - .value_or(default_network_config_timeout_seconds); - - std::future_status status = config_status.wait_for(std::chrono::seconds(config_timeout)); - - switch (status) { - case std::future_status::deferred: - case std::future_status::timeout: { - EVLOG_warning << "Timeout configuring config slot: " << configuration_slot_to_set; + if (std::optional interface_address = + get_network_configuration_interface(configuration_slot_to_set, network_connection_profile.value()); + interface_address.has_value()) { + connection_options->iface = interface_address; + } else { can_use_connection_profile = false; - break; - } - case std::future_status::ready: { - ConfigNetworkResult result = config_status.get(); - if (result.success and result.network_profile_slot == configuration_slot_to_set) { - EVLOG_debug << "Config slot " << configuration_slot_to_set << " is configured"; - // Set interface or ip to connection options. - connection_options->iface = result.interface_address; - } else { - EVLOG_warning << "Could not configure config slot " << configuration_slot_to_set; - can_use_connection_profile = false; - } - break; - } } } if (!can_use_connection_profile) { - if (!this->disconnect_triggered) { + if (this->wants_to_be_connected) { this->websocket_timer.timeout( [this, configuration_slot_to_set] { this->pending_configuration_slot = get_next_configuration_slot(configuration_slot_to_set); @@ -269,6 +244,37 @@ void ConnectivityManager::try_connect_websocket() { this->websocket->connect(); } +std::optional +ConnectivityManager::get_network_configuration_interface(int slot, const NetworkConnectionProfile& profile) { + if (!this->configure_network_connection_profile_callback.has_value()) { + return std::nullopt; + } + + EVLOG_debug << "Request to configure network connection profile " << slot; + + std::future config_status = + this->configure_network_connection_profile_callback.value()(slot, profile); + const int32_t config_timeout = + this->device_model.get_optional_value(ControllerComponentVariables::NetworkConfigTimeout) + .value_or(default_network_config_timeout_seconds); + + switch (config_status.wait_for(std::chrono::seconds(config_timeout))) { + case std::future_status::deferred: + case std::future_status::timeout: + EVLOG_warning << "Timeout configuring config slot: " << slot; + return std::nullopt; + + case std::future_status::ready: + if (ConfigNetworkResult result = config_status.get(); result.success) { + EVLOG_debug << "Config slot " << slot << " is configured"; + return result.interface_address; + } + EVLOG_warning << "Could not configure config slot " << slot; + break; + } + return std::nullopt; +} + int ConnectivityManager::get_next_configuration_slot(int32_t configuration_slot) { if (this->network_connection_slots.size() > 1) { @@ -310,6 +316,7 @@ void ConnectivityManager::on_network_disconnected(OCPPInterfaceEnum ocpp_interfa void ConnectivityManager::on_reconfiguration_of_security_parameters() { if (this->websocket != nullptr) { + // After the websocket gets closed a reconnect will be triggered this->websocket->disconnect(WebsocketCloseReason::ServiceRestart); } } @@ -394,7 +401,7 @@ void ConnectivityManager::on_websocket_closed(ocpp::WebsocketCloseReason reason) << this->active_network_configuration_priority + 1 << " which is configurationSlot " << this->get_active_network_configuration_slot(); - if (!this->disconnect_triggered) { + if (this->wants_to_be_connected) { this->websocket_timer.timeout( [this, reason] { if (reason != WebsocketCloseReason::ServiceRestart) { @@ -423,19 +430,14 @@ void ConnectivityManager::cache_network_connection_profiles() { void ConnectivityManager::check_cache_for_invalid_security_profiles() { const auto security_level = this->device_model.get_value(ControllerComponentVariables::SecurityProfile); - if (this->last_security_level == security_level) { + if (this->last_known_security_level == security_level) { return; } - this->last_security_level = security_level; + this->last_known_security_level = security_level; // Use active slot auto before_slot = this->pending_configuration_slot.value_or(this->get_active_network_configuration_slot()); - EVLOG_info << "Before cleanup"; - for (auto slot : this->network_connection_slots) { - EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; - } - auto is_lower_security_level = [this, security_level](const int slot) { const auto opt_profile = this->get_network_connection_profile(slot); return !opt_profile.has_value() || opt_profile->securityProfile < security_level; @@ -445,12 +447,7 @@ void ConnectivityManager::check_cache_for_invalid_security_profiles() { this->network_connection_slots.end(), is_lower_security_level), this->network_connection_slots.end()); - EVLOG_info << "After cleanup"; - for (auto slot : this->network_connection_slots) { - EVLOG_info << "Slot " << slot << " sec level: " << this->get_network_connection_profile(slot)->securityProfile; - } - - // Use the active slot and if not valid any longer use the next one + // Use the active slot and if not valid any longer use the next available one auto opt_priority = this->get_priority_from_configuration_slot(before_slot); if (opt_priority) { this->pending_configuration_slot = before_slot; From 94123cd726537e860b03928c54c762e2df72e7ca Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Wed, 20 Nov 2024 13:11:47 +0100 Subject: [PATCH 12/15] Improve some logging Signed-off-by: Marc Emmers --- include/ocpp/v201/connectivity_manager.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 526c5a4bd..7ecc736a9 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -85,10 +85,9 @@ class ConnectivityManager { /// void set_configure_network_connection_profile_callback(ConfigureNetworkConnectionProfileCallback callback); - /// \brief Gets the configured NetworkConnectionProfile based on the given \p configuration_slot . The - /// central system uri of the connection options will not contain ws:// or wss:// because this method removes it if - /// present. This returns the value from the cached network connection profiles. \param - /// active_network_configuration_priority \return + /// \brief Gets the cached NetworkConnectionProfile based on the given \p configuration_slot. + /// This returns the value from the cached network connection profiles. + /// \return Returns a profile if the slot is found std::optional get_network_connection_profile(const int32_t configuration_slot); /// \brief Get the priority of the given configuration slot. @@ -130,7 +129,7 @@ class ConnectivityManager { /// This is introduced because the websocket can take several minutes to timeout when a network interface becomes /// unavailable, whereas the system can detect this sooner. /// - /// \param ocpp_interface The interface that is disconnected. + /// \param ocpp_interface The interface that is disconnected. /// void on_network_disconnected(OCPPInterfaceEnum ocpp_interface); @@ -179,14 +178,14 @@ class ConnectivityManager { /// /// \brief Get the network configuration slot of the given priority. - /// \param priority The priority to get the configuration slot. + /// \param priority The priority to get the configuration slot. /// \return The configuration slot. /// int get_configuration_slot_from_priority(const int priority); /// /// \brief Get the next prioritized network configuration slot of the given configuration slot. - /// \param configuration_slot The current configuration slot. + /// \param configuration_slot The current configuration slot. /// \return The next prioritized configuration slot. /// int get_next_configuration_slot(int32_t configuration_slot); From 915864c6ba58fa8c7e655bbcee5bdddfb6d2f197 Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Thu, 21 Nov 2024 14:59:27 +0100 Subject: [PATCH 13/15] Improve const awareness Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 8 ++++---- include/ocpp/v201/connectivity_manager.hpp | 6 +++--- lib/ocpp/v201/charge_point.cpp | 4 ++-- lib/ocpp/v201/connectivity_manager.cpp | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 1c9de4017..e247b6dde 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -352,13 +352,13 @@ class ChargePointInterface { /// present. This returns the value from the cached network connection profiles. \param /// network_configuration_priority \return virtual std::optional - get_network_connection_profile(const int32_t configuration_slot) = 0; + get_network_connection_profile(const int32_t configuration_slot) const = 0; /// \brief Get the priority of the given configuration slot. /// \param configuration_slot The configuration slot to get the priority from. /// \return The priority if the configuration slot exists. /// - virtual std::optional get_priority_from_configuration_slot(const int configuration_slot) = 0; + virtual std::optional get_priority_from_configuration_slot(const int configuration_slot) const = 0; /// @brief Get the network connection slots sorted by priority. /// Each item in the vector contains the configured configuration slots, where the slot with index 0 has the highest @@ -940,9 +940,9 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa std::vector get_all_composite_schedules(const int32_t duration, const ChargingRateUnitEnum& unit) override; - std::optional get_network_connection_profile(const int32_t configuration_slot) override; + std::optional get_network_connection_profile(const int32_t configuration_slot) const override; - std::optional get_priority_from_configuration_slot(const int configuration_slot) override; + std::optional get_priority_from_configuration_slot(const int configuration_slot) const override; const std::vector& get_network_connection_slots() const override; diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 7ecc736a9..80c055a10 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -88,13 +88,13 @@ class ConnectivityManager { /// \brief Gets the cached NetworkConnectionProfile based on the given \p configuration_slot. /// This returns the value from the cached network connection profiles. /// \return Returns a profile if the slot is found - std::optional get_network_connection_profile(const int32_t configuration_slot); + std::optional get_network_connection_profile(const int32_t configuration_slot) const; /// \brief Get the priority of the given configuration slot. /// \param configuration_slot The configuration slot to get the priority from. /// \return The priority if the configuration slot exists. /// - std::optional get_priority_from_configuration_slot(const int configuration_slot); + std::optional get_priority_from_configuration_slot(const int configuration_slot) const; /// @brief Get the network connection slots sorted by priority. /// Each item in the vector contains the configured configuration slots, where the slot with index 0 has the highest @@ -174,7 +174,7 @@ class ConnectivityManager { /// \brief Get the active network configuration slot in use. /// \return The active slot the network is connected to or the pending slot. /// - int get_active_network_configuration_slot(); + int get_active_network_configuration_slot() const; /// /// \brief Get the network configuration slot of the given priority. diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 5eaaf6e6b..3afa446f3 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -4453,11 +4453,11 @@ std::vector ChargePoint::get_all_composite_schedules(const in return composite_schedules; } -std::optional ChargePoint::get_network_connection_profile(const int32_t configuration_slot) { +std::optional ChargePoint::get_network_connection_profile(const int32_t configuration_slot) const { return this->connectivity_manager->get_network_connection_profile(configuration_slot); } -std::optional ChargePoint::get_priority_from_configuration_slot(const int configuration_slot) { +std::optional ChargePoint::get_priority_from_configuration_slot(const int configuration_slot) const { return this->connectivity_manager->get_priority_from_configuration_slot(configuration_slot); } diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 7abd4ebc7..82e39a227 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -71,7 +71,7 @@ void ConnectivityManager::set_configure_network_connection_profile_callback( } std::optional -ConnectivityManager::get_network_connection_profile(const int32_t configuration_slot) { +ConnectivityManager::get_network_connection_profile(const int32_t configuration_slot) const { for (const auto& network_profile : this->cached_network_connection_profiles) { if (network_profile.configurationSlot == configuration_slot) { @@ -88,7 +88,7 @@ ConnectivityManager::get_network_connection_profile(const int32_t configuration_ return std::nullopt; } -std::optional ConnectivityManager::get_priority_from_configuration_slot(const int configuration_slot) { +std::optional ConnectivityManager::get_priority_from_configuration_slot(const int configuration_slot) const { auto it = std::find(this->network_connection_slots.begin(), this->network_connection_slots.end(), configuration_slot); if (it != this->network_connection_slots.end()) { @@ -98,7 +98,7 @@ std::optional ConnectivityManager::get_priority_from_configuration_slot return std::nullopt; } -int ConnectivityManager::get_active_network_configuration_slot() { +int ConnectivityManager::get_active_network_configuration_slot() const { return this->network_connection_slots.at(this->active_network_configuration_priority); } From 1c53a1de3d2978d25e531c4ece28b010ab57979d Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Thu, 21 Nov 2024 15:17:18 +0100 Subject: [PATCH 14/15] Fix linter issues Signed-off-by: Marc Emmers --- include/ocpp/v201/charge_point.hpp | 3 ++- lib/ocpp/v201/charge_point.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index e247b6dde..64631c388 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -940,7 +940,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa std::vector get_all_composite_schedules(const int32_t duration, const ChargingRateUnitEnum& unit) override; - std::optional get_network_connection_profile(const int32_t configuration_slot) const override; + std::optional + get_network_connection_profile(const int32_t configuration_slot) const override; std::optional get_priority_from_configuration_slot(const int configuration_slot) const override; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 3afa446f3..3af2b7dbf 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -4453,7 +4453,8 @@ std::vector ChargePoint::get_all_composite_schedules(const in return composite_schedules; } -std::optional ChargePoint::get_network_connection_profile(const int32_t configuration_slot) const { +std::optional +ChargePoint::get_network_connection_profile(const int32_t configuration_slot) const { return this->connectivity_manager->get_network_connection_profile(configuration_slot); } From a9dbe63dde5286e1acf95ca8b52915171300eb07 Mon Sep 17 00:00:00 2001 From: Marc Emmers Date: Fri, 22 Nov 2024 15:02:28 +0100 Subject: [PATCH 15/15] Fix review comments, allow interface to be nullopt Signed-off-by: Marc Emmers --- include/ocpp/v201/connectivity_manager.hpp | 9 +++--- lib/ocpp/v201/charge_point.cpp | 2 +- lib/ocpp/v201/connectivity_manager.cpp | 35 ++++++++-------------- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/include/ocpp/v201/connectivity_manager.hpp b/include/ocpp/v201/connectivity_manager.hpp index 80c055a10..93b7f4924 100644 --- a/include/ocpp/v201/connectivity_manager.hpp +++ b/include/ocpp/v201/connectivity_manager.hpp @@ -135,7 +135,7 @@ class ConnectivityManager { /// \brief Called when the charging station certificate is changed /// - void on_reconfiguration_of_security_parameters(); + void on_charging_station_certificate_changed(); /// \brief Confirms the connection is successful so the security profile requirements can be handled void confirm_successful_connection(); @@ -154,9 +154,10 @@ class ConnectivityManager { /// \param slot The configuration slot to get the interface for /// \param profile The network connection profile to get the interface for /// - /// \return A string containing the network interface to use, nullptr if the request failed or the callback is not - /// configured - std::optional get_network_configuration_interface(int slot, const NetworkConnectionProfile& profile); + /// \return The network configuration containing the network interface to use, nullptr if the request failed or the + /// callback is not configured + std::optional + handle_configure_network_connection_profile_callback(int slot, const NetworkConnectionProfile& profile); /// \brief Function invoked when the web socket connected with the \p security_profile /// diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 3af2b7dbf..a1852bc65 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -2323,7 +2323,7 @@ void ChargePoint::handle_certificate_signed_req(Call c if (response.status == CertificateSignedStatusEnum::Accepted and cert_signing_use == ocpp::CertificateSigningUseEnum::ChargingStationCertificate and this->device_model->get_value(ControllerComponentVariables::SecurityProfile) == 3) { - this->connectivity_manager->on_reconfiguration_of_security_parameters(); + this->connectivity_manager->on_charging_station_certificate_changed(); const auto& security_event = ocpp::security_events::RECONFIGURATIONOFSECURITYPARAMETERS; std::string tech_info = "Changed charging station certificate"; diff --git a/lib/ocpp/v201/connectivity_manager.cpp b/lib/ocpp/v201/connectivity_manager.cpp index 82e39a227..d06c2de14 100644 --- a/lib/ocpp/v201/connectivity_manager.cpp +++ b/lib/ocpp/v201/connectivity_manager.cpp @@ -185,11 +185,12 @@ void ConnectivityManager::try_connect_websocket() { EVLOG_warning << "Connection profile configured for " << configuration_slot_to_set << " failed: not valid URL"; can_use_connection_profile = false; } else if (this->configure_network_connection_profile_callback.has_value()) { - if (std::optional interface_address = - get_network_configuration_interface(configuration_slot_to_set, network_connection_profile.value()); - interface_address.has_value()) { - connection_options->iface = interface_address; + std::optional config = handle_configure_network_connection_profile_callback( + configuration_slot_to_set, network_connection_profile.value()); + if (config.has_value() && config->success) { + connection_options->iface = config->interface_address; } else { + EVLOG_warning << "Could not use config slot " << configuration_slot_to_set; can_use_connection_profile = false; } } @@ -244,34 +245,24 @@ void ConnectivityManager::try_connect_websocket() { this->websocket->connect(); } -std::optional -ConnectivityManager::get_network_configuration_interface(int slot, const NetworkConnectionProfile& profile) { +std::optional +ConnectivityManager::handle_configure_network_connection_profile_callback(int slot, + const NetworkConnectionProfile& profile) { if (!this->configure_network_connection_profile_callback.has_value()) { return std::nullopt; } - EVLOG_debug << "Request to configure network connection profile " << slot; - std::future config_status = this->configure_network_connection_profile_callback.value()(slot, profile); const int32_t config_timeout = this->device_model.get_optional_value(ControllerComponentVariables::NetworkConfigTimeout) .value_or(default_network_config_timeout_seconds); - switch (config_status.wait_for(std::chrono::seconds(config_timeout))) { - case std::future_status::deferred: - case std::future_status::timeout: - EVLOG_warning << "Timeout configuring config slot: " << slot; - return std::nullopt; - - case std::future_status::ready: - if (ConfigNetworkResult result = config_status.get(); result.success) { - EVLOG_debug << "Config slot " << slot << " is configured"; - return result.interface_address; - } - EVLOG_warning << "Could not configure config slot " << slot; - break; + if (config_status.wait_for(std::chrono::seconds(config_timeout)) == std::future_status::ready) { + return config_status.get(); } + + EVLOG_warning << "Timeout configuring config slot: " << slot; return std::nullopt; } @@ -314,7 +305,7 @@ void ConnectivityManager::on_network_disconnected(OCPPInterfaceEnum ocpp_interfa } } -void ConnectivityManager::on_reconfiguration_of_security_parameters() { +void ConnectivityManager::on_charging_station_certificate_changed() { if (this->websocket != nullptr) { // After the websocket gets closed a reconnect will be triggered this->websocket->disconnect(WebsocketCloseReason::ServiceRestart);