Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1) - OpenOCPP extracted (firmware OCPP 1.6J/2.0.1) - ShapeShifter library installed (pip install -e) - ShapeShifter specification extracted - EVerest extracted TODO updated with progress
This commit is contained in:
349
tools/EVerest-main/modules/EVSE/Auth/include/AuthHandler.hpp
Normal file
349
tools/EVerest-main/modules/EVSE/Auth/include/AuthHandler.hpp
Normal file
@@ -0,0 +1,349 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#ifndef _AUTH_HANDLER_HPP_
|
||||
#define _AUTH_HANDLER_HPP_
|
||||
|
||||
#include <condition_variable>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
#include <utils/types.hpp>
|
||||
|
||||
#include <generated/types/authorization.hpp>
|
||||
#include <generated/types/evse_manager.hpp>
|
||||
#include <generated/types/reservation.hpp>
|
||||
#include <generated/types/text_message.hpp>
|
||||
|
||||
#include <Connector.hpp>
|
||||
#include <ReservationHandler.hpp>
|
||||
|
||||
using namespace types::evse_manager;
|
||||
using namespace types::authorization;
|
||||
using namespace types::reservation;
|
||||
using namespace types::text_message;
|
||||
|
||||
namespace types {
|
||||
namespace authorization {
|
||||
|
||||
inline bool operator<(const IdToken& lhs, const IdToken& rhs) {
|
||||
return lhs.value < rhs.value;
|
||||
}
|
||||
|
||||
inline bool operator<(const ProvidedIdToken& lhs, const ProvidedIdToken& rhs) {
|
||||
return lhs.id_token < rhs.id_token;
|
||||
}
|
||||
|
||||
} // namespace authorization
|
||||
} // namespace types
|
||||
|
||||
namespace module {
|
||||
|
||||
enum class TokenHandlingResult {
|
||||
ALREADY_IN_PROCESS,
|
||||
REJECTED,
|
||||
USED_TO_START_TRANSACTION,
|
||||
USED_TO_STOP_TRANSACTION,
|
||||
TIMEOUT,
|
||||
NO_CONNECTOR_AVAILABLE,
|
||||
WITHDRAWN
|
||||
};
|
||||
|
||||
namespace conversions {
|
||||
std::string token_handling_result_to_string(const TokenHandlingResult& result);
|
||||
} // namespace conversions
|
||||
|
||||
/**
|
||||
* @brief This class handles authorization and reservation requests. It keeps track of the state of each connector and
|
||||
* validates incoming token and reservation requests accordingly.
|
||||
*
|
||||
*/
|
||||
class AuthHandler {
|
||||
|
||||
public:
|
||||
AuthHandler(const SelectionAlgorithm& selection_algorithm, const int connection_timeout,
|
||||
bool plug_in_timeout_enabled, bool prioritize_authorization_over_stopping_transaction,
|
||||
bool ignore_connector_faults, const std::string& id, kvsIntf* store);
|
||||
virtual ~AuthHandler();
|
||||
|
||||
/**
|
||||
* @brief Initializes the evse with the given \p connectors and the given \p evse_id . It instantiates new
|
||||
* connector objects and fills data sturctures of the class.
|
||||
*
|
||||
* @param evse_id
|
||||
* @param evse_index
|
||||
* @param connectors The connectors.
|
||||
*/
|
||||
void init_evse(const int evse_id, const int evse_index, const std::vector<Connector>& connectors);
|
||||
|
||||
/**
|
||||
* @brief Returns the evse_id for the given \p evse_index .
|
||||
*
|
||||
* @param evse_index
|
||||
* @return int32_t evse_id
|
||||
*/
|
||||
int32_t get_evse_id_by_index(const int evse_index);
|
||||
|
||||
/**
|
||||
* @brief Call when everything is initialized. This will call 'init' of the reservation handler.
|
||||
*/
|
||||
void initialize();
|
||||
|
||||
/**
|
||||
* @brief Handler for a new incoming \p provided_token
|
||||
*
|
||||
* @param provided_token
|
||||
*/
|
||||
TokenHandlingResult on_token(const ProvidedIdToken& provided_token);
|
||||
|
||||
/**
|
||||
* @brief Handler for an update to a token validation result. This is mainly used to update if we have a parent id.
|
||||
*
|
||||
* @param validation_result_update
|
||||
*/
|
||||
void handle_token_validation_result_update(const ValidationResultUpdate& validation_result_update);
|
||||
|
||||
/**
|
||||
* @brief Handler for new incoming \p reservation for the given \p connector . Places the reservation if possible.
|
||||
*
|
||||
* @param reservation
|
||||
* @return types::reservation::ReservationResult
|
||||
*/
|
||||
types::reservation::ReservationResult handle_reservation(const Reservation& reservation);
|
||||
|
||||
/**
|
||||
* @brief Handler for incoming cancel reservation request for the given \p reservation_id .
|
||||
*
|
||||
* @param reservation_id
|
||||
* @return return value first returns false if the reservation could not been cancelled. Return value second is the
|
||||
* evse id or nullopt if the reservation was a 'global' reservation without evse id.
|
||||
*/
|
||||
std::pair<bool, std::optional<int32_t>> handle_cancel_reservation(const int32_t reservation_id);
|
||||
|
||||
/**
|
||||
* @brief Callback to check if there is a reservation for the given token (on the given evse id).
|
||||
* @param id_token The token to check.
|
||||
* @param evse_id The evse to check the reservation for.
|
||||
* @param group_id_token The group id token to check.
|
||||
* @return The reservation check status
|
||||
*/
|
||||
ReservationCheckStatus handle_reservation_exists(std::string& id_token, const std::optional<int>& evse_id,
|
||||
std::optional<std::string>& group_id_token);
|
||||
|
||||
/**
|
||||
* @brief Callback to signal EvseManager that the given \p connector_id has been reserved with the given \p
|
||||
* reservation_id .
|
||||
*
|
||||
* @param evse_id
|
||||
* @param reservation_id
|
||||
*
|
||||
* @return true of EvseManager accepted the reservation.
|
||||
*/
|
||||
bool call_reserved(const int reservation_id, const std::optional<int>& evse_id);
|
||||
|
||||
/**
|
||||
* @brief Callback to signal EvseManager that the reservation for the given \p evse_id has been cancelled.
|
||||
*
|
||||
* @param reservation_id The id of the cancelled reservation.
|
||||
* @param reason The reason the reservation was cancelled.
|
||||
* @param evse_id Evse id if reservation was for a specific evse.
|
||||
* @param send_reservation_update True to send a reservation update. This should not be sent if OCPP cancels
|
||||
* the reservation.
|
||||
*/
|
||||
void call_reservation_cancelled(const int32_t reservation_id, const ReservationEndReason reason,
|
||||
const std::optional<int>& evse_id, const bool send_reservation_update);
|
||||
|
||||
/**
|
||||
* @brief Handler for the given \p events at the given \p connector . Submits events to the state machine of the
|
||||
* handler.
|
||||
*
|
||||
* @param evse_id
|
||||
* @param events
|
||||
*/
|
||||
void handle_session_event(const int evse_id, const SessionEvent& events);
|
||||
|
||||
/**
|
||||
* @brief Handler for permanent faults from evsemanager that prevents charging
|
||||
*/
|
||||
void handle_permanent_fault_cleared(const int evse_id, const int32_t connector_id);
|
||||
void handle_permanent_fault_raised(const int evse_id, const int32_t connector_id);
|
||||
|
||||
/**
|
||||
* @brief Set the connection timeout of the handler.
|
||||
*
|
||||
* @param connection_timeout
|
||||
*/
|
||||
void set_connection_timeout(const int connection_timeout);
|
||||
|
||||
/**
|
||||
* @brief Set the plug in timeout enabled flag of the handler.
|
||||
*
|
||||
* @param plug_in_timeout_enabled
|
||||
*/
|
||||
void set_plug_in_timeout_enabled(bool plug_in_timeout_enabled);
|
||||
|
||||
/**
|
||||
* @brief Set the master pass group id of the handler.
|
||||
*
|
||||
* @param master_pass_group_id
|
||||
*/
|
||||
void set_master_pass_group_id(const std::string& master_pass_group_id);
|
||||
|
||||
/**
|
||||
* @brief Set the prioritize authorization over stopping transaction flag of the handler.
|
||||
*
|
||||
* @param b
|
||||
*/
|
||||
void set_prioritize_authorization_over_stopping_transaction(bool b);
|
||||
|
||||
/**
|
||||
* @brief Registers the given \p callback to notify the evse about the processed authorization request.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void
|
||||
register_notify_evse_callback(const std::function<void(const int evse_index, const ProvidedIdToken& provided_token,
|
||||
const ValidationResult& validation_result)>& callback);
|
||||
/**
|
||||
* @brief Registers the given \p callback to withdraw authorization.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void register_withdraw_authorization_callback(const std::function<void(const int evse_index)>& callback);
|
||||
|
||||
/**
|
||||
* @brief Registers the given \p callback to validate a token.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void register_validate_token_callback(
|
||||
const std::function<std::vector<ValidationResult>(const ProvidedIdToken& provided_token)>& callback);
|
||||
|
||||
/**
|
||||
* @brief Registers the given \p callback to stop a transaction at an EvseManager.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void register_stop_transaction_callback(
|
||||
const std::function<void(const int evse_index, const StopTransactionRequest& request)>& callback);
|
||||
|
||||
/**
|
||||
* @brief Registers the given \p callback to signal a reservation to an EvseManager.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void register_reserved_callback(
|
||||
const std::function<bool(const std::optional<int>& evse_id, const int& reservation_id)>& callback);
|
||||
|
||||
/**
|
||||
* @brief Registers the given \p callback to signal a reservation has been cancelled to the EvseManager.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void register_reservation_cancelled_callback(
|
||||
const std::function<void(const std::optional<int32_t>& evse_id, const int32_t reservation_id,
|
||||
const ReservationEndReason reason, const bool send_reservation_update)>& callback);
|
||||
|
||||
/**
|
||||
* @brief Registers the given \p callback to publish the intermediate token validation status.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
void register_publish_token_validation_status_callback(
|
||||
const std::function<void(const ProvidedIdToken&, TokenValidationStatus, const std::vector<MessageContent>&)>&
|
||||
callback);
|
||||
|
||||
WithdrawAuthorizationResult handle_withdraw_authorization(const WithdrawAuthorizationRequest& request);
|
||||
|
||||
private:
|
||||
enum class SelectEvseReturnStatus {
|
||||
EvseSelected,
|
||||
Interrupted,
|
||||
TimeOut
|
||||
};
|
||||
|
||||
struct SelectEvseResult {
|
||||
std::optional<int> evse_id;
|
||||
SelectEvseReturnStatus status;
|
||||
};
|
||||
|
||||
SelectionAlgorithm selection_algorithm;
|
||||
int connection_timeout;
|
||||
bool plug_in_timeout_enabled;
|
||||
std::optional<std::string> master_pass_group_id;
|
||||
bool prioritize_authorization_over_stopping_transaction;
|
||||
bool ignore_faults;
|
||||
ReservationHandler reservation_handler;
|
||||
|
||||
std::map<int, std::unique_ptr<EVSEContext>> evses;
|
||||
|
||||
std::list<int> plug_in_queue;
|
||||
std::set<ProvidedIdToken> tokens_in_process;
|
||||
std::condition_variable cv;
|
||||
std::condition_variable processing_finished_cv;
|
||||
std::mutex event_mutex;
|
||||
std::mutex withdraw_mutex;
|
||||
std::unique_ptr<WithdrawAuthorizationRequest> withdraw_request;
|
||||
|
||||
// callbacks
|
||||
std::function<void(const int evse_index, const ProvidedIdToken& provided_token,
|
||||
const ValidationResult& validation_result)>
|
||||
notify_evse_callback;
|
||||
std::function<void(const int evse_index)> withdraw_authorization_callback;
|
||||
std::function<std::vector<ValidationResult>(const ProvidedIdToken& provided_token)> validate_token_callback;
|
||||
std::function<void(const int evse_index, const StopTransactionRequest& request)> stop_transaction_callback;
|
||||
std::function<void(const Array& reservations)> reservation_update_callback;
|
||||
std::function<bool(const std::optional<int>& evse_index, const int& reservation_id)> reserved_callback;
|
||||
std::function<void(const std::optional<int>& evse_index, const int32_t reservation_id,
|
||||
const types::reservation::ReservationEndReason reason, const bool send_reservation_update)>
|
||||
reservation_cancelled_callback;
|
||||
std::function<void(const ProvidedIdToken& token, TokenValidationStatus status,
|
||||
const std::vector<MessageContent>& tariff_messages)>
|
||||
publish_token_validation_status_callback;
|
||||
|
||||
void publish_token_validation_status(const ProvidedIdToken& token, TokenValidationStatus status,
|
||||
const std::vector<MessageContent>& tariff_messages = {});
|
||||
|
||||
std::vector<int> get_referenced_evses(const ProvidedIdToken& provided_token);
|
||||
int used_for_transaction(const std::vector<int>& evse_ids, const std::string& id_token);
|
||||
bool is_token_already_in_process(const ProvidedIdToken& provided_id_token,
|
||||
const std::vector<int>& referenced_evses);
|
||||
bool any_evse_available(const std::vector<int>& evse_ids);
|
||||
bool any_parent_id_present(const std::vector<int>& evse_ids);
|
||||
bool equals_master_pass_group_id(const std::optional<types::authorization::IdToken> parent_id_token);
|
||||
|
||||
TokenHandlingResult handle_token(ProvidedIdToken& provided_token, std::unique_lock<std::mutex>& lk);
|
||||
|
||||
/**
|
||||
* @brief Method selects an evse based on the configured selection algorithm. It might block until an event
|
||||
* occurs that can be used to determine an evse.
|
||||
*
|
||||
* @param selected_evses
|
||||
* @param id_token The id token of the request.
|
||||
* @return The status and optional evse id if an evse was selected.
|
||||
*/
|
||||
SelectEvseResult select_evse(const std::vector<int>& selected_evses, const IdToken& id_token,
|
||||
std::unique_lock<std::mutex>& lk);
|
||||
bool is_authorization_withdrawn(const std::vector<int>& selected_evses, const IdToken& id_token);
|
||||
|
||||
int get_latest_plugin(const std::vector<int>& evse_ids);
|
||||
void notify_evse(int evse_id, const ProvidedIdToken& provided_token, const ValidationResult& validation_result,
|
||||
std::unique_lock<std::mutex>& lk);
|
||||
Identifier get_identifier(const ValidationResult& validation_result, const std::string& id_token,
|
||||
const AuthorizationType& type);
|
||||
void submit_event_for_connector(const int32_t evse_id, const int32_t connector_id,
|
||||
const ConnectorEvent connector_event);
|
||||
/**
|
||||
* @brief Check reservations: if there are as many reservations as evse's, all should be set to reserved.
|
||||
*
|
||||
* This will check the reservation status of the evse's and send the statusses to the evse manager.
|
||||
*/
|
||||
void check_evse_reserved_and_send_updates();
|
||||
};
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif //_AUTH_HANDLER_HPP_
|
||||
100
tools/EVerest-main/modules/EVSE/Auth/include/Connector.hpp
Normal file
100
tools/EVerest-main/modules/EVSE/Auth/include/Connector.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#ifndef _CONNECTOR_HPP_
|
||||
#define _CONNECTOR_HPP_
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <everest/timer.hpp>
|
||||
|
||||
#include <utils/types.hpp>
|
||||
|
||||
#include <ConnectorStateMachine.hpp>
|
||||
#include <generated/types/authorization.hpp>
|
||||
#include <generated/types/evse_manager.hpp>
|
||||
|
||||
namespace module {
|
||||
|
||||
/// \brief Validated Identifier struct. Used to keep track of active Identifiers
|
||||
struct Identifier {
|
||||
types::authorization::IdToken id_token; ///< IdToken of the identifier
|
||||
types::authorization::AuthorizationType type; ///< Type of the provider of the identifier
|
||||
std::optional<types::authorization::AuthorizationStatus> authorization_status;
|
||||
std::optional<std::string> expiry_time; ///< Absolute UTC time point when reservation expires in RFC3339 format
|
||||
std::optional<types::authorization::IdToken> parent_id_token; ///< Parent id token of the identifier
|
||||
};
|
||||
|
||||
struct Connector {
|
||||
explicit Connector(
|
||||
int id, const types::evse_manager::ConnectorTypeEnum type = types::evse_manager::ConnectorTypeEnum::Unknown) :
|
||||
id(id), transaction_active(false), state_machine(ConnectorState::AVAILABLE), type(type) {
|
||||
}
|
||||
|
||||
int id;
|
||||
|
||||
bool transaction_active;
|
||||
ConnectorStateMachine state_machine;
|
||||
types::evse_manager::ConnectorTypeEnum type;
|
||||
|
||||
/**
|
||||
* @brief Submits the given \p event to the state machine
|
||||
*
|
||||
* @param event
|
||||
*/
|
||||
void submit_event(ConnectorEvent event);
|
||||
|
||||
/**
|
||||
* @brief Returns true if connector is in state UNAVAILABLE or UNAVAILABLE_FAULTED
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool is_unavailable() const;
|
||||
|
||||
ConnectorState get_state() const;
|
||||
};
|
||||
|
||||
struct EVSEContext {
|
||||
|
||||
EVSEContext(
|
||||
int evse_id, int evse_index, int connector_id,
|
||||
const types::evse_manager::ConnectorTypeEnum connector_type = types::evse_manager::ConnectorTypeEnum::Unknown) :
|
||||
evse_id(evse_id), evse_index(evse_index), transaction_active(false), plugged_in(false) {
|
||||
Connector c(connector_id, connector_type);
|
||||
connectors.push_back(c);
|
||||
}
|
||||
|
||||
EVSEContext(int evse_id, int evse_index, const std::vector<Connector>& connectors) :
|
||||
evse_id(evse_id),
|
||||
evse_index(evse_index),
|
||||
transaction_active(false),
|
||||
connectors(connectors),
|
||||
plugged_in(false),
|
||||
plug_in_timeout(false) {
|
||||
}
|
||||
|
||||
int32_t evse_id;
|
||||
int32_t evse_index;
|
||||
bool transaction_active;
|
||||
|
||||
// identifier is set when transaction is running and none if not
|
||||
std::optional<Identifier> identifier = std::nullopt;
|
||||
std::vector<Connector> connectors;
|
||||
Everest::SteadyTimer timeout_timer;
|
||||
std::atomic<bool> timeout_in_progress{false};
|
||||
bool plugged_in;
|
||||
bool plug_in_timeout; // indicates no authorization received within connection_timeout. Replug is required for this
|
||||
// EVSE to get authorization and start a transaction
|
||||
|
||||
bool is_available();
|
||||
bool is_unavailable();
|
||||
};
|
||||
|
||||
namespace conversions {
|
||||
std::string connector_state_to_string(const ConnectorState& state);
|
||||
} // namespace conversions
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif //_CONNECTOR_HPP_
|
||||
@@ -0,0 +1,45 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// Copyright Pionix GmbH and Contributors to EVerest
|
||||
|
||||
#ifndef _CONNECTOR_STATE_MACHINE_HPP_
|
||||
#define _CONNECTOR_STATE_MACHINE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace module {
|
||||
|
||||
enum class ConnectorEvent {
|
||||
ENABLE,
|
||||
DISABLE,
|
||||
ERROR_CLEARED,
|
||||
FAULTED,
|
||||
TRANSACTION_STARTED,
|
||||
SESSION_FINISHED
|
||||
};
|
||||
|
||||
/// @warning Do not change the order of ConnectorState, or if you do it, fix the code in ReservationHandler.
|
||||
enum class ConnectorState {
|
||||
AVAILABLE,
|
||||
UNAVAILABLE,
|
||||
FAULTED,
|
||||
OCCUPIED,
|
||||
UNAVAILABLE_FAULTED,
|
||||
FAULTED_OCCUPIED
|
||||
};
|
||||
|
||||
class ConnectorStateMachine {
|
||||
public:
|
||||
explicit ConnectorStateMachine(ConnectorState initial_state);
|
||||
|
||||
bool handle_event(ConnectorEvent event);
|
||||
|
||||
ConnectorState get_state() const;
|
||||
|
||||
private:
|
||||
ConnectorState state;
|
||||
};
|
||||
|
||||
} // namespace module
|
||||
|
||||
#endif //_CONNECTOR_STATE_MACHINE_HPP_
|
||||
@@ -0,0 +1,357 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <Connector.hpp>
|
||||
#include <everest/timer.hpp>
|
||||
#include <generated/types/evse_manager.hpp>
|
||||
#include <generated/types/reservation.hpp>
|
||||
|
||||
class kvsIntf;
|
||||
|
||||
namespace module {
|
||||
|
||||
struct ReservationEvseStatus {
|
||||
std::set<int32_t> reserved;
|
||||
std::set<int32_t> available;
|
||||
};
|
||||
|
||||
class ReservationHandler {
|
||||
private: // Members
|
||||
/// \brief Map of EVSE's, with EVSE id as key and the EVSE struct as value.
|
||||
std::map<int, std::unique_ptr<module::EVSEContext>>& evses;
|
||||
/// \brief Key value store id.
|
||||
const std::string kvs_store_key_id;
|
||||
/// \brief Key value store for storing reservations.
|
||||
kvsIntf* store;
|
||||
/// \brief Map of EVSE specific reservations, with EVSE id as key and the Reservation type as value.
|
||||
std::map<uint32_t, types::reservation::Reservation> evse_reservations;
|
||||
/// \brief All reservations not bound to a specific EVSE.
|
||||
std::vector<types::reservation::Reservation> global_reservations;
|
||||
/// \brief event mutex, for all timer bound locks (for `reservation_id_to_reservation_timeout_timer_map`)
|
||||
mutable std::recursive_mutex event_mutex;
|
||||
/// \brief Map with reservations and their timer.
|
||||
///
|
||||
/// Every reservation has a specific end time, which is stored in this map. Key is the reservation id. When the
|
||||
/// timer expires, it is removed from the map and the reservation is removed from the `evse_reservations` or
|
||||
/// `global_reservations`.
|
||||
std::map<int, std::unique_ptr<Everest::SteadyTimer>> reservation_id_to_reservation_timeout_timer_map;
|
||||
|
||||
/// \brief The callback that is called when a reservation is cancelled.
|
||||
std::function<void(const std::optional<uint32_t>& evse_id, const int32_t reservation_id,
|
||||
const types::reservation::ReservationEndReason reason, const bool send_reservation_update)>
|
||||
reservation_cancelled_callback;
|
||||
|
||||
std::set<int32_t> last_reserved_status;
|
||||
|
||||
/// \brief worker for the timers.
|
||||
boost::shared_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> work;
|
||||
/// \brief io_context for the worker for the timers.
|
||||
boost::asio::io_context io_context;
|
||||
/// \brief io context thread for the timers.
|
||||
std::thread io_context_thread;
|
||||
|
||||
public:
|
||||
///
|
||||
/// \brief Constructor.
|
||||
///
|
||||
ReservationHandler(std::map<int, std::unique_ptr<module::EVSEContext>>& evses, const std::string& id,
|
||||
kvsIntf* store);
|
||||
|
||||
///
|
||||
/// \brief Destructor.
|
||||
///
|
||||
~ReservationHandler();
|
||||
|
||||
///
|
||||
/// \brief Load reservations from key value store.
|
||||
///
|
||||
void load_reservations();
|
||||
|
||||
///
|
||||
/// \brief Try to make a reservation.
|
||||
/// \param evse_id Optional, the evse id. If omitted, a 'global' reservation will be made.
|
||||
/// \param reservation The reservation to make.
|
||||
/// \return The result of the reservation (`Accepted` if the reservation could be made).
|
||||
///
|
||||
types::reservation::ReservationResult make_reservation(const std::optional<uint32_t> evse_id,
|
||||
const types::reservation::Reservation& reservation);
|
||||
|
||||
///
|
||||
/// \brief Change a specific connector state.
|
||||
///
|
||||
/// This is important for the reservation handler, to know which connector is in which state, to know if a
|
||||
/// reservation can be made or not.
|
||||
///
|
||||
/// \param connector_state The state of the connector.
|
||||
/// \param evse_id The EVSE id the connector belongs to.
|
||||
/// \param connector_id The connector id.
|
||||
///
|
||||
void on_connector_state_changed(const ConnectorState connector_state, const uint32_t evse_id,
|
||||
const uint32_t connector_id);
|
||||
|
||||
///
|
||||
/// \brief Check if charging is possible on a given EVSE.
|
||||
///
|
||||
/// If there are multiple global reservations, while a charging station might look available, it is possible that
|
||||
/// charging is not possible because then cars that made reservations can not charge anymore.
|
||||
///
|
||||
/// Only use this function to check if a car can charge without having a reservation id.
|
||||
///
|
||||
/// \param evse_id The evse on which a car wants to charge.
|
||||
/// \return True if charging is possible.
|
||||
///
|
||||
bool is_charging_possible(const uint32_t evse_id);
|
||||
|
||||
///
|
||||
/// \brief Check is an EVSE is reserved.
|
||||
///
|
||||
/// This only looks at EVSE specific reservations.
|
||||
///
|
||||
/// \param evse_id The evse id to check.
|
||||
/// \return True if EVSE is reserved.
|
||||
///
|
||||
bool is_evse_reserved(const uint32_t evse_id);
|
||||
|
||||
///
|
||||
/// \brief Cancel a reservation.
|
||||
/// \param reservation_id The id of the reservation to cancel.
|
||||
/// \param execute_callback True if the `reservation_cancelled_callback` must be called.
|
||||
/// \param reason The cancel reason.
|
||||
/// \return First: true if reservation could be cancelled.
|
||||
/// Second: The evse id if the reservation to cancel was made for a specific EVSE.
|
||||
///
|
||||
std::pair<bool, std::optional<uint32_t>> cancel_reservation(const int reservation_id, const bool execute_callback,
|
||||
const types::reservation::ReservationEndReason reason);
|
||||
|
||||
///
|
||||
/// \brief Cancel a reservation.
|
||||
/// \param evse_id The evse id to cancel the reservation for.
|
||||
/// \param execute_callback True if the `reservation_cancelled_callback` must be called.
|
||||
/// \return True if the reservation could be cancelled.
|
||||
///
|
||||
bool cancel_reservation(const uint32_t evse_id, const bool execute_callback);
|
||||
|
||||
///
|
||||
/// \brief Register reservation cancelled callback.
|
||||
/// \param callback The callback that should be called when a reservation is cancelled.
|
||||
///
|
||||
void register_reservation_cancelled_callback(
|
||||
const std::function<void(const std::optional<uint32_t>& evse_id, const int32_t reservation_id,
|
||||
const types::reservation::ReservationEndReason reason,
|
||||
const bool send_reservation_update)>& callback);
|
||||
|
||||
///
|
||||
/// \brief Called when a reservation is used, will remove it from the reservation list.
|
||||
/// \param reservation_id The if of the reservation that is used.
|
||||
///
|
||||
/// \note This will not set the EVSE or Connector to 'available'. That must be done separately (because we don't
|
||||
/// know here when the connector is not connected anymore).
|
||||
///
|
||||
void on_reservation_used(const int32_t reservation_id);
|
||||
|
||||
///
|
||||
/// @brief Function checks if the given \p id_token or \p parent_id_token matches the reserved token of the given \p
|
||||
/// evse_id
|
||||
///
|
||||
/// @param id_token Id token
|
||||
/// @param evse_id Evse id
|
||||
/// @param parent_id_token Parent id token
|
||||
/// @return The reservation id when there is a matching identifier, otherwise std::nullopt.
|
||||
///
|
||||
std::optional<int32_t> matches_reserved_identifier(const std::string& id_token,
|
||||
const std::optional<uint32_t> evse_id,
|
||||
std::optional<std::string> parent_id_token);
|
||||
|
||||
///
|
||||
/// @brief Functions check if reservation at the given \p evse_id contains a parent_id
|
||||
/// @param evse_id Evse id
|
||||
/// @return true if reservation for \p evse_id exists and reservation contains a parent_id
|
||||
///
|
||||
bool has_reservation_parent_id(const std::optional<uint32_t> evse_id);
|
||||
|
||||
///
|
||||
/// \brief Check if the number of global reservations match the number of available evse's.
|
||||
/// \return The new reservation status of the evse's.
|
||||
///
|
||||
/// \note The return value has the new reserved and new available statusses (so the ones that were already reserved
|
||||
/// are not added to those lists).
|
||||
///
|
||||
ReservationEvseStatus check_number_global_reservations_match_number_available_evses();
|
||||
|
||||
private: // Functions
|
||||
///
|
||||
/// \brief Check if there is a specific connector type in the vector.
|
||||
/// \param evse_connectors The vector to check for the type.
|
||||
/// \param connector_type The connector type to find.
|
||||
/// \return True if the connector type is in the vector.
|
||||
///
|
||||
bool has_evse_connector_type(const std::vector<Connector>& evse_connectors,
|
||||
const types::evse_manager::ConnectorTypeEnum connector_type) const;
|
||||
|
||||
///
|
||||
/// \brief Check if there is at least one EVSE with the given connector type.
|
||||
/// \param connector_type The connector type to check.
|
||||
/// \return True if at least one EVSE has this connector type.
|
||||
///
|
||||
bool does_evse_connector_type_exist(const types::evse_manager::ConnectorTypeEnum connector_type) const;
|
||||
|
||||
///
|
||||
/// \brief Helper function to get a reservation result from the current EVSE state and connector state, and if
|
||||
/// there is a specific reservation for this EVSE.
|
||||
/// \param evse_id The evse id to get the state from.
|
||||
/// \param evse_specific_reservations The evse specific reservations list to look in.
|
||||
/// \return The `ReservationResult` to return for this specific EVSE.
|
||||
///
|
||||
types::reservation::ReservationResult get_evse_connector_state_reservation_result(
|
||||
const uint32_t evse_id, const std::map<uint32_t, types::reservation::Reservation>& evse_specific_reservations);
|
||||
|
||||
///
|
||||
/// \brief Helper function to check if the connector of a specific EVSE is available.
|
||||
/// \param evse_id The evse id the connector belongs to.
|
||||
/// \param connector_type The connector type to check.
|
||||
/// \return The `ReservationResult` to return for his specific connector.
|
||||
///
|
||||
types::reservation::ReservationResult
|
||||
get_connector_availability_reservation_result(const uint32_t evse_id,
|
||||
const types::evse_manager::ConnectorTypeEnum connector_type);
|
||||
|
||||
///
|
||||
/// \brief Get all possible orders of connector types given a vector of connector types.
|
||||
///
|
||||
/// For the reservations, there must be checked if all combinations of arriving cars with specific connector types
|
||||
/// are possible. For that, we want to have a list of all different combinations of arriving.
|
||||
///
|
||||
/// So for example for connector type A, B and C, the different combinations are:
|
||||
/// - A, B, C
|
||||
/// - A, C, B
|
||||
/// - B, A, C
|
||||
/// - B, C, A
|
||||
/// - C, A, B
|
||||
/// - C, B, A
|
||||
///
|
||||
/// And for connector types A, A and B, the combinations are:
|
||||
/// - A, A, B
|
||||
/// - A, B, A
|
||||
/// - B, A, A
|
||||
///
|
||||
/// \param connectors The connector types to get all orders from.
|
||||
/// \return A vector of all orders of the connector types.
|
||||
///
|
||||
std::vector<std::vector<types::evse_manager::ConnectorTypeEnum>>
|
||||
get_all_possible_orders(const std::vector<types::evse_manager::ConnectorTypeEnum>& connectors) const;
|
||||
|
||||
///
|
||||
/// \brief Helper function: For a specific order of arrival of cars, check if there is still an EVSE available for
|
||||
/// each car.
|
||||
///
|
||||
/// This function is called recursively, until no 'virtual cars' are left.
|
||||
///
|
||||
/// \param used_evse_ids The evse id's we have used in previous checks. This will be empty when the
|
||||
/// function is first called and will be filled every time an evse id is
|
||||
/// 'used'.
|
||||
/// \param next_car_arrival_order The order in which the cars arrive. This is for example 'A, B, C' and as
|
||||
/// soon as the first is handled, it is removed from the list before
|
||||
/// recursively calling the function again.
|
||||
/// \param evse_specific_reservations EVSE specific reservations, to see if an EVSE is already reserved.
|
||||
/// \return True if this combination of car arrival orders is possible.
|
||||
///
|
||||
bool can_virtual_car_arrive(const std::vector<uint32_t>& used_evse_ids,
|
||||
const std::vector<types::evse_manager::ConnectorTypeEnum>& next_car_arrival_order,
|
||||
const std::map<uint32_t, types::reservation::Reservation>& evse_specific_reservations);
|
||||
|
||||
///
|
||||
/// \brief Check if it is possible to make a new reservation.
|
||||
/// \param global_reservation_type If it is a global reservation: the reservation type.
|
||||
/// \param reservations_no_evse The list of global reservations.
|
||||
/// \param evse_specific_reservations The list of evse specific reservations.
|
||||
/// \return True if a reservation is possible, otherwise false.
|
||||
///
|
||||
bool is_reservation_possible(const std::optional<types::evse_manager::ConnectorTypeEnum> global_reservation_type,
|
||||
const std::vector<types::reservation::Reservation>& reservations_no_evse,
|
||||
const std::map<uint32_t, types::reservation::Reservation>& evse_specific_reservations);
|
||||
|
||||
///
|
||||
/// \brief If a reservation is made, add the reservation to the `reservation_id_to_reservation_timeout_timer_map`.
|
||||
/// \param reservation The reservation.
|
||||
/// \param evse_id The evse id.
|
||||
///
|
||||
void set_reservation_timer(const types::reservation::Reservation& reservation,
|
||||
const std::optional<uint32_t> evse_id);
|
||||
|
||||
///
|
||||
/// \brief Get all evses that have a specific connector type.
|
||||
/// \param connector_type The connector type.
|
||||
/// \return Vector with evse's.
|
||||
///
|
||||
std::vector<EVSEContext*>
|
||||
get_all_evses_with_connector_type(const types::evse_manager::ConnectorTypeEnum connector_type) const;
|
||||
|
||||
///
|
||||
/// \brief For H01.FR.11, H01.FR.12 and H01.FR.13, the correct state must be returned.
|
||||
///
|
||||
/// Also see @see module::ReservationHandler::get_reservation_evse_connector_state. This is a helper function to
|
||||
/// return the 'more important' state (Occupied is 'more important' than Unavailable).
|
||||
///
|
||||
/// \param currrent_state The current connector state.
|
||||
/// \param new_state The new state.
|
||||
/// \return The connector state.
|
||||
///
|
||||
ConnectorState get_new_connector_state(ConnectorState currrent_state, const ConnectorState new_state) const;
|
||||
|
||||
///
|
||||
/// \brief For H01.FR.11, H01.FR.12 and H01.FR.13, the correct state must be returned: if (all) evses are Occupied
|
||||
/// or reserved, occupied must be returned, if (all) evses are Faulted, faulted must be returned, if (all)
|
||||
/// evses are unavailable, unavailable must be returned. This function helps returning the correct state.
|
||||
///
|
||||
/// If at least one of the EVSE's is Occupied, it will return occupied, then it will look to faulted and then to
|
||||
/// unavailable. So if one is occupied and one faulted, it will still return occupied.
|
||||
///
|
||||
/// \param connector_type The connector type to check.
|
||||
/// \return The reservation result that can be returned on the reserve now request.
|
||||
///
|
||||
types::reservation::ReservationResult
|
||||
get_reservation_evse_connector_state(const types::evse_manager::ConnectorTypeEnum connector_type) const;
|
||||
|
||||
///
|
||||
/// \brief After a connector or evse is set to unavailable, faulted or occupied, this function can be called to
|
||||
/// check the reservations and cancel reservations that are not possible now anymore.
|
||||
///
|
||||
void check_reservations_and_cancel_if_not_possible();
|
||||
|
||||
///
|
||||
/// \brief Store reservations to key value store.
|
||||
///
|
||||
void store_reservations();
|
||||
|
||||
///
|
||||
/// \brief Get new reserved / available status for evse's and store it.
|
||||
/// \param currently_available_evses Current available evse's.
|
||||
/// \param reserved_evses Current reserved evse's.
|
||||
/// \return A struct with changed reservation statuses compared with the last time this function was called.
|
||||
///
|
||||
/// When an evse is reserved and it was available before, it will be added to the set in the struct (return value).
|
||||
/// But when an evse is reserved and last time it was already reserved, it is not added.
|
||||
///
|
||||
ReservationEvseStatus
|
||||
get_evse_global_reserved_status_and_set_new_status(const std::set<int32_t>& currently_available_evses,
|
||||
const std::set<int32_t>& reserved_evses);
|
||||
|
||||
///
|
||||
/// \brief Helper function to print information about reservations and evses, to find out why a reservation has
|
||||
/// failed.
|
||||
/// \param reservation The reservation.
|
||||
/// \param evse_id The evse id.
|
||||
///
|
||||
void print_reservations_debug_info(const types::reservation::Reservation& reservation,
|
||||
const std::optional<uint32_t> evse_id, const bool reservation_failed);
|
||||
};
|
||||
|
||||
} // namespace module
|
||||
Reference in New Issue
Block a user