Skip to content

Commit

Permalink
Feature/327 use case h01 reservation (#854)
Browse files Browse the repository at this point in the history
* H01 reservations implemented
* Some changes are made in the interface as well.

Signed-off-by: Maaike Zijderveld, iolar <[email protected]>
  • Loading branch information
maaikez authored Nov 26, 2024
1 parent c9a6f45 commit 173af8d
Show file tree
Hide file tree
Showing 19 changed files with 467 additions and 89 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.14)

project(ocpp
VERSION 0.20.0
VERSION 0.21.0
DESCRIPTION "A C++ implementation of the Open Charge Point Protocol"
LANGUAGES CXX
)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ The following table shows the known CSMS with which this library was tested.
| E. Transactions | ✅ yes |
| F. RemoteControl | ✅ yes |
| G. Availability | ✅ yes |
| H. Reservation | WIP |
| H. Reservation | ✅ yes |
| I. TariffAndCost | ✅ yes |
| J. MeterValues | ✅ yes |
| K. SmartCharging | WIP |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"attributes": [
{
"type": "Actual",
"mutability": "ReadOnly"
"mutability": "ReadOnly",
"value": true
}
],
"description": "If this configuration variable is present and set to true: Charging Station supports Reservation where EVSE id is not specified.",
Expand Down
58 changes: 30 additions & 28 deletions doc/v201/ocpp_201_status.md
Original file line number Diff line number Diff line change
Expand Up @@ -1071,21 +1071,21 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir

| ID | Status | Remark |
|-----------|--------|--------|
| H01.FR.01 | | |
| H01.FR.02 | | |
| H01.FR.03 | | |
| H01.FR.04 | | |
| H01.FR.06 | | |
| H01.FR.07 | | |
| H01.FR.09 | | |
| H01.FR.11 | | |
| H01.FR.12 | | |
| H01.FR.14 | | |
| H01.FR.15 | | |
| H01.FR.16 | | |
| H01.FR.17 | | |
| H01.FR.18 | | |
| H01.FR.19 | | |
| H01.FR.01 | | |
| H01.FR.02 | | |
| H01.FR.03 | | |
| H01.FR.04 | | |
| H01.FR.06 | | |
| H01.FR.07 | | |
| H01.FR.09 | | |
| H01.FR.11 | | |
| H01.FR.12 | | |
| H01.FR.14 | | |
| H01.FR.15 | | |
| H01.FR.16 | | |
| H01.FR.17 | | |
| H01.FR.18 | | |
| H01.FR.19 | | |
| H01.FR.20 | | |
| H01.FR.23 | | |
| H01.FR.24 | | |
Expand All @@ -1094,29 +1094,31 @@ This document contains the status of which OCPP 2.0.1 numbered functional requir

| ID | Status | Remark |
|-----------|--------|--------|
| H02.FR.01 | | |
| H02.FR.02 | | |
| H02.FR.01 | | |
| H02.FR.02 | | |

## Reservation - Use a reserved EVSE

| ID | Status | Remark |
|-----------|--------|--------|
| H03.FR.01 | | |
| H03.FR.02 | | |
| H03.FR.03 | | |
| H03.FR.04 | | |
| H03.FR.05 | | |
| H03.FR.06 | | |
| H03.FR.07 | | |
| H03.FR.08 | | |
| H03.FR.01 || |
| H03.FR.02 || |
| H03.FR.03 || |
| H03.FR.04 || |
| H03.FR.05 || |
| H03.FR.06 || |
| H03.FR.07 | ⛽️ | |
| H03.FR.08 | ⛽️ | |
| H03.FR.09 || |
| H03.FR.10 || |

## Reservation - Reservation Ended, not used

| ID | Status | Remark |
|-----------|--------|--------|
| H04.FR.01 | | |
| H04.FR.02 | | |
| H04.FR.03 | | |
| H04.FR.01 | | |
| H04.FR.02 | | |
| H04.FR.03 | | Not all the connectors maybe? |

## TariffAndCost - Show EV Driver-specific Tariff Information

Expand Down
9 changes: 9 additions & 0 deletions include/ocpp/common/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,15 @@ struct CompositeScheduleDefaultLimits {
int32_t number_phases;
};

/// \brief Status of a reservation check.
enum class ReservationCheckStatus {
NotReserved, ///< @brief No reservation of this evse and / or id token
ReservedForToken, ///< @brief Reservation for this token.
ReservedForOtherToken, ///< @brief Reserved for other token and reservation has no parent token or parent token does
///< not match.
ReservedForOtherTokenAndHasParentToken, ///< @brief Reserved for other token but reservation has a parent token.
};

} // namespace ocpp

