From 68f2eb992167a601002a36509e533a6c19a879e3 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Sun, 10 Dec 2023 21:41:05 +0100 Subject: [PATCH 1/4] WIP: First draft of an additional evse manager ready signal This is an experimental workaround for the evse manager potentially being ready too early and starting charging sessions before the OCPP 1.6 chargepoint could be initialized A proper fix for this will be done in everest-framework and libocpp Signed-off-by: Kai-Uwe Hermann --- config/config-sil-ocpp.yaml | 1 + interfaces/evse_manager.yaml | 12 + modules/EvseManager/EvseManager.cpp | 8 + modules/EvseManager/EvseManager.hpp | 3 + modules/EvseManager/evse/evse_managerImpl.cpp | 14 + modules/EvseManager/evse/evse_managerImpl.hpp | 1 + modules/EvseManager/manifest.yaml | 4 + modules/OCPP/OCPP.cpp | 285 ++++++++++-------- modules/OCPP/OCPP.hpp | 12 +- 9 files changed, 211 insertions(+), 129 deletions(-) diff --git a/config/config-sil-ocpp.yaml b/config/config-sil-ocpp.yaml index f57108785..d366930c1 100644 --- a/config/config-sil-ocpp.yaml +++ b/config/config-sil-ocpp.yaml @@ -28,6 +28,7 @@ active_modules: ac_hlc_enabled: false ac_hlc_use_5percent: false ac_enforce_hlc: false + external_ready_to_start_charging: true connections: bsp: - module_id: yeti_driver_1 diff --git a/interfaces/evse_manager.yaml b/interfaces/evse_manager.yaml index ecc8ae5a8..c72275355 100644 --- a/interfaces/evse_manager.yaml +++ b/interfaces/evse_manager.yaml @@ -136,6 +136,13 @@ cmds: description: The response raw exi stream and the status from the CSMS system type: object $ref: /iso15118_charger#/Response_Exi_Stream_Status + external_ready_to_start_charging: + description: >- + There are situations where another module needs to do some initialization after evse manager is in principle ready to start charging. + This command can be used (optimally in combination with a configuration option) to delay charging ready until the external module is done with its initialization + result: + description: Returns true if the signal was used by the evse manager implementation + type: boolean vars: session_event: description: Emits all events related to sessions @@ -179,6 +186,11 @@ vars: description: Enforced limits for this node (coming from the EnergyManager) type: object $ref: /energy#/EnforcedLimits + waiting_for_external_ready: + description: >- + Signals that the EVSE Manager is in principle ready to start charging, + but delays sending its ready signal waiting for the external_ready_to_start_charging command. + type: boolean ready: description: Signals that the EVSE Manager is ready to start charging type: boolean diff --git a/modules/EvseManager/EvseManager.cpp b/modules/EvseManager/EvseManager.cpp index ad1fb380f..d65428d23 100644 --- a/modules/EvseManager/EvseManager.cpp +++ b/modules/EvseManager/EvseManager.cpp @@ -846,6 +846,14 @@ void EvseManager::ready() { // start with a limit of 0 amps. We will get a budget from EnergyManager that is locally limited by hw // caps. charger->setMaxCurrent(0.0F, date::utc_clock::now() + std::chrono::seconds(10)); + this->p_evse->publish_waiting_for_external_ready(config.external_ready_to_start_charging); + if (!config.external_ready_to_start_charging) { + // immediately ready, otherwise delay until we get the external signal + this->ready_to_start_charging(); + } +} + +void EvseManager::ready_to_start_charging() { charger->run(); charger->enable(0); diff --git a/modules/EvseManager/EvseManager.hpp b/modules/EvseManager/EvseManager.hpp index 2f24669d4..0206ac09c 100644 --- a/modules/EvseManager/EvseManager.hpp +++ b/modules/EvseManager/EvseManager.hpp @@ -83,6 +83,7 @@ struct Conf { bool sae_j2847_2_bpt_enabled; std::string sae_j2847_2_bpt_mode; bool request_zero_power_in_idle; + bool external_ready_to_start_charging; }; class EvseManager : public Everest::ModuleBase { @@ -163,6 +164,8 @@ class EvseManager : public Everest::ModuleBase { std::string selected_protocol = "Unknown"; std::atomic_bool sae_bidi_active{false}; + + void ready_to_start_charging(); // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 protected: diff --git a/modules/EvseManager/evse/evse_managerImpl.cpp b/modules/EvseManager/evse/evse_managerImpl.cpp index dce4c445d..ec6b285ce 100644 --- a/modules/EvseManager/evse/evse_managerImpl.cpp +++ b/modules/EvseManager/evse/evse_managerImpl.cpp @@ -391,5 +391,19 @@ void evse_managerImpl::handle_set_get_certificate_response( mod->r_hlc[0]->call_certificate_response(certificate_reponse); } +bool evse_managerImpl::handle_external_ready_to_start_charging() { + if (mod->config.external_ready_to_start_charging) { + EVLOG_info << "Recived external ready to start charging command."; + mod->ready_to_start_charging(); + return true; + } else { + EVLOG_warning + << "Ignoring external ready to start charging command, this could be a configuration issue. Please check " + "if 'external_ready_to_start_charging' is set to true if you want to use this feature."; + } + + return false; +} + } // namespace evse } // namespace module diff --git a/modules/EvseManager/evse/evse_managerImpl.hpp b/modules/EvseManager/evse/evse_managerImpl.hpp index 205519037..a9af2dfa7 100644 --- a/modules/EvseManager/evse/evse_managerImpl.hpp +++ b/modules/EvseManager/evse/evse_managerImpl.hpp @@ -52,6 +52,7 @@ class evse_managerImpl : public evse_managerImplBase { handle_switch_three_phases_while_charging(bool& three_phases) override; virtual void handle_set_get_certificate_response( types::iso15118_charger::Response_Exi_Stream_Status& certificate_response) override; + virtual bool handle_external_ready_to_start_charging() override; // ev@d2d1847a-7b88-41dd-ad07-92785f06f5c4:v1 // insert your protected definitions here diff --git a/modules/EvseManager/manifest.yaml b/modules/EvseManager/manifest.yaml index a96856cc0..b694eceaf 100644 --- a/modules/EvseManager/manifest.yaml +++ b/modules/EvseManager/manifest.yaml @@ -202,6 +202,10 @@ config: "EvseManager does not need to wait for energy from the energy manager after plug in." type: boolean default: false + external_ready_to_start_charging: + description: Enable the external ready to start charging signal that delays charging ready until it has been received + type: boolean + default: false provides: evse: interface: evse_manager diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index 6549327af..309830962 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -141,6 +141,137 @@ void OCPP::publish_charging_schedules(const std::mapp_ocpp_generic->publish_charging_schedules(j); } +void OCPP::process_session_event(int32_t evse_id, const types::evse_manager::SessionEvent& session_event) { + auto event = types::evse_manager::session_event_enum_to_string(session_event.event); + + auto everest_connector_id = session_event.connector_id.value_or(1); + auto ocpp_connector_id = this->evse_connector_map[evse_id][everest_connector_id]; + + if (event == "Enabled") { + this->charge_point->on_enabled(evse_id); + } else if (event == "Disabled") { + EVLOG_debug << "EVSE#" << evse_id << ": " + << "Received Disabled"; + this->charge_point->on_disabled(evse_id); + } else if (event == "TransactionStarted") { + EVLOG_info << "EVSE#" << evse_id << ": " + << "Received TransactionStarted"; + const auto transaction_started = session_event.transaction_started.value(); + + const auto timestamp = ocpp::DateTime(transaction_started.timestamp); + const auto energy_Wh_import = transaction_started.meter_value.energy_Wh_import.total; + const auto session_id = session_event.uuid; + const auto id_token = transaction_started.id_tag.id_token; + const auto signed_meter_value = transaction_started.signed_meter_value; + std::optional reservation_id_opt = std::nullopt; + if (transaction_started.reservation_id) { + reservation_id_opt.emplace(transaction_started.reservation_id.value()); + } + this->charge_point->on_transaction_started(ocpp_connector_id, session_event.uuid, id_token, energy_Wh_import, + reservation_id_opt, timestamp, signed_meter_value); + } else if (event == "ChargingPausedEV") { + EVLOG_debug << "Connector#" << ocpp_connector_id << ": " + << "Received ChargingPausedEV"; + this->charge_point->on_suspend_charging_ev(ocpp_connector_id); + } else if (event == "ChargingPausedEVSE" or event == "WaitingForEnergy") { + EVLOG_debug << "Connector#" << ocpp_connector_id << ": " + << "Received ChargingPausedEVSE"; + this->charge_point->on_suspend_charging_evse(ocpp_connector_id); + } else if (event == "ChargingStarted" || event == "ChargingResumed") { + EVLOG_debug << "Connector#" << ocpp_connector_id << ": " + << "Received ChargingResumed"; + this->charge_point->on_resume_charging(ocpp_connector_id); + } else if (event == "TransactionFinished") { + EVLOG_debug << "Connector#" << ocpp_connector_id << ": " + << "Received TransactionFinished"; + const auto transaction_finished = session_event.transaction_finished.value(); + const auto timestamp = ocpp::DateTime(transaction_finished.timestamp); + const auto energy_Wh_import = transaction_finished.meter_value.energy_Wh_import.total; + const auto reason = ocpp::v16::conversions::string_to_reason( + types::evse_manager::stop_transaction_reason_to_string(transaction_finished.reason.value())); + const auto signed_meter_value = transaction_finished.signed_meter_value; + std::optional> id_tag_opt = std::nullopt; + if (transaction_finished.id_tag) { + id_tag_opt.emplace(ocpp::CiString<20>(transaction_finished.id_tag.value())); + } + this->charge_point->on_transaction_stopped(ocpp_connector_id, session_event.uuid, reason, timestamp, + energy_Wh_import, id_tag_opt, signed_meter_value); + // always triggered by libocpp + } else if (event == "SessionStarted") { + EVLOG_info << "Connector#" << ocpp_connector_id << ": " + << "Received SessionStarted"; + // ev side disconnect + auto session_started = session_event.session_started.value(); + this->charge_point->on_session_started( + ocpp_connector_id, session_event.uuid, + types::evse_manager::start_session_reason_to_string(session_started.reason), session_started.logging_path); + } else if (event == "SessionFinished") { + EVLOG_debug << "Connector#" << ocpp_connector_id << ": " + << "Received SessionFinished"; + // ev side disconnect + this->charge_point->on_session_stopped(ocpp_connector_id, session_event.uuid); + } else if (event == "Error") { + EVLOG_debug << "Connector#" << ocpp_connector_id << ": " + << "Received Error"; + const auto evse_error = types::evse_manager::error_enum_to_string(session_event.error.value().error_code); + ocpp::v16::ChargePointErrorCode ocpp_error_code = get_ocpp_error_code(evse_error); + this->charge_point->on_error(ocpp_connector_id, ocpp_error_code); + } else if (event == "AllErrorsCleared") { + this->charge_point->on_fault(ocpp_connector_id, ocpp::v16::ChargePointErrorCode::NoError); + } else if (event == "PermanentFault") { + const auto evse_error = types::evse_manager::error_enum_to_string(session_event.error.value().error_code); + ocpp::v16::ChargePointErrorCode ocpp_error_code = get_ocpp_error_code(evse_error); + this->charge_point->on_fault(ocpp_connector_id, ocpp_error_code); + } else if (event == "ReservationStart") { + this->charge_point->on_reservation_start(ocpp_connector_id); + } else if (event == "ReservationEnd") { + this->charge_point->on_reservation_end(ocpp_connector_id); + } else if (event == "ReservationAuthtokenMismatch") { + } else if (event == "PluginTimeout") { + this->charge_point->on_plugin_timeout(ocpp_connector_id); + } +} + +void OCPP::init_evse_subscriptions() { + int32_t evse_id = 1; + for (auto& evse : this->r_evse_manager) { + evse->subscribe_powermeter([this, evse_id](types::powermeter::Powermeter powermeter) { + json powermeter_json = powermeter; + this->charge_point->on_meter_values(evse_id, powermeter_json); // + }); + + evse->subscribe_limits([this, evse_id](types::evse_manager::Limits limits) { + double max_current = limits.max_current; + this->charge_point->on_max_current_offered(evse_id, max_current); + }); + + evse->subscribe_session_event([this, evse_id](types::evse_manager::SessionEvent session_event) { + if (this->ocpp_stopped) { + // dont call any on handler in case ocpp is stopped + return; + } + + if (!this->started) { + EVLOG_error << "OCPP not fully initialized, but received a session event on evse_id: " << evse_id + << " that will be discarded: " << session_event.event; + return; + } + + this->process_session_event(evse_id, session_event); + }); + + evse->subscribe_iso15118_certificate_request( + [this, evse_id](types::iso15118_charger::Request_Exi_Stream_Schema request) { + this->charge_point->data_transfer_pnc_get_15118_ev_certificate( + evse_id, request.exiRequest, request.iso15118SchemaVersion, + ocpp::v201::conversions::string_to_certificate_action_enum( + types::iso15118_charger::certificate_action_enum_to_string(request.certificateAction))); + }); + + evse_id++; + } +} + void OCPP::init_evse_connector_map() { int32_t ocpp_connector_id = 1; // this represents the OCPP connector id int32_t evse_id = 1; // this represents the evse id of EVerests evse manager @@ -212,9 +343,23 @@ void OCPP::init() { this->init_evse_ready_map(); for (size_t evse_id = 1; evse_id <= this->r_evse_manager.size(); evse_id++) { + this->r_evse_manager.at(evse_id - 1)->subscribe_waiting_for_external_ready([this, evse_id](bool ready) { + std::lock_guard lk(this->evse_ready_mutex); + if (ready) { + this->evse_ready_map[evse_id] = true; + this->evse_ready_cv.notify_one(); + } + }); + + // also use the the ready signal, TODO(kai): maybe warn about it's usage here` this->r_evse_manager.at(evse_id - 1)->subscribe_ready([this, evse_id](bool ready) { std::lock_guard lk(this->evse_ready_mutex); if (ready) { + if (!this->evse_ready_map[evse_id]) { + EVLOG_error << "Received EVSE ready without receiving waiting_for_external_ready first, this is " + "probably a bug in your evse_manager implementation / configuration. evse_id: " + << evse_id; + } this->evse_ready_map[evse_id] = true; this->evse_ready_cv.notify_one(); } @@ -283,6 +428,8 @@ void OCPP::init() { std::make_shared(*this->r_security)); this->charge_point->set_message_queue_resume_delay(std::chrono::seconds(config.MessageQueueResumeDelay)); + + this->init_evse_subscriptions(); // initialize EvseManager subscriptions as early as possible } void OCPP::ready() { @@ -443,6 +590,7 @@ void OCPP::ready() { this->r_system->call_allow_firmware_installation(); }); + // FIXME(kai): subscriptions should be as early as possible this->r_system->subscribe_log_status([this](types::system::LogStatus log_status) { this->charge_point->on_log_status_notification(log_status.request_id, types::system::log_status_enum_to_string(log_status.log_status)); @@ -478,6 +626,8 @@ void OCPP::ready() { this->charge_point->register_enable_evse_callback([this](int32_t connector) { if (this->connector_evse_index_map.count(connector)) { + // FIXME(kai): these callbacks can already be called from within libocpp during its startup, so we might see + // some issues here... return this->r_evse_manager.at(this->connector_evse_index_map.at(connector))->call_enable(0); } else { return false; @@ -568,134 +718,21 @@ void OCPP::ready() { }); } - int32_t evse_id = 1; - for (auto& evse : this->r_evse_manager) { - evse->subscribe_powermeter([this, evse_id](types::powermeter::Powermeter powermeter) { - json powermeter_json = powermeter; - this->charge_point->on_meter_values(evse_id, powermeter_json); // - }); - - evse->subscribe_limits([this, evse_id](types::evse_manager::Limits limits) { - double max_current = limits.max_current; - this->charge_point->on_max_current_offered(evse_id, max_current); - }); - - evse->subscribe_session_event([this, evse_id](types::evse_manager::SessionEvent session_event) { - if (this->ocpp_stopped) { - // dont call any on handler in case ocpp is stopped - return; - } - - auto event = types::evse_manager::session_event_enum_to_string(session_event.event); - - auto everest_connector_id = session_event.connector_id.value_or(1); - auto ocpp_connector_id = this->evse_connector_map[evse_id][everest_connector_id]; - - if (event == "Enabled") { - this->charge_point->on_enabled(evse_id); - } else if (event == "Disabled") { - EVLOG_debug << "EVSE#" << evse_id << ": " - << "Received Disabled"; - this->charge_point->on_disabled(evse_id); - } else if (event == "TransactionStarted") { - EVLOG_debug << "EVSE#" << evse_id << ": " - << "Received TransactionStarted"; - const auto transaction_started = session_event.transaction_started.value(); - - const auto timestamp = ocpp::DateTime(transaction_started.timestamp); - const auto energy_Wh_import = transaction_started.meter_value.energy_Wh_import.total; - const auto session_id = session_event.uuid; - const auto id_token = transaction_started.id_tag.id_token; - const auto signed_meter_value = transaction_started.signed_meter_value; - std::optional reservation_id_opt = std::nullopt; - if (transaction_started.reservation_id) { - reservation_id_opt.emplace(transaction_started.reservation_id.value()); - } - this->charge_point->on_transaction_started(ocpp_connector_id, session_event.uuid, id_token, - energy_Wh_import, reservation_id_opt, timestamp, - signed_meter_value); - } else if (event == "ChargingPausedEV") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received ChargingPausedEV"; - this->charge_point->on_suspend_charging_ev(ocpp_connector_id); - } else if (event == "ChargingPausedEVSE" or event == "WaitingForEnergy") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received ChargingPausedEVSE"; - this->charge_point->on_suspend_charging_evse(ocpp_connector_id); - } else if (event == "ChargingStarted" || event == "ChargingResumed") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received ChargingResumed"; - this->charge_point->on_resume_charging(ocpp_connector_id); - } else if (event == "TransactionFinished") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received TransactionFinished"; - const auto transaction_finished = session_event.transaction_finished.value(); - const auto timestamp = ocpp::DateTime(transaction_finished.timestamp); - const auto energy_Wh_import = transaction_finished.meter_value.energy_Wh_import.total; - const auto reason = ocpp::v16::conversions::string_to_reason( - types::evse_manager::stop_transaction_reason_to_string(transaction_finished.reason.value())); - const auto signed_meter_value = transaction_finished.signed_meter_value; - std::optional> id_tag_opt = std::nullopt; - if (transaction_finished.id_tag) { - id_tag_opt.emplace(ocpp::CiString<20>(transaction_finished.id_tag.value())); - } - this->charge_point->on_transaction_stopped(ocpp_connector_id, session_event.uuid, reason, timestamp, - energy_Wh_import, id_tag_opt, signed_meter_value); - // always triggered by libocpp - } else if (event == "SessionStarted") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received SessionStarted"; - // ev side disconnect - auto session_started = session_event.session_started.value(); - this->charge_point->on_session_started( - ocpp_connector_id, session_event.uuid, - types::evse_manager::start_session_reason_to_string(session_started.reason), - session_started.logging_path); - } else if (event == "SessionFinished") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received SessionFinished"; - // ev side disconnect - this->charge_point->on_session_stopped(ocpp_connector_id, session_event.uuid); - } else if (event == "Error") { - EVLOG_debug << "Connector#" << ocpp_connector_id << ": " - << "Received Error"; - const auto evse_error = - types::evse_manager::error_enum_to_string(session_event.error.value().error_code); - ocpp::v16::ChargePointErrorCode ocpp_error_code = get_ocpp_error_code(evse_error); - this->charge_point->on_error(ocpp_connector_id, ocpp_error_code); - } else if (event == "AllErrorsCleared") { - this->charge_point->on_fault(ocpp_connector_id, ocpp::v16::ChargePointErrorCode::NoError); - } else if (event == "PermanentFault") { - const auto evse_error = - types::evse_manager::error_enum_to_string(session_event.error.value().error_code); - ocpp::v16::ChargePointErrorCode ocpp_error_code = get_ocpp_error_code(evse_error); - this->charge_point->on_fault(ocpp_connector_id, ocpp_error_code); - } else if (event == "ReservationStart") { - this->charge_point->on_reservation_start(ocpp_connector_id); - } else if (event == "ReservationEnd") { - this->charge_point->on_reservation_end(ocpp_connector_id); - } else if (event == "ReservationAuthtokenMismatch") { - } else if (event == "PluginTimeout") { - this->charge_point->on_plugin_timeout(ocpp_connector_id); - } - }); - - evse->subscribe_iso15118_certificate_request( - [this, evse_id](types::iso15118_charger::Request_Exi_Stream_Schema request) { - this->charge_point->data_transfer_pnc_get_15118_ev_certificate( - evse_id, request.exiRequest, request.iso15118SchemaVersion, - ocpp::v201::conversions::string_to_certificate_action_enum( - types::iso15118_charger::certificate_action_enum_to_string(request.certificateAction))); - }); - - evse_id++; - } - std::unique_lock lk(this->evse_ready_mutex); while (!this->all_evse_ready()) { this->evse_ready_cv.wait(lk); } - this->charge_point->start(); + + if (this->charge_point->start()) { + // signal that we're started + this->started = true; + EVLOG_info << "OCPP initialized"; + } + + // signal to the EVSEs that OCPP is initialized + for (const auto& evse : this->r_evse_manager) { + evse->call_external_ready_to_start_charging(); + } } } // namespace module diff --git a/modules/OCPP/OCPP.hpp b/modules/OCPP/OCPP.hpp index 881364072..6066a8f0a 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -33,7 +33,10 @@ #include #include #include +#include #include +#include + #include #include #include @@ -104,7 +107,6 @@ class OCPP : public Everest::ModuleBase { // insert your public definitions here std::unique_ptr charge_point; std::unique_ptr charging_schedules_timer; - bool started = false; bool ocpp_stopped = false; // ev@1fce4c5e-0ab8-41bb-90f7-14277703d2ac:v1 @@ -123,11 +125,8 @@ class OCPP : public Everest::ModuleBase { std::filesystem::path ocpp_share_path; void set_external_limits(const std::map& charging_schedules); void publish_charging_schedules(const std::map& charging_schedules); - std::thread upload_diagnostics_thread; - std::thread upload_logs_thread; - std::thread update_firmware_thread; - std::thread signed_update_firmware_thread; + void init_evse_subscriptions(); // initialize subscriptions to all EVSEs provided by r_evse_manager void init_evse_connector_map(); void init_evse_ready_map(); EvseConnectorMap evse_connector_map; // provides access to OCPP connector id by using EVerests evse and connector id @@ -137,6 +136,9 @@ class OCPP : public Everest::ModuleBase { std::mutex evse_ready_mutex; std::condition_variable evse_ready_cv; bool all_evse_ready(); + + std::atomic_bool started{false}; + void process_session_event(int32_t evse_id, const types::evse_manager::SessionEvent& session_event); // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 }; From 7009ea91ee74484aa4e74f5bfedd4a1468b044ec Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Mon, 11 Dec 2023 19:15:15 +0100 Subject: [PATCH 2/4] Set external_ready_to_start_charging: true in second evse manager Signed-off-by: Kai-Uwe Hermann --- config/config-sil-ocpp.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config-sil-ocpp.yaml b/config/config-sil-ocpp.yaml index d366930c1..bf3d22fe5 100644 --- a/config/config-sil-ocpp.yaml +++ b/config/config-sil-ocpp.yaml @@ -57,6 +57,7 @@ active_modules: ac_hlc_enabled: false ac_hlc_use_5percent: false ac_enforce_hlc: false + external_ready_to_start_charging: true connections: bsp: - module_id: yeti_driver_2 From 5dcaf4228e214d6e59ae69bc74abb7c06c6ee324 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Mon, 11 Dec 2023 19:15:24 +0100 Subject: [PATCH 3/4] Fixed typo Signed-off-by: Kai-Uwe Hermann --- modules/EvseManager/evse/evse_managerImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/EvseManager/evse/evse_managerImpl.cpp b/modules/EvseManager/evse/evse_managerImpl.cpp index ec6b285ce..8da41e77e 100644 --- a/modules/EvseManager/evse/evse_managerImpl.cpp +++ b/modules/EvseManager/evse/evse_managerImpl.cpp @@ -393,7 +393,7 @@ void evse_managerImpl::handle_set_get_certificate_response( bool evse_managerImpl::handle_external_ready_to_start_charging() { if (mod->config.external_ready_to_start_charging) { - EVLOG_info << "Recived external ready to start charging command."; + EVLOG_info << "Received external ready to start charging command."; mod->ready_to_start_charging(); return true; } else { From 9c43e7ae0e5f9daa034f960a1ee99ad77e204219 Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Mon, 11 Dec 2023 19:20:58 +0100 Subject: [PATCH 4/4] Queue up session events in OCPP 1.6 module before initialization Signed-off-by: Kai-Uwe Hermann --- modules/OCPP/OCPP.cpp | 20 ++++++++++++++++---- modules/OCPP/OCPP.hpp | 2 ++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/modules/OCPP/OCPP.cpp b/modules/OCPP/OCPP.cpp index 309830962..a7c43583a 100644 --- a/modules/OCPP/OCPP.cpp +++ b/modules/OCPP/OCPP.cpp @@ -252,8 +252,10 @@ void OCPP::init_evse_subscriptions() { } if (!this->started) { - EVLOG_error << "OCPP not fully initialized, but received a session event on evse_id: " << evse_id - << " that will be discarded: " << session_event.event; + EVLOG_info << "OCPP not fully initialized, but received a session event on evse_id: " << evse_id + << " that will be queued up: " << session_event.event; + std::scoped_lock lock(this->session_event_mutex); + this->session_event_queue[evse_id].push(session_event); return; } @@ -626,8 +628,6 @@ void OCPP::ready() { this->charge_point->register_enable_evse_callback([this](int32_t connector) { if (this->connector_evse_index_map.count(connector)) { - // FIXME(kai): these callbacks can already be called from within libocpp during its startup, so we might see - // some issues here... return this->r_evse_manager.at(this->connector_evse_index_map.at(connector))->call_enable(0); } else { return false; @@ -727,6 +727,18 @@ void OCPP::ready() { // signal that we're started this->started = true; EVLOG_info << "OCPP initialized"; + + // process session event queue + std::scoped_lock lock(this->session_event_mutex); + for (auto& [evse_id, evse_session_event_queue] : this->session_event_queue) { + while (!evse_session_event_queue.empty()) { + auto queued_session_event = evse_session_event_queue.front(); + EVLOG_info << "Processing queued session event for evse_id: " << evse_id + << ", event: " << queued_session_event.event; + this->process_session_event(evse_id, queued_session_event); + evse_session_event_queue.pop(); + } + } } // signal to the EVSEs that OCPP is initialized diff --git a/modules/OCPP/OCPP.hpp b/modules/OCPP/OCPP.hpp index 6066a8f0a..c4f13fd79 100644 --- a/modules/OCPP/OCPP.hpp +++ b/modules/OCPP/OCPP.hpp @@ -138,6 +138,8 @@ class OCPP : public Everest::ModuleBase { bool all_evse_ready(); std::atomic_bool started{false}; + std::mutex session_event_mutex; + std::map> session_event_queue; void process_session_event(int32_t evse_id, const types::evse_manager::SessionEvent& session_event); // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 };