Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OCPP201: Support for TxStartpoint EnergyTransfer #501

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 78 additions & 8 deletions modules/OCPP201/OCPP201.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<std::mutex> lk(this->evse_ready_mutex);
for (size_t evse_id = 1; evse_id <= this->r_evse_manager.size(); evse_id++) {
Expand Down Expand Up @@ -769,6 +788,17 @@ void OCPP201::ready() {
this->config.CoreDatabasePath, sql_init_path.string(), this->config.MessageLogPath,
std::make_shared<EvseSecurity>(*this->r_security), callbacks);

const auto tx_start_point_request_value_response = this->charge_point->request_value<std::string>(
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,
Expand All @@ -783,10 +813,27 @@ 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:
[[fallthrough]];
case TxStartPoint::EnergyTransfer:
this->charge_point->on_session_started(evse_id, connector_id);
break;
}
break;
}
case types::evse_manager::SessionEventEnum::SessionFinished: {
Expand All @@ -809,19 +856,27 @@ 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;
}

if (transaction_started.id_tag.authorization_type == types::authorization::AuthorizationType::OCPP) {
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: {
Expand All @@ -848,6 +903,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;
}
Expand Down
34 changes: 32 additions & 2 deletions modules/OCPP201/OCPP201.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,32 @@

// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1
// insert your custom include headers here
#include <tuple>

#include <ocpp/v201/charge_point.hpp>

enum class TxStartPoint {
ParkingBayOccupancy,
EVConnected,
Authorized,
PowerPathClosed,
EnergyTransfer,
DataSigned
};

struct TransactionStart {
int32_t evse_id;

Check notice on line 41 in modules/OCPP201/OCPP201.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/OCPP201/OCPP201.hpp#L41

struct member 'TransactionStart::evse_id' is never used.
int32_t connector_id;

Check notice on line 42 in modules/OCPP201/OCPP201.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/OCPP201/OCPP201.hpp#L42

struct member 'TransactionStart::connector_id' is never used.
std::string session_id;

Check notice on line 43 in modules/OCPP201/OCPP201.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/OCPP201/OCPP201.hpp#L43

struct member 'TransactionStart::session_id' is never used.
ocpp::DateTime timestamp;
ocpp::v201::TriggerReasonEnum trigger_reason;
ocpp::v201::MeterValue meter_start;
ocpp::v201::IdToken id_token;
std::optional<ocpp::v201::IdToken> group_id_token;
std::optional<int32_t> reservation_id;
std::optional<int32_t> remote_start_id;
ocpp::v201::ChargingStateEnum charging_state;
};
// ev@4bf81b14-a215-475c-a1d3-0a484ae48918:v1

namespace module {
Expand Down Expand Up @@ -89,8 +114,13 @@

// 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<std::pair<int32_t, int32_t>, types::evse_manager::StartSessionReason> session_started_reasons;

Check notice on line 119 in modules/OCPP201/OCPP201.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/OCPP201/OCPP201.hpp#L119

class member 'OCPP201::session_started_reasons' is never used.
std::map<std::pair<int32_t, int32_t>, std::optional<TransactionStart>> transaction_starts;

Check notice on line 120 in modules/OCPP201/OCPP201.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/OCPP201/OCPP201.hpp#L120

class member 'OCPP201::transaction_starts' is never used.

TxStartPoint tx_start_point;

Check notice on line 122 in modules/OCPP201/OCPP201.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

modules/OCPP201/OCPP201.hpp#L122

class member 'OCPP201::tx_start_point' is never used.

std::filesystem::path ocpp_share_path;

// key represents evse_id, value indicates if ready
Expand Down