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

Allow resuming of transactions for OCPP1.6 #704

Merged
merged 3 commits into from
Jul 31, 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
10 changes: 8 additions & 2 deletions include/ocpp/v16/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,15 @@ class ChargePoint {
/// (Available, Unavailable, Faulted). connector_status_map is empty, last availability states from the persistant
/// storage will be used
/// \param bootreason reason for calling the start function
/// \return
/// \param resuming_session_ids can optionally contain active session ids from previous executions. If empty and
/// libocpp has transactions in its internal database that have not been stopped yet, calling this function will
/// initiate a StopTransaction.req for those transactions. If this vector contains session_ids this function will
/// not stop transactions with this session_id even in case it has an internal database entry for this session and
/// it hasnt been stopped yet. Its ignored if this vector contains session_ids that are unknown to libocpp.
/// \return
bool start(const std::map<int, ChargePointStatus>& connector_status_map = {},
BootReasonEnum bootreason = BootReasonEnum::PowerUp);
BootReasonEnum bootreason = BootReasonEnum::PowerUp,
const std::set<std::string>& resuming_session_ids = {});

/// \brief Restarts the ChargePoint if it has been stopped before. The ChargePoint is reinitialized, connects to the
/// websocket and starts to communicate OCPP messages again
Expand Down
19 changes: 14 additions & 5 deletions include/ocpp/v16/charge_point_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,16 +232,19 @@ class ChargePointImpl : ocpp::ChargingStationBase {
/// update can proceed
void change_all_connectors_to_unavailable_for_firmware_update();

/// \brief Tries to resume the transactions given by \p resuming_session_ids . This function retrieves open
/// transactions from the internal database (e.g. because of power loss). In case the \p
/// resuming_session_ids contain the internal session_id, this function attempts to resume the transaction by
/// initializing it and adding it to the \ref transaction_handler. If the session_id is not part of \p
/// resuming_session_ids a StopTransaction.req is initiated to properly close the transaction.
void try_resume_transactions(const std::set<std::string>& resuming_session_ids);
void stop_all_transactions();
void stop_all_transactions(Reason reason);
bool validate_against_cache_entries(CiString<20> id_tag);

// new transaction handling:
void start_transaction(std::shared_ptr<Transaction> transaction);

/// \brief Sends StopTransaction.req for all transactions for which meter_stop or time_end is not set in the
/// database's Transaction table
void stop_pending_transactions();
void stop_transaction(int32_t connector, Reason reason, std::optional<CiString<20>> id_tag_end);

/// \brief Converts the given \p measurands_csv to a vector of Measurands
Expand Down Expand Up @@ -382,8 +385,14 @@ class ChargePointImpl : ocpp::ChargingStationBase {
/// \param connector_status_map initial state of connectors including connector 0 with reduced set of states
/// (Available, Unavailable, Faulted)
/// \param bootreason reason for calling the start function
/// \return
bool start(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason);
/// \param resuming_session_ids can optionally contain active session ids from previous executions. If empty and
/// libocpp has transactions in its internal database that have not been stopped yet, calling this function will
/// initiate a StopTransaction.req for those transactions. If this vector contains session_ids this function will
/// not stop transactions with this session_id even in case it has an internal database entry for this session and
/// it hasnt been stopped yet. Its ignored if this vector contains session_ids that are unknown to libocpp.
/// \return
bool start(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason,
const std::set<std::string>& resuming_session_ids);

/// \brief Restarts the ChargePoint if it has been stopped before. The ChargePoint is reinitialized, connects to the
/// websocket and starts to communicate OCPP messages again
Expand Down
5 changes: 3 additions & 2 deletions lib/ocpp/v16/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ ChargePoint::ChargePoint(const std::string& config, const fs::path& share_path,

ChargePoint::~ChargePoint() = default;

bool ChargePoint::start(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason) {
return this->charge_point->start(connector_status_map, bootreason);
bool ChargePoint::start(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason,
const std::set<std::string>& resuming_session_ids) {
return this->charge_point->start(connector_status_map, bootreason, resuming_session_ids);
}

bool ChargePoint::restart(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason) {
Expand Down
33 changes: 21 additions & 12 deletions lib/ocpp/v16/charge_point_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ void ChargePointImpl::update_clock_aligned_meter_values_interval() {
}
}

void ChargePointImpl::stop_pending_transactions() {
void ChargePointImpl::try_resume_transactions(const std::set<std::string>& resuming_session_ids) {
std::vector<ocpp::v16::TransactionEntry> transactions;
try {
transactions = this->database_handler->get_transactions(true);
Expand Down Expand Up @@ -395,16 +395,24 @@ void ChargePointImpl::stop_pending_transactions() {

this->transaction_handler->add_transaction(transaction);

// StopTransaction.req is not yet queued for the transaction in the database, so we add the transaction to
// the transaction_handler and initiate a StopTransaction.req
if (!this->message_queue->contains_stop_transaction_message(transaction_entry.transaction_id)) {
EVLOG_info << "Queuing StopTransaction.req for transaction with id: " << transaction_entry.transaction_id
<< " because it hasn't been acknowledged by CSMS.";
this->stop_transaction(transaction_entry.connector, Reason::PowerLoss, std::nullopt);
} else {
// mark the transaction as stopped
EVLOG_info << "Trying to resume transaction with session_id: " << transaction_entry.session_id
<< " and transaction_id: " << transaction_entry.transaction_id;

if (this->message_queue->contains_stop_transaction_message(transaction_entry.transaction_id)) {
// StopTransaction.req is already queued for the transaction in the database, so we mark the transaction as
// stopped and wait for the StopTransaction.conf
transaction->set_finished();
this->transaction_handler->add_stopped_transaction(transaction->get_connector());
} else {
if (std::find(resuming_session_ids.begin(), resuming_session_ids.end(), transaction_entry.session_id) ==
resuming_session_ids.end()) {
EVLOG_info << "Queuing StopTransaction.req for transaction with id: "
<< transaction_entry.transaction_id
<< " because it hasn't been acknowledged by CSMS and shall not be resumed.";
this->stop_transaction(transaction_entry.connector, Reason::PowerLoss, std::nullopt);
} else {
EVLOG_info << "Resuming transaction with transaction id: " << transaction_entry.transaction_id;
}
}
}
}
Expand Down Expand Up @@ -855,7 +863,8 @@ void ChargePointImpl::send_meter_value(int32_t connector, MeterValue meter_value
this->send<MeterValuesRequest>(call, initiated_by_trigger_message);
}

bool ChargePointImpl::start(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason) {
bool ChargePointImpl::start(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason,
const std::set<std::string>& resuming_session_ids) {
this->message_queue->start();
this->bootreason = bootreason;
this->init_state_machine(connector_status_map);
Expand All @@ -864,7 +873,7 @@ bool ChargePointImpl::start(const std::map<int, ChargePointStatus>& connector_st
// push transaction messages including SecurityEventNotification.req onto the message queue
this->message_queue->get_persisted_messages_from_db(this->configuration->getDisableSecurityEventNotifications());
this->boot_notification();
this->stop_pending_transactions();
this->try_resume_transactions(resuming_session_ids);
this->load_charging_profiles();
this->call_set_connection_timeout();

Expand Down Expand Up @@ -903,7 +912,7 @@ bool ChargePointImpl::restart(const std::map<int, ChargePointStatus>& connector_
this->database_handler->open_connection();
// instantiating new message queue on restart
this->message_queue = this->create_message_queue();
return this->start(connector_status_map, bootreason);
return this->start(connector_status_map, bootreason, {});
} else {
EVLOG_warning << "Attempting to restart Chargepoint while it has not been stopped before";
return false;
Expand Down
Loading