From c6fa3bbb39a1b2741bbfed92285bc7c5edfb46df Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Thu, 18 Jan 2024 00:13:40 +0100 Subject: [PATCH 1/3] WIP: TxStartPoint EnergyTransfer support Signed-off-by: Kai-Uwe Hermann --- modules/OCPP201/OCPP201.cpp | 87 +++++++++++++++++++++++++++++++++---- modules/OCPP201/OCPP201.hpp | 34 ++++++++++++++- 2 files changed, 111 insertions(+), 10 deletions(-) diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index ff8d0602b..cbfbf6608 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -500,6 +500,25 @@ ocpp::v201::IdToken get_id_token(const types::authorization::ProvidedIdToken& pr return id_token; } +TxStartPoint get_tx_start_point(const std::string& tx_start_point_string) { + if (tx_start_point_string == "ParkingBayOccupancy") { + return TxStartPoint::ParkingBayOccupancy; + } else if (tx_start_point_string == "EVConnected") { + return TxStartPoint::EVConnected; + } else if (tx_start_point_string == "Authorized") { + return TxStartPoint::Authorized; + } else if (tx_start_point_string == "PowerPathClosed") { + return TxStartPoint::PowerPathClosed; + } else if (tx_start_point_string == "EnergyTransfer") { + return TxStartPoint::EnergyTransfer; + } else if (tx_start_point_string == "DataSigned") { + return TxStartPoint::DataSigned; + } + + // default to PowerPathClosed for now + return TxStartPoint::PowerPathClosed; +} + void OCPP201::init_evse_ready_map() { std::lock_guard lk(this->evse_ready_mutex); for (size_t evse_id = 1; evse_id <= this->r_evse_manager.size(); evse_id++) { @@ -769,6 +788,17 @@ void OCPP201::ready() { this->config.CoreDatabasePath, sql_init_path.string(), this->config.MessageLogPath, std::make_shared(*this->r_security), callbacks); + const auto tx_start_point_request_value_response = this->charge_point->request_value( + ocpp::v201::Component{"TxCtrlr"}, ocpp::v201::Variable{"TxStartPoint"}, ocpp::v201::AttributeEnum::Actual); + if (tx_start_point_request_value_response.status == ocpp::v201::GetVariableStatusEnum::Accepted and + tx_start_point_request_value_response.value.has_value()) { + auto tx_start_point_string = tx_start_point_request_value_response.value.value(); + this->tx_start_point = get_tx_start_point(tx_start_point_string); + EVLOG_info << "TxStartPoint from device model: " << tx_start_point_string; + } else { + this->tx_start_point = TxStartPoint::PowerPathClosed; + } + if (this->config.EnableExternalWebsocketControl) { const std::string connect_topic = "everest_api/ocpp/cmd/connect"; this->mqtt.subscribe(connect_topic, @@ -783,10 +813,28 @@ void OCPP201::ready() { for (const auto& evse : this->r_evse_manager) { evse->subscribe_session_event([this, evse_id](types::evse_manager::SessionEvent session_event) { const auto connector_id = session_event.connector_id.value_or(1); + const auto evse_connector = std::make_pair(evse_id, connector_id); switch (session_event.event) { case types::evse_manager::SessionEventEnum::SessionStarted: { - this->session_started_reason = session_event.session_started.value().reason; - this->charge_point->on_session_started(evse_id, connector_id); + if (!session_event.session_started.has_value()) { + this->session_started_reasons[evse_connector] = + types::evse_manager::StartSessionReason::EVConnected; + } else { + this->session_started_reasons[evse_connector] = session_event.session_started.value().reason; + } + + switch (this->tx_start_point) { + case TxStartPoint::EVConnected: + [[fallthrough]]; + case TxStartPoint::Authorized: + [[fallthrough]]; + case TxStartPoint::PowerPathClosed: + this->charge_point->on_session_started(evse_id, connector_id); + break; + case TxStartPoint::EnergyTransfer: + // TODO: does this need a session_started/PlugIn event later? + break; + } break; } case types::evse_manager::SessionEventEnum::SessionFinished: { @@ -809,7 +857,8 @@ void OCPP201::ready() { auto trigger_reason = ocpp::v201::TriggerReasonEnum::Authorized; // if session started reason was Authorized, Transaction is started because of EV plug in event - if (this->session_started_reason == types::evse_manager::StartSessionReason::Authorized) { + if (this->session_started_reasons[evse_connector] == + types::evse_manager::StartSessionReason::Authorized) { trigger_reason = ocpp::v201::TriggerReasonEnum::CablePluggedIn; } @@ -817,11 +866,18 @@ void OCPP201::ready() { trigger_reason = ocpp::v201::TriggerReasonEnum::RemoteStart; } - this->charge_point->on_transaction_started( - evse_id, connector_id, session_id, timestamp, trigger_reason, meter_value, id_token, std::nullopt, - reservation_id, remote_start_id, - ocpp::v201::ChargingStateEnum::EVConnected); // FIXME(piet): add proper groupIdToken + - // ChargingStateEnum + if (this->tx_start_point == TxStartPoint::EnergyTransfer) { + this->transaction_starts[evse_connector].emplace(TransactionStart{ + evse_id, connector_id, session_id, timestamp, trigger_reason, meter_value, id_token, + std::nullopt, reservation_id, remote_start_id, ocpp::v201::ChargingStateEnum::Charging}); + } else { + this->charge_point->on_transaction_started( + evse_id, connector_id, session_id, timestamp, trigger_reason, meter_value, id_token, + std::nullopt, reservation_id, remote_start_id, + ocpp::v201::ChargingStateEnum::EVConnected); // FIXME(piet): add proper groupIdToken + + // ChargingStateEnum + } + break; } case types::evse_manager::SessionEventEnum::TransactionFinished: { @@ -848,6 +904,21 @@ void OCPP201::ready() { break; } case types::evse_manager::SessionEventEnum::ChargingStarted: { + if (this->tx_start_point == TxStartPoint::EnergyTransfer) { + if (this->transaction_starts[evse_connector].has_value()) { + auto transaction_start = this->transaction_starts[evse_connector].value(); + this->charge_point->on_transaction_started( + transaction_start.evse_id, transaction_start.connector_id, transaction_start.session_id, + transaction_start.timestamp, transaction_start.trigger_reason, + transaction_start.meter_start, transaction_start.id_token, transaction_start.group_id_token, + transaction_start.reservation_id, transaction_start.remote_start_id, + transaction_start.charging_state); + this->transaction_starts[evse_connector].reset(); + } else { + EVLOG_error + << "ChargingStarted with TxStartPoint EnergyTransfer but no TransactionStart was available"; + } + } this->charge_point->on_charging_state_changed(evse_id, ocpp::v201::ChargingStateEnum::Charging); break; } diff --git a/modules/OCPP201/OCPP201.hpp b/modules/OCPP201/OCPP201.hpp index b9a2f0218..7d68f0145 100644 --- a/modules/OCPP201/OCPP201.hpp +++ b/modules/OCPP201/OCPP201.hpp @@ -24,7 +24,32 @@ // ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 // insert your custom include headers here +#include + #include + +enum class TxStartPoint { + ParkingBayOccupancy, + EVConnected, + Authorized, + PowerPathClosed, + EnergyTransfer, + DataSigned +}; + +struct TransactionStart { + int32_t evse_id; + int32_t connector_id; + std::string session_id; + ocpp::DateTime timestamp; + ocpp::v201::TriggerReasonEnum trigger_reason; + ocpp::v201::MeterValue meter_start; + ocpp::v201::IdToken id_token; + std::optional group_id_token; + std::optional reservation_id; + std::optional remote_start_id; + ocpp::v201::ChargingStateEnum charging_state; +}; // ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1 namespace module { @@ -89,8 +114,13 @@ class OCPP201 : public Everest::ModuleBase { // ev@211cfdbe-f69a-4cd6-a4ec-f8aaa3d1b6c8:v1 // insert your private definitions here - types::evse_manager::StartSessionReason session_started_reason; // keep track of this to be able to report correct - // trigger reason in TransactionStarted event + // track the session started reasons for every EVSE+Connector combination to be able to report correct trigger + // reason in TransactionStarted event + std::map, types::evse_manager::StartSessionReason> session_started_reasons; + std::map, std::optional> transaction_starts; + + TxStartPoint tx_start_point; + std::filesystem::path ocpp_share_path; // key represents evse_id, value indicates if ready From a9f3db06d366761f5897f0c7f228710770ea420b Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 23 Jan 2024 00:26:58 +0100 Subject: [PATCH 2/3] OCPP201: start session on EnergyTransfer Signed-off-by: Kai-Uwe Hermann # Conflicts: # dependencies.yaml # modules/OCPP201/OCPP201.hpp --- modules/OCPP201/OCPP201.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index cbfbf6608..4ea3a893f 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -832,7 +832,7 @@ void OCPP201::ready() { this->charge_point->on_session_started(evse_id, connector_id); break; case TxStartPoint::EnergyTransfer: - // TODO: does this need a session_started/PlugIn event later? + this->charge_point->on_session_started(evse_id, connector_id); break; } break; From 635231b5661391eddafc64e2c659b4910aacaf0a Mon Sep 17 00:00:00 2001 From: Kai-Uwe Hermann Date: Tue, 23 Jan 2024 00:46:21 +0100 Subject: [PATCH 3/3] fallthrough Signed-off-by: Kai-Uwe Hermann --- modules/OCPP201/OCPP201.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/OCPP201/OCPP201.cpp b/modules/OCPP201/OCPP201.cpp index 4ea3a893f..b90e81e6d 100644 --- a/modules/OCPP201/OCPP201.cpp +++ b/modules/OCPP201/OCPP201.cpp @@ -829,8 +829,7 @@ void OCPP201::ready() { case TxStartPoint::Authorized: [[fallthrough]]; case TxStartPoint::PowerPathClosed: - this->charge_point->on_session_started(evse_id, connector_id); - break; + [[fallthrough]]; case TxStartPoint::EnergyTransfer: this->charge_point->on_session_started(evse_id, connector_id); break;