#endif
2 changes: 1 addition & 1 deletion include/ocpp/v16/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ class ChargePoint {
/// \param callback
/// \ingroup ocpp16_callbacks
void register_is_token_reserved_for_connector_callback(
const std::function<bool(const int32_t connector, const std::string& id_token)>& callback);
const std::function<ReservationCheckStatus(const int32_t connector, const std::string& id_token)>& callback);

/// \brief Registers a callback function for the session cost datatransfer message (California Pricing Requirements)
/// \param session_cost_callback The callback.
Expand Down
5 changes: 3 additions & 2 deletions include/ocpp/v16/charge_point_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ class ChargePointImpl : ocpp::ChargingStationBase {
transaction_updated_callback;
std::function<void(const int32_t connector, const std::string& session_id, const int32_t transaction_id)>
transaction_stopped_callback;
std::function<bool(const int32_t connector, const std::string& id_token)> is_token_reserved_for_connector_callback;
std::function<ocpp::ReservationCheckStatus(const int32_t connector, const std::string& id_token)>
is_token_reserved_for_connector_callback;

// iso15118 callback
std::function<void(const int32_t connector, const ocpp::v201::Get15118EVCertificateResponse& certificate_response,
Expand Down Expand Up @@ -865,7 +866,7 @@ class ChargePointImpl : ocpp::ChargingStationBase {
/// received.
/// \param callback
void register_is_token_reserved_for_connector_callback(
const std::function<bool(const int32_t connector, const std::string& id_token)>& callback);
const std::function<ReservationCheckStatus(const int32_t connector, const std::string& id_token)>& callback);

void register_session_cost_callback(
const std::function<DataTransferResponse(const RunningCost& running_cost, const uint32_t number_of_decimals)>&
Expand Down
49 changes: 40 additions & 9 deletions include/ocpp/v201/charge_point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "ocpp/v201/messages/Get15118EVCertificate.hpp"
#include <ocpp/v201/messages/Authorize.hpp>
#include <ocpp/v201/messages/BootNotification.hpp>
#include <ocpp/v201/messages/CancelReservation.hpp>
#include <ocpp/v201/messages/CertificateSigned.hpp>
#include <ocpp/v201/messages/ChangeAvailability.hpp>
#include <ocpp/v201/messages/ClearCache.hpp>
Expand Down Expand Up @@ -61,6 +62,7 @@
#include <ocpp/v201/messages/ReportChargingProfiles.hpp>
#include <ocpp/v201/messages/RequestStartTransaction.hpp>
#include <ocpp/v201/messages/RequestStopTransaction.hpp>
#include <ocpp/v201/messages/ReserveNow.hpp>
#include <ocpp/v201/messages/Reset.hpp>
#include <ocpp/v201/messages/SecurityEventNotification.hpp>
#include <ocpp/v201/messages/SendLocalList.hpp>
Expand Down Expand Up @@ -233,6 +235,11 @@ class ChargePointInterface {
/// \param connector_id Reserved connector id
virtual void on_reserved(const int32_t evse_id, const int32_t connector_id) = 0;

/// \brief Event handler that should be called when the reservation of the connector is cleared.
/// \param evse_id Cleared EVSE id
/// \param connector_id Cleared connector id.
virtual void on_reservation_cleared(const int32_t evse_id, const int32_t connector_id) = 0;

/// \brief Event handler that will update the charging state internally when it has been changed.
/// \param evse_id The evse id of which the charging state has changed.
/// \param charging_state The new charging state.
Expand Down Expand Up @@ -274,6 +281,11 @@ class ChargePointInterface {
///
virtual void on_variable_changed(const SetVariableData& set_variable_data) = 0;

/// \brief Event handler that will send a ReservationStatusUpdate request.
/// \param reservation_id The reservation id.
/// \param status The status.
virtual void on_reservation_status(const int32_t reservation_id, const ReservationUpdateStatusEnum status) = 0;

/// @} // End handlers group

/// @}
Expand Down Expand Up @@ -558,16 +570,10 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa
/// \param evse The evse id that must be checked. Reservation will be checked for all connectors.
/// \param id_token The id token to check if it is reserved for that token.
/// \param group_id_token The group id token to check if it is reserved for that group id.
/// \return True when one of the EVSE connectors is reserved for another id token or group id token than the given
/// tokens.
/// If id_token is different than reserved id_token, but group_id_token is equal to reserved group_id_token,
/// returns true.
/// If both are different, returns true.
/// If id_token is equal to reserved id_token or group_id_token is equal, return false.
/// If there is no reservation, return false.
/// \return The status of the reservation for this evse, id token and group id token.
///
bool is_evse_reserved_for_other(EvseInterface& evse, const IdToken& id_token,
const std::optional<IdToken>& group_id_token) const;
ReservationCheckStatus is_evse_reserved_for_other(EvseInterface& evse, const IdToken& id_token,
const std::optional<IdToken>& group_id_token) const;

///
/// \brief Check if one of the connectors of the evse is available (both connectors faulted or unavailable or on of
Expand All @@ -585,6 +591,22 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa
///
void set_evse_connectors_unavailable(EvseInterface& evse, bool persist);

///
/// \brief Check if there is a connector available with the given connector type.
/// \param evse_id The evse to check for.
/// \param connector_type The connector type.
/// \return True when a connector is available and the evse id exists.
///
bool is_connector_available(const uint32_t evse_id, std::optional<ConnectorEnum> connector_type);

///
/// \brief Check if the connector exists on the given evse id.
/// \param evse_id The evse id to check for.
/// \param connector_type The connector type.
/// \return False if evse id does not exist or evse does not have the given connector type.
///
bool does_connector_exist(const uint32_t evse_id, std::optional<ConnectorEnum> connector_type);

/// \brief Get the value optional offline flag
/// \return true if the charge point is offline. std::nullopt if it is online;
bool is_offline();
Expand Down Expand Up @@ -729,6 +751,11 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa
void handle_change_availability_req(Call<ChangeAvailabilityRequest> call);
void handle_heartbeat_response(CallResult<HeartbeatResponse> call);

// Function Block H: Reservations
void handle_reserve_now_request(Call<ReserveNowRequest> call);
void handle_cancel_reservation_callback(Call<CancelReservationRequest> call);
void send_reserve_now_rejected_response(const MessageId& unique_id, const std::string& status_info);

// Functional Block I: TariffAndCost
void handle_costupdated_req(const Call<CostUpdatedRequest> call);

Expand Down Expand Up @@ -914,6 +941,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa

void on_reserved(const int32_t evse_id, const int32_t connector_id) override;

void on_reservation_cleared(const int32_t evse_id, const int32_t connector_id) override;

bool on_charging_state_changed(
const uint32_t evse_id, const ChargingStateEnum charging_state,
const TriggerReasonEnum trigger_reason = TriggerReasonEnum::ChargingStateChanged) override;
Expand All @@ -933,6 +962,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa

void on_variable_changed(const SetVariableData& set_variable_data) override;

void on_reservation_status(const int32_t reservation_id, const ReservationUpdateStatusEnum status) override;

std::optional<DataTransferResponse> data_transfer_req(const CiString<255>& vendorId,
const std::optional<CiString<50>>& messageId,
const std::optional<json>& data) override;
Expand Down
14 changes: 10 additions & 4 deletions include/ocpp/v201/charge_point_callbacks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <ocpp/v201/messages/GetDisplayMessages.hpp>
#include <ocpp/v201/messages/GetLog.hpp>
#include <ocpp/v201/messages/RequestStartTransaction.hpp>
#include <ocpp/v201/messages/ReserveNow.hpp>
#include <ocpp/v201/messages/SetDisplayMessage.hpp>
#include <ocpp/v201/messages/TransactionEvent.hpp>
#include <ocpp/v201/messages/UnlockConnector.hpp>
Expand Down Expand Up @@ -78,13 +79,13 @@ struct Callbacks {
std::function<RequestStartStopStatusEnum(const RequestStartTransactionRequest& request,
const bool authorize_remote_start)>
remote_start_transaction_callback;

///
/// \brief Check if the current reservation for the given evse id is made for the id token / group id token.
/// \return True if evse is reserved for the given id token / group id token, false if it is reserved for another
/// one.
/// \return The reservation check status of this evse / id token.
///
std::function<bool(const int32_t evse_id, const CiString<36> idToken,
const std::optional<CiString<36>> groupIdToken)>
std::function<ocpp::ReservationCheckStatus(const int32_t evse_id, const CiString<36> idToken,
const std::optional<CiString<36>> groupIdToken)>
is_reservation_for_token_callback;
std::function<UpdateFirmwareResponse(const UpdateFirmwareRequest& request)> update_firmware_request_callback;
// callback to be called when a variable has been changed by the CSMS
Expand Down Expand Up @@ -160,6 +161,11 @@ struct Callbacks {
std::optional<std::string> currency_code)>>
set_running_cost_callback;

/// \brief Callback function is called when a reservation request is received from the CSMS
std::optional<std::function<ReserveNowStatusEnum(const ReserveNowRequest& request)>> reserve_now_callback;
/// \brief Callback function is called when a cancel reservation request is received from the CSMS
std::optional<std::function<bool(const int32_t reservationId)>> cancel_reservation_callback;

/// @} // End ocpp 201 callbacks group / topic

/// @} // End group
Expand Down
29 changes: 29 additions & 0 deletions include/ocpp/v201/evse.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ class EvseInterface {
/// \return
virtual uint32_t get_number_of_connectors() const = 0;

///
/// \brief Check if the given connector type exists on this evse.
/// \param connector_type The connector type to check.
/// \return True if connector type is unknown or this evse has the given connector type.
///
virtual bool does_connector_exist(ConnectorEnum connector_type) = 0;

///
/// \brief Get connector status.
///
/// This will search if there is a connector on this evse with status 'Available'. It will search through all
/// connectors, optionally filtering by connector type, and return on the first connector that is 'Available'. If
/// there is no 'Available' connector, it will return the status of the last found connector with the given
/// connector type.
///
/// \param connector_type The connector type to filter on (optional).
/// \return Connector status. If connector type is given and does not exist, std::nullopt.
///
virtual std::optional<ConnectorStatusEnum> get_connector_status(std::optional<ConnectorEnum> connector_type) = 0;

/// \brief Opens a new transaction
/// \param transaction_id id of the transaction
/// \param connector_id id of the connector
Expand Down Expand Up @@ -198,6 +218,13 @@ class Evse : public EvseInterface {
/// \brief Component responsible for maintaining and persisting the operational status of CS, EVSEs, and connectors.
std::shared_ptr<ComponentStateManagerInterface> component_state_manager;

///
/// \brief Get connector type of Connector
/// \param connector_id Connector id
/// \return The connector type. If evse or connector id is not correct: std::nullopt.
///
std::optional<ConnectorEnum> get_evse_connector_type(const uint32_t connector_id);

public:
/// \brief Construct a new Evse object
/// \param evse_id id of the evse
Expand All @@ -220,6 +247,8 @@ class Evse : public EvseInterface {
int32_t get_id() const;

uint32_t get_number_of_connectors() const;
bool does_connector_exist(const ConnectorEnum connector_type) override;
std::optional<ConnectorStatusEnum> get_connector_status(std::optional<ConnectorEnum> connector_type) override;

void open_transaction(const std::string& transaction_id, const int32_t connector_id, const DateTime& timestamp,
const MeterValue& meter_start, const std::optional<IdToken>& id_token,
Expand Down
4 changes: 2 additions & 2 deletions include/ocpp/v201/evse_manager.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ class EvseManager : public EvseManagerInterface {
const std::function<void(int32_t evse_id)>& pause_charging_callback);

EvseInterface& get_evse(int32_t id) override;
const EvseInterface& get_evse(int32_t id) const override;
const EvseInterface& get_evse(const int32_t id) const override;

bool does_evse_exist(int32_t id) const override;
bool does_evse_exist(const int32_t id) const override;

size_t get_number_of_evses() const override;

Expand Down
2 changes: 1 addition & 1 deletion lib/ocpp/v16/charge_point.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ void ChargePoint::register_security_event_callback(
}

void ChargePoint::register_is_token_reserved_for_connector_callback(
const std::function<bool(const int32_t connector, const std::string& id_token)>& callback) {
const std::function<ocpp::ReservationCheckStatus(const int32_t connector, const std::string& id_token)>& callback) {
this->charge_point->register_is_token_reserved_for_connector_callback(callback);
}

Expand Down
2 changes: 1 addition & 1 deletion lib/ocpp/v16/charge_point_configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1512,7 +1512,7 @@ std::optional<KeyValue> ChargePointConfiguration::getReserveConnectorZeroSupport
KeyValue kv;
kv.key = "ReserveConnectorZeroSupported";
kv.readonly = true;
kv.value.emplace(std::to_string(reserve_connector_zero_supported.value()));
kv.value.emplace(ocpp::conversions::bool_to_string(reserve_connector_zero_supported.value()));
reserve_connector_zero_supported_kv.emplace(kv);
}
return reserve_connector_zero_supported_kv;
Expand Down
Loading

0 comments on commit 173af8d

Please sign in to comment.