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:
Eric F
2026-06-08 00:38:27 -04:00
parent 468cfeaa50
commit d398a6ced2
7326 changed files with 1177561 additions and 7 deletions

View File

@@ -0,0 +1,94 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include <everest/logging.hpp>
#include <everest/timer.hpp>
#include <ocpp/common/types.hpp>
namespace ocpp {
class ClockAlignedTimer : private Everest::Timer<std::chrono::system_clock> {
public:
using system_time_point = std::chrono::time_point<std::chrono::system_clock>;
private:
system_time_point start_point;
std::chrono::seconds call_interval = std::chrono::seconds(0);
std::function<void()> callback;
system_time_point get_next_timepoint() {
using namespace std::chrono_literals;
auto now = std::chrono::system_clock::now();
auto diff = now - this->start_point;
auto time_to_next = 0s;
// Only calculate next time if it is positive. Otherwise we would end up before the start point
if (diff > 0s) {
time_to_next = ((std::chrono::duration_cast<std::chrono::seconds>(diff) / this->call_interval) + 1) *
this->call_interval;
}
auto next_time = this->start_point + time_to_next;
EVLOG_debug << "Clock aligned interval every " << this->call_interval.count() << " seconds, starting at "
<< ocpp::DateTime(date::utc_clock::from_sys(this->start_point))
<< ". Next one at: " << ocpp::DateTime(date::utc_clock::from_sys(next_time));
EVLOG_debug << "This amounts to "
<< std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(24)) / this->call_interval
<< " samples per day";
return next_time;
}
system_time_point call_next() {
if (this->callback == nullptr or this->call_interval.count() == 0) {
return system_time_point{};
}
auto wrapper = [this]() {
this->callback();
this->at(this->get_next_timepoint());
};
auto next_timepoint = this->get_next_timepoint();
this->at(wrapper, next_timepoint);
return next_timepoint;
}
public:
ClockAlignedTimer() = default;
explicit ClockAlignedTimer(boost::asio::io_context* io_context) : Timer(io_context) {
}
explicit ClockAlignedTimer(boost::asio::io_context* io_context, const std::function<void()>& callback) :
Timer(io_context), callback(callback) {
}
template <class Rep, class Period>
system_time_point interval_starting_from(const std::function<void()>& callback,
const std::chrono::duration<Rep, Period> interval,
system_time_point start_point) {
this->callback = callback;
return this->interval_starting_from(interval, start_point);
}
template <class Rep, class Period>
system_time_point interval_starting_from(const std::chrono::duration<Rep, Period> interval,
system_time_point start_point) {
this->start_point = start_point;
this->call_interval = interval;
return this->call_next();
}
template <class Rep, class Period>
system_time_point set_interval(const std::chrono::duration<Rep, Period>& interval) {
this->call_interval = interval;
return this->call_next();
}
using Everest::Timer<std::chrono::system_clock>::stop;
};
} // namespace ocpp

View File

@@ -0,0 +1,162 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_CALL_TYPES_HPP
#define OCPP_COMMON_CALL_TYPES_HPP
#include <iostream>
#include <nlohmann/json_fwd.hpp>
#include <sstream>
#include <stdexcept>
#include <chrono>
#include <cstddef>
#include <string>
#include <ocpp/common/cistring.hpp>
using json = nlohmann::json;
namespace ocpp {
// The locations inside the message array
const auto MESSAGE_TYPE_ID = 0;
const auto MESSAGE_ID = 1;
const auto CALL_ACTION = 2;
const auto CALL_PAYLOAD = 3;
const auto CALLRESULT_PAYLOAD = 2;
const auto CALLERROR_ERROR_CODE = 2;
const auto CALLERROR_ERROR_DESCRIPTION = 3;
const auto CALLERROR_ERROR_DETAILS = 4;
/// \brief Contains a MessageId implementation based on a case insensitive string with a maximum length of 36 printable
/// ASCII characters
class MessageId : public CiString<36> {
using CiString::CiString;
};
/// \brief Comparison operator< between two MessageId \p lhs and \p rhs
bool operator<(const MessageId& lhs, const MessageId& rhs);
/// \brief Conversion from a given MessageId \p k to a given json object \p j
void to_json(json& j, const MessageId& k);
/// \brief Conversion from a given json object \p j to a given MessageId \p k
void from_json(const json& j, MessageId& k);
/// \brief Contains the different message type ids
enum class MessageTypeId {
CALL = 2,
CALLRESULT = 3,
CALLERROR = 4,
UNKNOWN = 5,
};
/// \brief Creates a unique message ID
/// \returns the unique message ID
MessageId create_message_id();
/// \brief Contains a OCPP Call message
template <class T> struct Call {
T msg;
MessageId uniqueId;
/// \brief Creates a new Call message object
Call() = default;
/// \brief Creates a new Call message object with the given OCPP message \p msg
explicit Call(T msg) : msg(msg) {
this->uniqueId = create_message_id();
}
/// \brief Creates a new Call message object with the given OCPP message \p msg and \p uniqueId
Call(T msg, MessageId uniqueId) : msg(msg), uniqueId(uniqueId) {
}
/// \brief Conversion from a given Call message \p c to a given json object \p j
friend void to_json(json& j, const Call& c) {
j = json::array();
j.push_back(MessageTypeId::CALL);
j.push_back(c.uniqueId.get());
j.push_back(c.msg.get_type());
j.push_back(json(c.msg));
}
/// \brief Conversion from a given json object \p j to a given Call message \p c
friend void from_json(const json& j, Call& c) {
// the required parts of the message
c.msg = j.at(CALL_PAYLOAD);
c.uniqueId.set(j.at(MESSAGE_ID));
}
/// \brief Writes the given case Call \p c to the given output stream \p os
/// \returns an output stream with the Call written to
friend std::ostream& operator<<(std::ostream& os, const Call& c) {
os << json(c).dump(4);
return os;
}
};
/// \brief Contains a OCPP CallResult message
template <class T> struct CallResult {
T msg;
MessageId uniqueId;
/// \brief Creates a new CallResult message object
CallResult() = default;
/// \brief Creates a new CallResult message object with the given OCPP message \p msg and \p uniqueID
CallResult(T msg, MessageId uniqueId) : msg(msg), uniqueId(uniqueId) {
}
/// \brief Conversion from a given CallResult message \p c to a given json object \p j
friend void to_json(json& j, const CallResult& c) {
j = json::array();
j.push_back(MessageTypeId::CALLRESULT);
j.push_back(c.uniqueId.get());
j.push_back(json(c.msg));
}
/// \brief Conversion from a given json object \p j to a given CallResult message \p c
friend void from_json(const json& j, CallResult& c) {
// the required parts of the message
c.msg = j.at(CALLRESULT_PAYLOAD);
c.uniqueId.set(j.at(MESSAGE_ID));
}
/// \brief Writes the given case CallResult \p c to the given output stream \p os
/// \returns an output stream with the CallResult written to
friend std::ostream& operator<<(std::ostream& os, const CallResult& c) {
os << json(c).dump(4);
return os;
}
};
/// \brief Contains a OCPP CallError message
struct CallError {
MessageId uniqueId;
std::string errorCode;
std::string errorDescription;
json errorDetails;
/// \brief Creates a new CallError message object
CallError();
/// \brief Creates a new CallResult message object with the given \p uniqueID \p errorCode \p errorDescription and
/// \p errorDetails
CallError(const MessageId& uniqueId, const std::string& errorCode, const std::string& errorDescription,
const json& errorDetails);
};
/// \brief Conversion from a given CallError message \p c to a given json object \p j
void to_json(json& j, const CallError& c);
/// \brief Conversion from a given json object \p j to a given CallError message \p c
void from_json(const json& j, CallError& c);
/// \brief Writes the given case CallError \p c to the given output stream \p os
/// \returns an output stream with the CallError written to
std::ostream& operator<<(std::ostream& os, const CallError& c);
} // namespace ocpp
#endif

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_CHARGE_POINT_HPP
#define OCPP_COMMON_CHARGE_POINT_HPP
#include <boost/shared_ptr.hpp>
#include <ocpp/common/evse_security.hpp>
#include <ocpp/common/evse_security_impl.hpp>
#include <ocpp/common/message_queue.hpp>
#include <ocpp/common/ocpp_logging.hpp>
namespace ocpp {
/// \brief Common base class for OCPP1.6 and OCPP2.0.1 charging stations
class ChargingStationBase {
protected:
std::shared_ptr<EvseSecurity> evse_security;
std::shared_ptr<MessageLogging> logging;
boost::shared_ptr<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> work;
boost::asio::io_context io_context;
std::thread io_context_thread;
public:
/// \brief Constructor for ChargingStationBase
/// \param evse_security Pointer to evse_security that manages security related operations; if nullptr
/// security_configuration must be set
/// \param security_configuration specifies the file paths that are required to set up the internal evse_security
/// implementation
explicit ChargingStationBase(const std::shared_ptr<EvseSecurity>& evse_security,
const std::optional<SecurityConfiguration>& security_configuration = std::nullopt);
virtual ~ChargingStationBase();
};
} // namespace ocpp
#endif // OCPP_COMMON

View File

@@ -0,0 +1,96 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_CISTRING_HPP
#define OCPP_COMMON_CISTRING_HPP
#include <nlohmann/json.hpp>
#include <ocpp/common/string.hpp>
#include <ocpp/common/utils.hpp>
using json = nlohmann::json;
namespace ocpp {
/// \brief Contains a CaseInsensitive string implementation that only allows printable ASCII characters
template <size_t L> class CiString : public String<L> {
public:
/// \brief Creates a string from the given \p data
CiString(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) : String<L>(data, to_large) {
}
CiString(const char* data, StringTooLarge to_large = StringTooLarge::Throw) : String<L>(data, to_large) {
}
CiString(const CiString<L>& data) : String<L>(data.get()) {
}
/// \brief Creates a string
CiString() : String<L>() {
}
CiString(CiString&&) = default;
CiString& operator=(const CiString&) = default;
CiString& operator=(CiString&&) = default;
/// \brief CaseInsensitive string implementation only allows printable ASCII characters
bool is_valid(std::string_view data) {
for (const char& character : data) {
// printable ASCII starts at code 0x20 (space) and ends with code 0x7e (tilde) and 0xa (\n)
if ((character < 0x20 || character > 0x7e) && character != 0xa) {
throw std::runtime_error("CiString can only contain printable ASCII characters");
}
}
return true;
}
/// \brief Conversion operator to turn a String into std::string
operator std::string() const {
return this->get();
}
};
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator==(const CiString<L>& lhs, const char* rhs) {
return iequals(lhs.get(), rhs);
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator==(const CiString<L>& lhs, const CiString<L>& rhs) {
return iequals(lhs.get(), rhs.get());
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator!=(const CiString<L>& lhs, const char* rhs) {
return !(lhs.get() == rhs);
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator!=(const CiString<L>& lhs, const CiString<L>& rhs) {
return !(lhs.get() == rhs.get());
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator<(const CiString<L>& lhs, const CiString<L>& rhs) {
return lhs.get() < rhs.get();
}
/// \brief Writes the given string \p str to the given output stream \p os
/// \returns an output stream with the case insensitive string written to
template <size_t L> std::ostream& operator<<(std::ostream& os, const CiString<L>& str) {
os << str.get();
return os;
}
template <size_t L> void to_json(json& j, const CiString<L>& k) {
j = json(k.get());
}
template <size_t L> void from_json(const json& j, CiString<L>& k) {
k.set(j);
}
} // namespace ocpp
#endif

View File

@@ -0,0 +1,318 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/common/websocket/websocket.hpp>
#include <ocpp/v2/messages/SetNetworkProfile.hpp>
#include <ocpp/v2/ocpp_types.hpp>
#include <everest/util/async/monitor.hpp>
#include <atomic>
#include <chrono>
#include <functional>
#include <future>
#include <optional>
namespace ocpp {
namespace v2 {
class DeviceModelAbstract;
} // namespace v2
/// \brief The result of a configuration of a network profile.
struct ConfigNetworkResult {
std::optional<std::string> interface_address; ///< ip address or interface string
bool success; ///< true if the configuration was successful
};
using WebsocketConnectionCallback =
std::function<void(int configuration_slot, const ocpp::v2::NetworkConnectionProfile& network_connection_profile,
const OcppProtocolVersion version)>;
using WebsocketConnectionFailedCallback = std::function<void(ConnectionFailedReason reason)>;
using ConfigureNetworkConnectionProfileCallback = std::function<std::future<ConfigNetworkResult>(
const std::int32_t configuration_slot, const ocpp::v2::NetworkConnectionProfile& network_connection_profile)>;
class ConnectivityManagerInterface {
public:
virtual ~ConnectivityManagerInterface() = default;
/// \brief Set the \p callback that is called when a message is received from the websocket
///
virtual void set_message_callback(const std::function<void(const std::string& message)>& callback) = 0;
/// \brief Set the logger \p logging
///
virtual void set_logging(std::shared_ptr<MessageLogging> logging) = 0;
/// \brief Set the websocket \p authorization_key
///
virtual void set_websocket_authorization_key(const std::string& authorization_key) = 0;
/// \brief Set the websocket \p connection_options
///
virtual void set_websocket_connection_options(const WebsocketConnectionOptions& connection_options) = 0;
/// \brief Set the websocket connection options without triggering a reconnect
///
virtual void set_websocket_connection_options_without_reconnect() = 0;
/// \brief Set the \p callback that is called when the websocket is connected.
///
virtual void set_websocket_connected_callback(WebsocketConnectionCallback callback) = 0;
/// \brief Set the \p callback that is called when the websocket is disconnected.
///
virtual void set_websocket_disconnected_callback(WebsocketConnectionCallback callback) = 0;
/// \brief Set the \p callback that is called when the websocket could not connect with a specific reason
///
virtual void set_websocket_connection_failed_callback(WebsocketConnectionFailedCallback callback) = 0;
/// \brief Set the \p callback that is called to configure a network connection profile when none is configured
///
virtual void
set_configure_network_connection_profile_callback(ConfigureNetworkConnectionProfileCallback callback) = 0;
/// \brief Gets the cached NetworkConnectionProfile based on the given \p configuration_slot.
/// This returns the value from the cached network connection profiles.
/// \return Returns a profile if the slot is found
virtual std::optional<ocpp::v2::NetworkConnectionProfile>
get_network_connection_profile(const std::int32_t configuration_slot) const = 0;
/// \brief Get the priority of the given configuration slot.
/// \param configuration_slot The configuration slot to get the priority from.
/// \return The priority if the configuration slot exists.
///
virtual std::optional<std::int32_t>
get_priority_from_configuration_slot(const std::int32_t configuration_slot) const = 0;
/// @brief Get a snapshot of the network connection slots sorted by priority.
/// Each item in the vector contains the configured configuration slots, where the slot with index 0 has the highest
/// priority. A copy is returned so callers do not observe mid-mutation state through a reference.
/// @return The network connection slots
///
virtual std::vector<int> get_network_connection_slots() const = 0;
/// \brief Check if the websocket is connected
/// \return True is the websocket is connected, else false
///
virtual bool is_websocket_connected() = 0;
/// @brief Get the time the websocket has been disconnected.
/// @return The time the websocket has been disconnected
///
virtual std::chrono::time_point<std::chrono::steady_clock> get_time_disconnected() const = 0;
/// \brief Connect to the websocket
/// \param configuration_slot Optional the network_profile_slot to connect to. std::nullopt will select the slot
/// internally.
///
virtual void connect(std::optional<std::int32_t> network_profile_slot = std::nullopt) = 0;
/// \brief Disconnect the websocket
///
virtual void disconnect() = 0;
/// \brief send a \p message over the websocket
/// \returns true if the message was sent successfully
///
virtual bool send_to_websocket(const std::string& message) = 0;
///
/// \brief Can be called when a network is disconnected, for example when an ethernet cable is removed.
///
/// This is introduced because the websocket can take several minutes to timeout when a network interface becomes
/// unavailable, whereas the system can detect this sooner.
///
/// \param ocpp_interface The interface that is disconnected.
///
virtual void on_network_disconnected(ocpp::v2::OCPPInterfaceEnum ocpp_interface) = 0;
/// \brief Called when the charging station certificate is changed
///
virtual void on_charging_station_certificate_changed() = 0;
/// \brief Confirms the connection is successful so the security profile requirements can be handled
virtual void confirm_successful_connection() = 0;
/// \brief Reload network connection profiles from NetworkConfiguration DM components into the in-memory cache
virtual void reload_network_profiles() = 0;
/// \brief Write a network connection profile to the device model and refresh the in-memory cache.
/// \param slot The configuration slot to write to
/// \param profile The profile to write
/// \param source The source of the change (e.g. 'csms', 'internal')
/// \return true if the profile was written successfully
virtual bool set_network_profile(int32_t slot, const ocpp::v2::NetworkConnectionProfile& profile,
const std::string& source) = 0;
};
class ConnectivityManager : public ConnectivityManagerInterface {
private:
/// \brief Reference to the device model
ocpp::v2::DeviceModelAbstract& device_model;
/// \brief Pointer to the evse security class
std::shared_ptr<EvseSecurity> evse_security;
/// \brief Pointer to the logger
std::shared_ptr<MessageLogging> logging;
/// \brief The share path
fs::path share_path;
/// \brief Pointer to the websocket
std::unique_ptr<Websocket> websocket;
/// \brief The message callback
std::function<void(const std::string& message)> message_callback;
/// \brief Callback that is called when the websocket is connected successfully
std::optional<WebsocketConnectionCallback> websocket_connected_callback;
/// \brief Callback that is called when the websocket connection is disconnected
std::optional<WebsocketConnectionCallback> websocket_disconnected_callback;
/// \brief Callback that is called when the websocket could not connect with a specific reason
std::optional<WebsocketConnectionFailedCallback> websocket_connection_failed_callback;
/// \brief Callback that is called to configure a network connection profile when none is configured
std::optional<ConfigureNetworkConnectionProfileCallback> configure_network_connection_profile_callback;
Everest::SteadyTimer websocket_timer;
bool wants_to_be_connected;
OcppProtocolVersion connected_ocpp_version;
/// @brief Mutable shared state, accessed concurrently from the OCPP message-handling thread,
/// the websocket callback thread, and the websocket_timer thread. All access goes through the
/// monitor handle, which acquires a recursive mutex for the handle's lifetime.
struct NetworkProfileCacheState {
/// Cached NetworkConnectionProfile entries reflecting the per-slot NetworkConfiguration DM variables.
std::vector<ocpp::v2::SetNetworkProfileRequest> cached_profiles;
/// Ordered list of configuration slots (highest priority first) derived from NetworkConfigurationPriority.
std::vector<std::int32_t> slots;
/// Index into \c slots of the slot currently considered active.
std::int32_t active_priority{0};
/// Slot currently being evaluated by \c try_connect_websocket (overrides active_priority if set).
std::optional<std::int32_t> pending_configuration_slot;
/// Last SecurityProfile value observed when pruning invalid profiles from the cache.
int last_known_security_level{0};
};
mutable everest::lib::util::monitor<NetworkProfileCacheState, std::recursive_mutex> m_state;
public:
ConnectivityManager(ocpp::v2::DeviceModelAbstract& device_model, std::shared_ptr<EvseSecurity> evse_security,
const fs::path& share_path = {});
void reload_network_profiles() override;
bool set_network_profile(int32_t slot, const ocpp::v2::NetworkConnectionProfile& profile,
const std::string& source) override;
void set_message_callback(const std::function<void(const std::string& message)>& callback) override;
void set_logging(std::shared_ptr<MessageLogging> logging) override;
void set_websocket_authorization_key(const std::string& authorization_key) override;
void set_websocket_connection_options(const WebsocketConnectionOptions& connection_options) override;
void set_websocket_connection_options_without_reconnect() override;
void set_websocket_connected_callback(WebsocketConnectionCallback callback) override;
void set_websocket_disconnected_callback(WebsocketConnectionCallback callback) override;
void set_websocket_connection_failed_callback(WebsocketConnectionFailedCallback callback) override;
void set_configure_network_connection_profile_callback(ConfigureNetworkConnectionProfileCallback callback) override;
std::optional<ocpp::v2::NetworkConnectionProfile>
get_network_connection_profile(const std::int32_t configuration_slot) const override;
std::optional<std::int32_t>
get_priority_from_configuration_slot(const std::int32_t configuration_slot) const override;
std::vector<int> get_network_connection_slots() const override;
bool is_websocket_connected() override;
std::chrono::time_point<std::chrono::steady_clock> get_time_disconnected() const override;
void connect(std::optional<std::int32_t> network_profile_slot = std::nullopt) override;
void disconnect() override;
bool send_to_websocket(const std::string& message) override;
void on_network_disconnected(ocpp::v2::OCPPInterfaceEnum ocpp_interface) override;
void on_charging_station_certificate_changed() override;
void confirm_successful_connection() override;
/// \brief Removes all connection profiles from the cache that have a security profile lower than the currently
/// connected security profile
void check_cache_for_invalid_security_profiles();
private:
std::atomic<std::chrono::time_point<std::chrono::steady_clock>> time_disconnected{};
/// \brief Mark \c time_disconnected with steady_clock::now() iff currently unset (zero).
/// Atomic compare-exchange so concurrent disconnect callbacks cannot overwrite the
/// first observed disconnect time.
void mark_disconnected_at_now();
/// \brief Initializes the websocket and tries to connect
///
void try_connect_websocket();
/// \brief Get the current websocket connection options
/// \return the current websocket connection options
///
std::optional<WebsocketConnectionOptions> get_ws_connection_options(const std::int32_t configuration_slot);
/// \brief Resolve the Identity to use for the given slot. Per-slot Identity overrides
/// SecurityCtrlr.Identity (B09.FR.16-18) when present and non-empty.
std::string resolve_identity(std::int32_t configuration_slot) const;
/// \brief Resolve the BasicAuthPassword to use for the given slot. Per-slot BasicAuthPassword
/// overrides the global SecurityCtrlr.BasicAuthPassword (B09.FR.26-28) when present
/// and non-empty.
std::optional<std::string> resolve_basic_auth_password(std::int32_t configuration_slot) const;
/// \brief Read the everest version string from the deployed version_information.txt,
/// next to the binary. Returns nullopt if the file is missing or contains no usable line.
std::optional<std::string> read_everest_version() const;
/// \brief Calls the configuration callback to get the interface to use, if there is a callback
/// \param slot The configuration slot to get the interface for
/// \param profile The network connection profile to get the interface for
///
/// \return The network configuration containing the network interface to use, nullptr if the request failed or the
/// callback is not configured
std::optional<ConfigNetworkResult>
handle_configure_network_connection_profile_callback(int slot, const ocpp::v2::NetworkConnectionProfile& profile);
/// \brief Function invoked when the web socket connected with the \p security_profile
///
void on_websocket_connected(OcppProtocolVersion protocol);
/// \brief Function invoked when the web socket disconnected
///
void on_websocket_disconnected();
/// \brief Function invoked when the web socket stops connecting
/// and does not re-attempt to connect again
///
void on_websocket_stopped_connecting(ocpp::WebsocketCloseReason reason);
///
/// \brief Get the active network configuration slot in use.
/// \return The active slot (or pending slot override) if one is available, std::nullopt if the slot
/// list is empty or the current priority index would be out of range.
///
std::optional<int> get_active_network_configuration_slot() const;
///
/// \brief Get the network configuration slot of the given priority.
/// \param priority The priority to get the configuration slot.
/// \return The configuration slot if \p priority is a valid index, std::nullopt otherwise.
///
std::optional<int> get_configuration_slot_from_priority(const int priority);
///
/// \brief Get the next prioritized network configuration slot of the given configuration slot.
/// \param configuration_slot The current configuration slot.
/// \return The next prioritized configuration slot, or std::nullopt if the slot list is empty.
///
std::optional<int> get_next_configuration_slot(std::int32_t configuration_slot);
/// \brief Append the given slot to NetworkConfigurationPriority if it is not already listed.
void append_slot_to_network_configuration_priority_if_absent(int32_t slot, const std::string& source);
/// \brief Cache all the network connection profiles
void cache_network_connection_profiles();
/// \brief Log an error if all cached profiles have security_profile 0. Caller must hold the state lock.
void warn_if_all_security_level_zero_locked(const NetworkProfileCacheState& state) const;
/// \brief Removes all NetworkConfiguration DM slots and in-memory cache entries for profiles that have a security
/// profile lower than the currently connected security profile, and persists the updated
/// NetworkConfigurationPriority
void remove_network_connection_profiles_below_actual_security_profile();
};
} // namespace ocpp

View File

@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#pragma once
#include <chrono>
#include <cstdint>
#include <string>
namespace ocpp {
// Time
constexpr std::int32_t DAYS_PER_WEEK = 7;
constexpr std::int32_t HOURS_PER_DAY = 24;
constexpr std::int32_t SECONDS_PER_HOUR = 3600;
constexpr std::int32_t SECONDS_PER_DAY = 86400;
constexpr float DEFAULT_LIMIT_AMPS = 48.0;
constexpr float DEFAULT_LIMIT_WATTS = 33120.0;
constexpr std::int32_t DEFAULT_AND_MAX_NUMBER_PHASES = 3;
constexpr float LOW_VOLTAGE = 230;
constexpr float NO_LIMIT_SPECIFIED = -1.0;
constexpr float NO_SETPOINT_SPECIFIED = std::numeric_limits<float>::max();
constexpr float NO_DISCHARGE_LIMIT_SPECIFIED = -std::numeric_limits<float>::max();
constexpr std::int32_t NO_START_PERIOD = -1;
constexpr std::int32_t EVSEID_NOT_SET = -1;
constexpr std::chrono::seconds DEFAULT_WAIT_FOR_FUTURE_TIMEOUT = std::chrono::seconds(60);
const std::string VARIABLE_ATTRIBUTE_VALUE_SOURCE_INTERNAL = "internal";
const std::string VARIABLE_ATTRIBUTE_VALUE_SOURCE_CSMS = "csms";
} // namespace ocpp

View File

@@ -0,0 +1,97 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#pragma once
#include <memory>
#include <vector>
namespace ocpp {
// This file contains the implementation of a couple of custom iterators, enabling the iteration and abstraction of more
// complex containers. For example we want to be able to iterate a std::vector<std::unique_ptr<T>> and get references to
// T from the iterator
//
// ForwardIterator<T> implements a custom iterator for type T that does not depend on any underlying container.
// You can add this for your type by returning ForwardIterator<T> from begin() and end()
// ForwardIterator can only be constructed by passing a ForwardIteratorBase derived struct in a unique_ptr.
// ForwardIteratorBase is an abstract class that allows us to implement container specific functionality.
// VectorOfUniquePtrIterator is an implementation of the ForwardIteratorBase specifically catered to the example of
// std::vector<std:unique_ptr<T>>
// So to implement the begin() and end() functions for your type, you could do the following:
// std::vector<std::unique_ptr<T>> container;
// ForwardIterator<T> begin() {
// return ForwardIterator<T>(std::make_unique<VectorOfUniquePtrIterator<T>>(container.begin()));
// }
/// \brief Abstract struct to implement to enable the use of the ForwardIterator<T>
template <typename T> struct ForwardIteratorBase {
virtual ~ForwardIteratorBase() = default;
/// \brief Get a reference to the value pointed to by the iterator
virtual T& deref() const = 0;
/// \brief Increment the iterator once to the next position
virtual void advance() = 0;
/// \brief Check for equality between this iterator and \p other
virtual bool not_equal(const ForwardIteratorBase& other) = 0;
};
/// \brief Helper struct that allows the use of an iterator in an interface, can be implemented using any forward
/// iterator
template <typename T> struct ForwardIterator {
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = value_type*;
using reference = value_type&;
using base = ForwardIteratorBase<T>;
/// \brief Construct a new wrapper using any type that implements the abstract struct Base
explicit ForwardIterator(std::unique_ptr<base> it) : it{std::move(it)} {
}
/// \brief Get a reference to the value pointed to by the iterator
reference operator*() const {
return it->deref();
};
/// \brief Increment the iterator once to the next position
ForwardIterator& operator++() {
it->advance();
return *this;
}
/// \brief Check for inequality between this \p a and \p b
friend bool operator!=(const ForwardIterator& a, const ForwardIterator& b) {
return a.it->not_equal(*b.it);
};
private:
std::unique_ptr<base> it;
};
/// \brief Implementation for the ForwardIteratorBase based on a vector of unique_ptr with type T
template <typename T> struct VectorOfUniquePtrIterator : ForwardIteratorBase<T> {
using iterator_type = typename std::vector<std::unique_ptr<T>>::iterator;
using base = ForwardIteratorBase<T>;
explicit VectorOfUniquePtrIterator(iterator_type it) : it{it} {
}
T& deref() const override {
return *it->get();
}
void advance() override {
++it;
}
bool not_equal(const base& other) override {
return it != dynamic_cast<const VectorOfUniquePtrIterator&>(other).it;
}
private:
iterator_type it;
};
} // namespace ocpp

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include <memory>
#include <string>
#include <vector>
#include <everest/database/exceptions.hpp>
#include <everest/database/sqlite/connection.hpp>
#include <ocpp/common/types.hpp>
namespace ocpp::common {
struct DBTransactionMessage {
json json_message;
std::string message_type;
std::int32_t message_attempts;
DateTime timestamp;
std::string unique_id;
};
class DatabaseHandlerCommon {
protected:
std::unique_ptr<everest::db::sqlite::ConnectionInterface> database;
const fs::path sql_migration_files_path;
const std::uint32_t target_schema_version;
/// \brief Perform the initialization needed to use the database. Will be called by open_connection()
virtual void init_sql() = 0;
public:
/// \brief Common database handler class
/// Class handles some common database functionality like inserting and removing transaction messages.
///
/// \param database Interface for the database connection
/// \param sql_migration_files_path Filesystem path to migration file folder
/// \param target_schema_version The required schema version of the database
explicit DatabaseHandlerCommon(std::unique_ptr<everest::db::sqlite::ConnectionInterface> database,
const fs::path& sql_migration_files_path,
std::uint32_t target_schema_version) noexcept;
virtual ~DatabaseHandlerCommon() = default;
/// \brief Opens connection to database file and performs the initialization by calling init_sql()
void open_connection();
/// \brief Closes the database connection.
void close_connection();
/// \brief Get messages from messages queue table specified by \p queue_type
/// \param queue_type , defaults to QueueType::Transaction
/// \return The transaction messages.
virtual std::vector<DBTransactionMessage>
get_message_queue_messages(const QueueType queue_type = QueueType::Transaction);
/// \brief Insert a new message into messages queue table specified by \p queue_type
/// \param message The message to be stored.
/// \param queue_type , defaults to QueueType::Transaction
virtual void insert_message_queue_message(const DBTransactionMessage& message,
const QueueType queue_type = QueueType::Transaction);
/// \brief Remove a message from the messages queue table specified by \p queue_type
/// \param unique_id The unique id of the transaction message
/// \param queue_type , defaults to QueueType::Transaction
/// \return True on success.
virtual void remove_message_queue_message(const std::string& unique_id,
const QueueType queue_type = QueueType::Transaction);
/// \brief Deletes all entries from message queue table specified by \p queue_type
/// \param queue_type , defaults to QueueType::Transaction
virtual void clear_message_queue(const QueueType queue_type = QueueType::Transaction);
};
} // namespace ocpp::common

View File

@@ -0,0 +1,166 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_EVSE_SECURITY
#define OCPP_COMMON_EVSE_SECURITY
#include <filesystem>
#include <fstream>
#include <memory>
#include <string>
#include <ocpp/common/types.hpp>
#include <ocpp/v2/ocpp_types.hpp>
namespace ocpp {
/// \brief Handler for security related operations of the charging station
class EvseSecurity {
public:
virtual ~EvseSecurity() = default;
/// \brief Installs the CA \p certificate for the given \p certificate_type . This function respects the
/// requirements of OCPP specified for the CSMS initiated message InstallCertificate.req .
/// \param certificate PEM formatted CA certificate
/// \param certificate_type specifies the CA certificate type
/// \return result of the operation
virtual InstallCertificateResult install_ca_certificate(const std::string& certificate,
const CaCertificateType& certificate_type) = 0;
/// \brief Deletes the certificate specified by \p certificate_hash_data . This function respects the
/// requirements of OCPP specified for the CSMS initiated message DeleteCertificate.req
/// \param certificate_hash_data specifies the certificate to be deleted
/// \return result of the operation
virtual DeleteCertificateResult delete_certificate(const CertificateHashDataType& certificate_hash_data) = 0;
/// \brief Verifies the given \p certificate_chain for the given \p certificate_type using the respective CA
/// certificates for the leaf and if valid installs the certificate. Before installing the certificate, this
/// function checks if a private key is present for the given certificate. This function respects the
/// requirements of OCPP specified for the CSMS initiated message CertificateSigned.req .
/// \param certificate_chain PEM formatted certificate or certificate chain
/// \param certificate_type type of the leaf certificate
/// \return result of the operation
virtual InstallCertificateResult update_leaf_certificate(const std::string& certificate_chain,
const CertificateSigningUseEnum& certificate_type) = 0;
/// \brief Verifies the given \p certificate_chain for the given \p certificate_type against the respective CA
/// certificates for the leaf according to the requirements specified in OCPP.
/// \param certificate_chain PEM formatted certificate or certificate chain
/// \param certificate_type type of the leaf certificate
/// \return result of the operation
virtual CertificateValidationResult verify_certificate(const std::string& certificate_chain,
const LeafCertificateType& certificate_type) = 0;
/// \brief Verifies the given \p certificate_chain against the respective CA
/// trust anchors (indicated by the given \p certificate_types) for the leaf.
/// \param certificate_chain PEM formatted certificate or certificate chain
/// \param certificate_types types of the root certificates for which the chain is verified
/// \return result of the operation
virtual CertificateValidationResult
verify_certificate(const std::string& certificate_chain,
const std::vector<LeafCertificateType>& certificate_types) = 0;
/// \brief Retrieves all certificates installed on the filesystem applying the \p certificate_types filter. This
/// function respects the requirements of OCPP specified for the CSMS initiated message
/// GetInstalledCertificateIds.req .
/// \param certificate_types
/// \return contains the certificate hash data chains of the requested \p certificate_types
virtual std::vector<CertificateHashDataChain>
get_installed_certificates(const std::vector<CertificateType>& certificate_types) = 0;
/// \brief Retrieves the OCSP request data of the V2G certificates (exluding the root). This function respects the
/// requirements of OCPP specified for the CSMS initiated message GetCertificateStatus.req . \return contains OCSP
/// request data
virtual std::vector<OCSPRequestData> get_v2g_ocsp_request_data() = 0;
/// \brief Retrieves the OCSP request data of a certificate chain.
/// \param certificate_chain PEM formatted certificate or certificate chain
/// \param certificate_type type of the leaf certificate
/// \return contains OCSP request data
virtual std::vector<OCSPRequestData> get_mo_ocsp_request_data(const std::string& certificate_chain) = 0;
/// \brief Updates the OCSP cache for the given \p certificate_hash_data with the given \p ocsp_response
/// \param certificate_hash_data identifies the certificate for which the \p ocsp_response is specified
/// \param ocsp_response the actual OCSP data
virtual void update_ocsp_cache(const CertificateHashDataType& certificate_hash_data,
const std::string& ocsp_response) = 0;
/// \brief Indicates if a CA certificate for the given \p certificate_type is installed on the filesystem
/// \param certificate_type
/// \return true if CA certificate is present, else false
virtual bool is_ca_certificate_installed(const CaCertificateType& certificate_type) = 0;
/// \brief Generates a certificate signing request for the given \p certificate_type , \p country , \p organization
/// and \p common , uses the TPM if \p use_tpm is true
/// \param certificate_type
/// \param country
/// \param organization
/// \param common
/// \param use_tpm If the TPM should be used for the CSR request
/// \return the status and an optional PEM formatted certificate signing request string
virtual GetCertificateSignRequestResult
generate_certificate_signing_request(const CertificateSigningUseEnum& certificate_type, const std::string& country,
const std::string& organization, const std::string& common, bool use_tpm) = 0;
/// \brief Searches the filesystem on the specified directories for the given \p certificate_type and retrieves the
/// most recent certificate that is already valid and the respective key. If no certificate is present or no key is
/// matching the certificate, this function returns a GetKeyPairStatus other than "Accepted". The function \ref
/// update_leaf_certificate will install two files for each leaf, one containing the single leaf and one containing
/// the leaf including any possible SUBCAs
/// \param certificate_type type of the leaf certificate
/// \param include_ocsp if OCSP data should be included
/// \return contains response result, with info related to the certificate chain and response status
virtual GetCertificateInfoResult get_leaf_certificate_info(const CertificateSigningUseEnum& certificate_type,
bool include_ocsp = false) = 0;
/// \brief Updates the certificate and key links for the given \p certificate_type
virtual bool update_certificate_links(const CertificateSigningUseEnum& certificate_type) = 0;
/// \brief Retrieves the PEM formatted CA bundle file for the given \p certificate_type
/// \param certificate_type
/// \return CA certificate file
virtual std::string get_verify_file(const CaCertificateType& certificate_type) = 0;
/// \brief Retrieves the PEM formatted CA bundle location for the given \p certificate_type
/// \param certificate_type
/// \return CA certificate file
virtual std::string get_verify_location(const CaCertificateType& certificate_type) = 0;
/// \brief Gets the expiry day count for the leaf certificate of the given \p certificate_type
/// \param certificate_type
/// \return day count until the leaf certificate expires
virtual int get_leaf_expiry_days_count(const CertificateSigningUseEnum& certificate_type) = 0;
};
namespace evse_security_conversions {
/** Conversions for Plug&Charge Data Transfer **/
ocpp::v2::GetCertificateIdUseEnum to_ocpp_v2(ocpp::CertificateType other);
ocpp::v2::InstallCertificateUseEnum to_ocpp_v2(ocpp::CaCertificateType other);
ocpp::v2::HashAlgorithmEnum to_ocpp_v2(ocpp::HashAlgorithmEnumType other);
ocpp::v2::InstallCertificateStatusEnum to_ocpp_v2(ocpp::InstallCertificateResult other);
ocpp::v2::DeleteCertificateStatusEnum to_ocpp_v2(ocpp::DeleteCertificateResult other);
ocpp::v2::CertificateHashDataType to_ocpp_v2(ocpp::CertificateHashDataType other);
ocpp::v2::CertificateHashDataChain to_ocpp_v2(ocpp::CertificateHashDataChain other);
ocpp::v2::OCSPRequestData to_ocpp_v2(ocpp::OCSPRequestData other);
std::vector<ocpp::v2::OCSPRequestData> to_ocpp_v2(const std::vector<ocpp::OCSPRequestData>& ocsp_request_data);
ocpp::CertificateType from_ocpp_v2(ocpp::v2::GetCertificateIdUseEnum other);
std::vector<ocpp::CertificateType> from_ocpp_v2(const std::vector<ocpp::v2::GetCertificateIdUseEnum>& other);
ocpp::CaCertificateType from_ocpp_v2(ocpp::v2::InstallCertificateUseEnum other);
ocpp::CertificateSigningUseEnum from_ocpp_v2(ocpp::v2::CertificateSigningUseEnum other);
ocpp::HashAlgorithmEnumType from_ocpp_v2(ocpp::v2::HashAlgorithmEnum other);
ocpp::InstallCertificateResult from_ocpp_v2(ocpp::v2::InstallCertificateStatusEnum other);
ocpp::DeleteCertificateResult from_ocpp_v2(ocpp::v2::DeleteCertificateStatusEnum other);
ocpp::CertificateHashDataType from_ocpp_v2(ocpp::v2::CertificateHashDataType other);
ocpp::CertificateHashDataChain from_ocpp_v2(ocpp::v2::CertificateHashDataChain other);
ocpp::OCSPRequestData from_ocpp_v2(ocpp::v2::OCSPRequestData other);
} // namespace evse_security_conversions
} // namespace ocpp
#endif // OCPP_COMMON_EVSE_SECURITY

View File

@@ -0,0 +1,100 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_EVSE_SECURITY_IMPL
#define OCPP_COMMON_EVSE_SECURITY_IMPL
#include <filesystem>
#include <optional>
#include <evse_security/evse_security.hpp>
#include <ocpp/common/evse_security.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
namespace ocpp {
struct SecurityConfiguration {
fs::path csms_ca_bundle;
fs::path mf_ca_bundle;
fs::path mo_ca_bundle;
fs::path v2g_ca_bundle;
fs::path csms_leaf_cert_directory;
fs::path csms_leaf_key_directory;
fs::path secc_leaf_cert_directory;
fs::path secc_leaf_key_directory;
fs::path secc_leaf_cert_link;
fs::path secc_leaf_key_link;
fs::path cpo_cert_chain_link;
std::optional<std::string> private_key_password;
};
class EvseSecurityImpl : public EvseSecurity {
private:
std::unique_ptr<evse_security::EvseSecurity> evse_security;
public:
explicit EvseSecurityImpl(const SecurityConfiguration& security_configuration);
InstallCertificateResult install_ca_certificate(const std::string& certificate,
const CaCertificateType& certificate_type) override;
DeleteCertificateResult delete_certificate(const CertificateHashDataType& certificate_hash_data) override;
InstallCertificateResult update_leaf_certificate(const std::string& certificate_chain,
const CertificateSigningUseEnum& certificate_type) override;
CertificateValidationResult verify_certificate(const std::string& certificate_chain,
const LeafCertificateType& certificate_type) override;
CertificateValidationResult verify_certificate(const std::string& certificate_chain,
const std::vector<LeafCertificateType>& certificate_types) override;
std::vector<CertificateHashDataChain>
get_installed_certificates(const std::vector<CertificateType>& certificate_types) override;
std::vector<OCSPRequestData> get_v2g_ocsp_request_data() override;
std::vector<OCSPRequestData> get_mo_ocsp_request_data(const std::string& certificate_chain) override;
void update_ocsp_cache(const CertificateHashDataType& certificate_hash_data,
const std::string& ocsp_response) override;
bool is_ca_certificate_installed(const CaCertificateType& certificate_type) override;
GetCertificateSignRequestResult
generate_certificate_signing_request(const CertificateSigningUseEnum& certificate_type, const std::string& country,
const std::string& organization, const std::string& common,
bool use_tpm) override;
GetCertificateInfoResult get_leaf_certificate_info(const CertificateSigningUseEnum& certificate_type,
bool include_ocsp = false) override;
bool update_certificate_links(const CertificateSigningUseEnum& certificate_type) override;
std::string get_verify_file(const CaCertificateType& certificate_type) override;
std::string get_verify_location(const CaCertificateType& certificate_type) override;
int get_leaf_expiry_days_count(const CertificateSigningUseEnum& certificate_type) override;
};
namespace conversions {
GetCertificateSignRequestStatus to_ocpp(evse_security::GetCertificateSignRequestStatus other);
CaCertificateType to_ocpp(evse_security::CaCertificateType other);
CertificateType to_ocpp(evse_security::CertificateType other);
HashAlgorithmEnumType to_ocpp(evse_security::HashAlgorithm other);
GetCertificateInfoStatus to_ocpp(evse_security::GetCertificateInfoStatus other);
InstallCertificateResult to_ocpp(evse_security::InstallCertificateResult other);
CertificateValidationResult to_ocpp(evse_security::CertificateValidationResult other);
DeleteCertificateResult to_ocpp(evse_security::DeleteCertificateResult other);
CertificateHashDataType to_ocpp(evse_security::CertificateHashData other);
CertificateHashDataChain to_ocpp(evse_security::CertificateHashDataChain other);
OCSPRequestData to_ocpp(evse_security::OCSPRequestData other);
CertificateOCSP to_ocpp(evse_security::CertificateOCSP other);
CertificateInfo to_ocpp(evse_security::CertificateInfo other);
evse_security::CaCertificateType from_ocpp(CaCertificateType other);
evse_security::LeafCertificateType from_ocpp(LeafCertificateType other);
evse_security::LeafCertificateType from_ocpp(CertificateSigningUseEnum other);
evse_security::CertificateType from_ocpp(CertificateType other);
evse_security::HashAlgorithm from_ocpp(HashAlgorithmEnumType other);
evse_security::InstallCertificateResult from_ocpp(InstallCertificateResult other);
evse_security::DeleteCertificateResult from_ocpp(DeleteCertificateResult other);
evse_security::CertificateHashData from_ocpp(CertificateHashDataType other);
evse_security::CertificateHashDataChain from_ocpp(CertificateHashDataChain other);
evse_security::OCSPRequestData from_ocpp(OCSPRequestData other);
evse_security::CertificateOCSP from_ocpp(CertificateOCSP other);
evse_security::CertificateInfo from_ocpp(CertificateInfo other);
}; // namespace conversions
} // namespace ocpp
#endif

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/common/message_queue.hpp>
namespace ocpp {
/// \brief Interface for dispatching OCPP messages that shall be send over the websocket. This interface defines
/// dispatching of Call, CallResult and CallError messages.
/// \tparam T Type specifies the OCPP protocol version
template <typename T> class MessageDispatcherInterface {
public:
virtual ~MessageDispatcherInterface() = default;
/// \brief Dispatches a Call message.
/// \param call the OCPP Call message.
/// \param triggered indicates if the call was triggered by a TriggerMessage. Default is false.
virtual void dispatch_call(const json& call, bool triggered = false) = 0;
/// \brief Dispatches a Call message asynchronously.
/// \param call the OCPP Call message.
/// \param triggered indicates if the call was triggered by a TriggerMessage. Default is false.
/// \return std::future<ocpp::EnhancedMessage<T>> Future object containing the enhanced message
/// result of type T.
virtual std::future<ocpp::EnhancedMessage<T>> dispatch_call_async(const json& call, bool triggered = false) = 0;
/// \brief Dispatches a CallResult message.
/// \param call_result the OCPP CallResult message.
virtual void dispatch_call_result(const json& call_result) = 0;
/// \brief Dispatches a CallError message.
/// \param call_result the OCPP CallError message.
virtual void dispatch_call_error(const json& call_error) = 0;
};
} // namespace ocpp

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,153 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_LOGGING_HPP
#define OCPP_COMMON_LOGGING_HPP
#include <filesystem>
#include <fstream>
#include <iostream>
#include <map>
#include <memory>
#include <mutex>
#include <ocpp/common/types.hpp>
#include <thread>
namespace ocpp {
/// Container for a formatted OCPP message with a message type
struct FormattedMessageWithType {
std::string message_type; ///< The message type
std::string message; ///< The message content
};
/// Configuration for log rotation
struct LogRotationConfig {
bool date_suffix; ///< If set to true the log rotation files use a date after the ".", if not use the traditional
///< .0, .1 ... style
std::uint64_t
maximum_file_size_bytes; ///< The maximum size of the log file in bytes after which the file will be rotated
std::uint64_t maximum_file_count; ///< The maximum number of log files to keep in rotation
LogRotationConfig(bool date_suffix, std::uint64_t maximum_file_size_bytes, std::uint64_t maximum_file_count) :
date_suffix(date_suffix),
maximum_file_size_bytes(maximum_file_size_bytes),
maximum_file_count(maximum_file_count) {
}
};
enum class LogRotationStatus {
NotRotated,
Rotated,
RotatedWithDeletion
};
enum class LogType {
ChargePoint,
CentralSystem,
System
};
/// \brief contains a ocpp message logging abstraction
class MessageLogging {
private:
bool log_messages;
std::string message_log_path; // FIXME: use fs::path here
std::string output_file_name;
bool log_to_console;
bool detailed_log_to_console;
bool log_to_file;
bool log_to_html;
bool log_raw;
bool log_security;
bool session_logging;
std::filesystem::path log_file;
std::ofstream log_os;
std::filesystem::path log_raw_file;
std::ofstream log_raw_os;
std::filesystem::path html_log_file;
std::ofstream html_log_os;
std::filesystem::path html_raw_log_file;
std::ofstream html_raw_log_os;
std::filesystem::path security_log_file;
std::ofstream security_log_os;
std::mutex output_file_mutex;
std::function<void(const std::string& message, MessageDirection direction)> message_callback;
std::function<void(LogRotationStatus status)> status_callback;
std::map<std::string, std::string> lookup_map;
std::recursive_mutex session_id_logging_mutex;
std::map<std::string, std::shared_ptr<MessageLogging>> session_id_logging;
bool rotate_logs;
bool date_suffix;
std::string logfile_basename;
std::uint64_t maximum_file_size_bytes;
std::uint64_t maximum_file_count;
/// \brief Initialize the OCPP message logging
void initialize();
/// \brief Output log message to the configured targets
void log_output(LogType typ, const std::string& message_type, const std::string& json_str, bool raw = false);
/// \brief Format the given \p json_str with the given \p message_type
FormattedMessageWithType format_message(const std::string& message_type, const std::string& json_str);
/// \brief Rotates the log at the given file \p file_basename and remove oldest file if there are more log files
/// than the maximum
LogRotationStatus rotate_log(const std::string& file_basename);
/// \brief Rotates the log at the given \p path if needed based on the config, closing the stream \p os before
LogRotationStatus rotate_log_if_needed(const std::filesystem::path& path, std::ofstream& os);
/// \brief Rotates the log at the given \p path if needed based on the config, calling \p before_close_of_os before
/// closing the stream \p os and calling \p after_open_of_os afterwards
LogRotationStatus rotate_log_if_needed(const std::filesystem::path& path, std::ofstream& os,
std::function<void(std::ofstream& os)> before_close_of_os,
std::function<void(std::ofstream& os)> after_open_of_os);
public:
/// \brief Creates a new MessageLogging object with the provided configuration
explicit MessageLogging(
bool log_messages, const std::string& message_log_path, const std::string& output_file_name,
bool log_to_console, bool detailed_log_to_console, bool log_to_file, bool log_to_html, bool log_raw,
bool log_security, bool session_logging,
std::function<void(const std::string& message, MessageDirection direction)> message_callback);
/// \brief Creates a new MessageLogging object with the provided configuration and enabled log rotation
explicit MessageLogging(
bool log_messages, const std::string& message_log_path, const std::string& output_file_name,
bool log_to_console, bool detailed_log_to_console, bool log_to_file, bool log_to_html, bool log_raw,
bool log_security, bool session_logging,
std::function<void(const std::string& message, MessageDirection direction)> message_callback,
LogRotationConfig log_rotation_config, std::function<void(LogRotationStatus status)> status_callback);
~MessageLogging();
/// \brief Log a message originating from the charge point
void charge_point(const std::string& message_type, const std::string& json_str);
/// \brief Log a message originating from the central system
void central_system(const std::string& message_type, const std::string& json_str);
/// \brief Log a system message
void sys(const std::string& msg);
/// \brief Log a security message
void security(const std::string& msg);
/// \brief Log a raw OCPP message
void raw(const std::string& msg, LogType log_type);
/// \brief Start session logging (without log rotation)
void start_session_logging(const std::string& session_id, const std::string& log_path);
/// \brief Stop session logging
void stop_session_logging(const std::string& session_id);
/// \returns The message log path
std::string get_message_log_path();
/// \returns If session logging is active
bool session_logging_active() const;
};
} // namespace ocpp
#endif // OCPP_COMMON_LOGGING_HPP

View File

@@ -0,0 +1,121 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#pragma once
#include <condition_variable>
#include <mutex>
#include <queue>
namespace ocpp {
/// \brief Thread safe message queue. Holds a conditional variable
/// that can be waited upon. Will take up the waiting thread on each
/// operation of push/pop/clear
template <typename T> class SafeQueue {
public:
/// \return True if the queue is empty
bool empty() const {
const std::lock_guard lock(mutex);
return queue.empty();
}
/// \brief We return a copy here, since while might be accessing the
/// reference while another thread uses pop and makes the reference stale
T front() {
const std::lock_guard lock(mutex);
return queue.front();
}
/// \return retrieves and removes the first element in the queue. Undefined behavior if the queue is empty
T pop() {
std::unique_lock<std::mutex> lock(mutex);
T front = std::move(queue.front());
queue.pop();
// Unlock here and notify
lock.unlock();
notify_waiting_thread();
return front;
}
/// \brief Queues an element and notifies any threads waiting on the internal conditional variable
void push(T&& value) {
{
const std::lock_guard<std::mutex> lock(mutex);
queue.push(std::move(value));
}
notify_waiting_thread();
}
/// \brief Queues an element and notifies any threads waiting on the internal conditional variable
void push(const T& value) {
{
const std::lock_guard<std::mutex> lock(mutex);
queue.push(value);
}
notify_waiting_thread();
}
/// \brief Clears the queue
void clear() {
{
const std::lock_guard<std::mutex> lock(mutex);
std::queue<T> empty;
empty.swap(queue);
}
notify_waiting_thread();
}
/// \brief Waits for the queue to receive an element
/// \param timeout to wait for an element, pass in a value <= 0 to wait indefinitely
void wait_on_queue_element(std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) {
wait_on_queue_element_or_predicate([]() { return false; }, timeout);
}
/// \brief Same as 'wait_on_queue' but receives an additional predicate to wait upon
template <class Predicate>
void wait_on_queue_element_or_predicate(Predicate pred,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) {
std::unique_lock<std::mutex> lock(mutex);
if (timeout.count() > 0) {
cv.wait_for(lock, timeout, [&]() { return (false == queue.empty()) or pred(); });
} else {
cv.wait(lock, [&]() { return (false == queue.empty()) or pred(); });
}
}
/// \brief Waits on the queue for a custom event
/// \param timeout to wait for an element, pass in a value <= 0 to wait indefinitely
template <class Predicate>
void wait_on_custom_event(Predicate pred, std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) {
std::unique_lock<std::mutex> lock(mutex);
if (timeout.count() > 0) {
cv.wait_for(lock, timeout, [&]() { return pred(); });
} else {
cv.wait(lock, [&]() { return pred(); });
}
}
/// \brief Notifies a single waiting thread to wake up
void notify_waiting_thread() {
cv.notify_one();
}
private:
std::queue<T> queue;
mutable std::mutex mutex;
std::condition_variable cv;
};
} // namespace ocpp

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_SCHEMAS_HPP
#define OCPP_COMMON_SCHEMAS_HPP
#include <map>
#include <regex>
#include <set>
#include <vector>
#include <everest/logging.hpp>
#include <nlohmann/json-schema.hpp>
#include <nlohmann/json_fwd.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
using json = nlohmann::json;
using json_uri = nlohmann::json_uri;
using json_validator = nlohmann::json_schema::json_validator;
namespace ocpp {
/// \brief Contains the json schema validation for the libocpp config
class Schemas {
private:
json schema;
std::shared_ptr<json_validator> validator;
fs::path schemas_path;
std::set<fs::path> available_schemas_paths;
const static std::vector<std::string> profiles;
const static std::regex date_time_regex;
/// \brief Loads the root schema "Config.json" from the schemas path
void load_root_schema();
/// \brief A custom json schema loader that loads \p schema files relative to the provided \p uri
void loader(const json_uri& uri, json& schema);
public:
/// \brief Creates a new Schemas object looking for the root schema file in relation to the provided \p main_dir
explicit Schemas(fs::path schemas_path);
/// \brief Creates a new Schemas object using the supplied JSON schema
explicit Schemas(const json& schema_in);
/// \brief Creates a new Schemas object using the supplied JSON schema
explicit Schemas(json&& schema_in);
/// \brief Provides the config schema
/// \returns the config schema as as json object
json get_schema();
/// \brief Provides the config schema validator
/// \returns a json_validator for the config
std::shared_ptr<json_validator> get_validator();
/// \brief Provides a format checker for the given \p format and \p value
static void format_checker(const std::string& format, const std::string& value);
};
} // namespace ocpp
#endif // OCPP_COMMON_SCHEMAS_HPP

View File

@@ -0,0 +1,109 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_STRING_HPP
#define OCPP_COMMON_STRING_HPP
#include <cstddef>
#include <iostream>
#include <sstream>
#include <stdexcept>
#include <string>
namespace ocpp {
class StringConversionException : public std::runtime_error {
using std::runtime_error::runtime_error;
};
enum class StringTooLarge {
Throw,
Truncate
};
/// \brief Contains a String impementation with a maximum length
template <size_t L> class String {
private:
std::string data;
static constexpr size_t length = L;
public:
/// \brief Creates a string from the given \p data
explicit String(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) {
this->set(data, to_large);
}
explicit String(const char* data, StringTooLarge to_large = StringTooLarge::Throw) {
this->set(data, to_large);
}
/// \brief Creates a string
String() = default;
/// \brief Provides a std::string representation of the string
/// \returns a std::string
std::string get() const {
return data;
}
/// \brief Sets the content of the string to the given \p data
void set(const std::string& data, StringTooLarge to_large = StringTooLarge::Throw) {
std::string_view view = data;
if (view.length() > String<L>::length) {
if (to_large == StringTooLarge::Throw) {
throw StringConversionException("String length (" + std::to_string(view.length()) +
") exceeds permitted length (" + std::to_string(String<L>::length) +
")");
}
// Truncate
view = view.substr(0, length);
}
if (this->is_valid(view)) {
this->data = view;
} else {
throw StringConversionException("String has invalid format");
}
}
/// \brief Override this to check for a specific format
bool is_valid(std::string_view data) {
(void)data; // not needed here
return true;
}
/// \brief Conversion operator to turn a String into std::string
operator std::string() {
return this->get();
}
};
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator==(const String<L>& lhs, const char* rhs) {
return lhs.get() == rhs;
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator==(const String<L>& lhs, const String<L>& rhs) {
return lhs.get() == rhs.get();
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator!=(const String<L>& lhs, const char* rhs) {
return !(lhs.get() == rhs);
}
/// \brief Case insensitive compare for a case insensitive (Ci)String
template <size_t L> bool operator!=(const String<L>& lhs, const String<L>& rhs) {
return !(lhs.get() == rhs.get());
}
/// \brief Writes the given string \p str to the given output stream \p os
/// \returns an output stream with the case insensitive string written to
template <size_t L> std::ostream& operator<<(std::ostream& os, const String<L>& str) {
os << str.get();
return os;
}
} // namespace ocpp
#endif

View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_SUPPORT_OLDER_CPP_VERSIONS_HPP_
#define OCPP_COMMON_SUPPORT_OLDER_CPP_VERSIONS_HPP_
#ifndef LIBOCPP_USE_BOOST_FILESYSTEM
#include <filesystem>
#else
#include <boost/filesystem.hpp>
#endif
#ifndef LIBOCPP_USE_BOOST_FILESYSTEM
namespace fs = std::filesystem;
namespace fsstd = std;
#else
namespace fs = boost::filesystem;
namespace fsstd = boost::filesystem;
#endif
#endif /* OCPP_COMMON_SUPPORT_OLDER_CPP_VERSIONS_HPP_ */

View File

@@ -0,0 +1,866 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_TYPES_HPP
#define OCPP_COMMON_TYPES_HPP
#include <chrono>
#include <cstddef>
#include <iostream>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <nlohmann/json_fwd.hpp>
#include <date/date.h>
#include <date/tz.h>
#include <ocpp/common/cistring.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v2/ocpp_enums.hpp>
using json = nlohmann::json;
namespace ocpp {
/// \brief Parent structure for all OCPP messages supported by this implementation
struct Message {
/// \brief Provides the type of the message
/// \returns the message type as a string
virtual std::string get_type() const = 0;
virtual ~Message() = default;
};
/// \brief Exception used when DateTime class is initialized by invalid timepoint string.
class TimePointParseException : public std::exception {
public:
explicit TimePointParseException(const std::string& timepoint_str) :
msg{"Timepoint string parsing failed. Could not convert: \"" + timepoint_str + "\" into DateTime."} {
}
const char* what() const noexcept override {
return msg.c_str();
}
private:
std::string msg;
};
/// \brief Contains a DateTime implementation that can parse and create RFC 3339 compatible strings
class DateTimeImpl {
private:
std::chrono::time_point<date::utc_clock> timepoint;
public:
/// \brief Creates a new DateTimeImpl object with the current utc time
DateTimeImpl();
~DateTimeImpl() = default;
/// \brief Creates a new DateTimeImpl object from the given \p timepoint
explicit DateTimeImpl(std::chrono::time_point<date::utc_clock> timepoint);
/// \brief Creates a new DateTimeImpl object from the given \p timepoint_str
explicit DateTimeImpl(const std::string& timepoint_str);
/// \brief Converts this DateTimeImpl to a RFC 3339 compatible string
/// \returns a RFC 3339 compatible string representation of the stored DateTime
std::string to_rfc3339() const;
/// \brief Sets the timepoint of this DateTimeImpl to the given \p timepoint_str
void from_rfc3339(const std::string& timepoint_str);
/// \brief Converts this DateTimeImpl to a std::chrono::time_point
/// \returns a std::chrono::time_point
std::chrono::time_point<date::utc_clock> to_time_point() const;
/// \brief Assignment operator= to assign another DateTimeImpl \p dt to this DateTimeImpl
DateTimeImpl& operator=(const DateTimeImpl& dt);
/// \brief Conversion operatpr std::string returns a RFC 3339 compatible string representation of the stored
/// DateTime
operator std::string() const {
return this->to_rfc3339();
}
/// \brief Writes the given DateTimeImpl \p dt to the given output stream \p os as a RFC 3339 compatible string
/// \returns an output stream with the DateTimeImpl as a RFC 3339 compatible string written to
friend std::ostream& operator<<(std::ostream& os, const DateTimeImpl& dt);
/// \brief Comparison operator> between two DateTimeImpl \p lhs and \p rhs
friend bool operator>(const DateTimeImpl& lhs, const DateTimeImpl& rhs);
/// \brief Comparison operator>= between two DateTimeImpl \p lhs and \p rhs
friend bool operator>=(const DateTimeImpl& lhs, const DateTimeImpl& rhs);
/// \brief Comparison operator< between two DateTimeImpl \p lhs and \p rhs
friend bool operator<(const DateTimeImpl& lhs, const DateTimeImpl& rhs);
/// \brief Comparison operator<= between two DateTimeImpl \p lhs and \p rhs
friend bool operator<=(const DateTimeImpl& lhs, const DateTimeImpl& rhs);
/// \brief Comparison operator== between two DateTimeImpl \p lhs and \p rhs
friend bool operator==(const DateTimeImpl& lhs, const DateTimeImpl& rhs);
};
/// \brief Contains a DateTime implementation that can parse and create RFC 3339 compatible strings
class DateTime : public DateTimeImpl {
public:
/// \brief Creates a new DateTime object with the current system time
DateTime();
~DateTime() = default;
/// \brief Creates a new DateTime object from the given \p timepoint
explicit DateTime(std::chrono::time_point<date::utc_clock> timepoint);
/// \brief Creates a new DateTime object from the given \p timepoint_str
explicit DateTime(const std::string& timepoint_str);
};
/// \brief Base exception for when a conversion from string to enum or vice versa fails
class EnumConversionException : public std::out_of_range {
public:
using std::out_of_range::out_of_range;
};
/// \brief Exception used when conversion from enum to string fails
class EnumToStringException : public EnumConversionException {
public:
/// \brief Creates a new StringToEnumException
/// \param enumValue value of enum that failed to convert
/// \param type name of the enum trying to convert from
template <typename T>
explicit EnumToStringException(T enumValue, std::string_view type) :
EnumConversionException{std::string{"No known conversion from value '"} +
std::to_string(static_cast<int>(enumValue)) + "' to " + type.data()} {
}
};
/// \brief Exception used when conversion from string to enum fails
class StringToEnumException : public EnumConversionException {
public:
/// \brief Creates a new StringToEnumException
/// \param str input string that failed to convert
/// \param type name of the enum trying to convert to
StringToEnumException(std::string_view str, std::string_view type) :
EnumConversionException{std::string{"Provided string '"} + str.data() + "' could not be converted to " +
type.data()} {
}
};
/// \brief Contains the different connection states of the charge point
enum class SessionStartedReason {
EVConnected,
Authorized
};
namespace conversions {
/// \brief Converts the given SessionStartedReason \p e to std::string
/// \returns a string representation of the SessionStartedReason
std::string session_started_reason_to_string(SessionStartedReason e);
/// \brief Converts the given std::string \p s to SessionStartedReason
/// \returns a SessionStartedReason from a string representation
SessionStartedReason string_to_session_started_reason(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given \p session_started_reason
/// to the given output stream \p os \returns an output stream with the SessionStartedReason written to
std::ostream& operator<<(std::ostream& os, const SessionStartedReason& session_started_reason);
struct Current {
std::optional<float> DC; ///< DC current
std::optional<float> L1; ///< AC L1 value only
std::optional<float> L2; ///< AC L2 value only
std::optional<float> L3; ///< AC L3 value only
std::optional<float> N; ///< AC Neutral value only
/// \brief Conversion from a given Current \p k to a given json object \p j
friend void to_json(json& j, const Current& k);
/// \brief Conversion from a given json object \p j to a given Current \p k
friend void from_json(const json& j, Current& k);
// \brief Writes the string representation of the given Current \p k to the given output stream \p os
/// \returns an output stream with the Current written to
friend std::ostream& operator<<(std::ostream& os, const Current& k);
};
struct Voltage {
std::optional<float> DC; ///< DC voltage
std::optional<float> L1; ///< AC L1 value only
std::optional<float> L2; ///< AC L2 value only
std::optional<float> L3; ///< AC L3 value only
/// \brief Conversion from a given Voltage \p k to a given json object \p j
friend void to_json(json& j, const Voltage& k);
/// \brief Conversion from a given json object \p j to a given Voltage \p k
friend void from_json(const json& j, Voltage& k);
// \brief Writes the string representation of the given Voltage \p k to the given output stream \p os
/// \returns an output stream with the Voltage written to
friend std::ostream& operator<<(std::ostream& os, const Voltage& k);
};
struct Frequency {
float L1; ///< AC L1 value
std::optional<float> L2; ///< AC L2 value
std::optional<float> L3; ///< AC L3 value
/// \brief Conversion from a given Frequency \p k to a given json object \p j
friend void to_json(json& j, const Frequency& k);
/// \brief Conversion from a given json object \p j to a given Frequency \p k
friend void from_json(const json& j, Frequency& k);
// \brief Writes the string representation of the given Frequency \p k to the given output stream \p os
/// \returns an output stream with the Frequency written to
friend std::ostream& operator<<(std::ostream& os, const Frequency& k);
};
struct Power {
float total; ///< DC / AC Sum value
std::optional<float> L1; ///< AC L1 value only
std::optional<float> L2; ///< AC L2 value only
std::optional<float> L3; ///< AC L3 value only
/// \brief Conversion from a given Power \p k to a given json object \p j
friend void to_json(json& j, const Power& k);
/// \brief Conversion from a given json object \p j to a given Power \p k
friend void from_json(const json& j, Power& k);
// \brief Writes the string representation of the given Power \p k to the given output stream \p os
/// \returns an output stream with the Power written to
friend std::ostream& operator<<(std::ostream& os, const Power& k);
};
struct Energy {
float total; ///< DC / AC Sum value (which is relevant for billing)
std::optional<float> L1; ///< AC L1 value only
std::optional<float> L2; ///< AC L2 value only
std::optional<float> L3; ///< AC L3 value only
/// \brief Conversion from a given Energy \p k to a given json object \p j
friend void to_json(json& j, const Energy& k);
/// \brief Conversion from a given json object \p j to a given Energy \p k
friend void from_json(const json& j, Energy& k);
// \brief Writes the string representation of the given Energy \p k to the given output stream \p os
/// \returns an output stream with the Energy written to
friend std::ostream& operator<<(std::ostream& os, const Energy& k);
};
struct ReactivePower {
float total; ///< VAR total
std::optional<float> VARphA; ///< VAR phase A
std::optional<float> VARphB; ///< VAR phase B
std::optional<float> VARphC; ///< VAR phase C
/// \brief Conversion from a given ReactivePower \p k to a given json object \p j
friend void to_json(json& j, const ReactivePower& k);
/// \brief Conversion from a given json object \p j to a given ReactivePower \p k
friend void from_json(const json& j, ReactivePower& k);
// \brief Writes the string representation of the given ReactivePower \p k to the given output stream \p os
/// \returns an output stream with the ReactivePower written to
friend std::ostream& operator<<(std::ostream& os, const ReactivePower& k);
};
struct Powermeter {
std::string timestamp; ///< Timestamp of measurement
Energy energy_Wh_import; ///< Imported energy in Wh (from grid)
std::optional<std::string> meter_id; ///< A (user defined) meter if (e.g. id printed on the case)
std::optional<bool> phase_seq_error; ///< AC only: true for 3 phase rotation error (ccw)
std::optional<Energy> energy_Wh_export; ///< Exported energy in Wh (to grid)
std::optional<Power>
power_W; ///< Instantaneous power in Watt. Negative values are exported, positive values imported Energy.
std::optional<Voltage> voltage_V; ///< Voltage in Volts
std::optional<ReactivePower> VAR; ///< Reactive power VAR
std::optional<Current> current_A; ///< Current in ampere
std::optional<Frequency> frequency_Hz; ///< Grid frequency in Hertz
/// \brief Conversion from a given Powermeter \p k to a given json object \p j
friend void to_json(json& j, const Powermeter& k);
/// \brief Conversion from a given json object \p j to a given Powermeter \p k
friend void from_json(const json& j, Powermeter& k);
// \brief Writes the string representation of the given Powermeter \p k to the given output stream \p os
/// \returns an output stream with the Powermeter written to
friend std::ostream& operator<<(std::ostream& os, const Powermeter& k);
};
struct StateOfCharge {
float value = 0; ///< State of Charge in percent
std::optional<std::string> location; ///< Location of the State of Charge measurement
/// \brief Conversion from a given StateOfCharge \p k to a given json object \p j
friend void to_json(json& j, const StateOfCharge& k);
/// \brief Conversion from a given json object \p j to a given StateOfCharge \p k
friend void from_json(const json& j, StateOfCharge& k);
// \brief Writes the string representation of the given StateOfCharge \p k to the given output stream \p os
/// \returns an output stream with the StateOfCharge written to
friend std::ostream& operator<<(std::ostream& os, const StateOfCharge& k);
};
struct Temperature {
float value = 0; ///< Temperature in degree Celsius
std::optional<std::string> location; ///< Location of the Temperature measurement
/// \brief Conversion from a given Temperature \p k to a given json object \p j
friend void to_json(json& j, const Temperature& k);
/// \brief Conversion from a given json object \p j to a given Temperature \p k
friend void from_json(const json& j, Temperature& k);
// \brief Writes the string representation of the given Temperature \p k to the given output stream \p os
/// \returns an output stream with the Temperature written to
friend std::ostream& operator<<(std::ostream& os, const Temperature& k);
};
struct RPM {
float value = 0; ///< RPM
std::optional<std::string> location; ///< Location of the RPM measurement
/// \brief Conversion from a given RPM \p k to a given json object \p j
friend void to_json(json& j, const RPM& k);
/// \brief Conversion from a given json object \p j to a given RPM \p k
friend void from_json(const json& j, RPM& k);
// \brief Writes the string representation of the given RPM \p k to the given output stream \p os
/// \returns an output stream with the RPM written to
friend std::ostream& operator<<(std::ostream& os, const RPM& k);
};
struct Measurement {
Powermeter power_meter; ///< Powermeter data
std::optional<StateOfCharge> soc_Percent; ///< State of Charge in percent
std::vector<Temperature> temperature_C; ///< Temperature in degree Celsius
std::optional<RPM> rpm; ///< RPM
/// \brief Conversion from a given Measurement \p k to a given json object \p j
friend void to_json(json& j, const Measurement& k);
/// \brief Conversion from a given json object \p j to a given Measurement \p k
friend void from_json(const json& j, Measurement& k);
// \brief Writes the string representation of the given Measurement \p k to the given output stream \p os
/// \returns an output stream with the Measurement written to
friend std::ostream& operator<<(std::ostream& os, const Measurement& k);
};
struct DisplayMessageContent {
std::string message;
std::optional<std::string> language;
std::optional<v2::MessageFormatEnum> message_format;
friend void from_json(const json& j, DisplayMessageContent& m);
friend void to_json(json& j, const DisplayMessageContent& m);
};
///
/// \brief Type of an identifier string.
///
enum class IdentifierType {
SessionId, ///< \brief Identifier is the session id.
IdToken, ///< \brief Identifier is the id token.
TransactionId ///< \brief Identifier is the transaction id.
};
struct TariffMessage {
std::optional<std::string> ocpp_transaction_id;
std::optional<std::string> identifier_id;
std::optional<IdentifierType> identifier_type;
std::vector<DisplayMessageContent> message;
};
struct DisplayMessage {
std::optional<std::int32_t> id;
std::optional<v2::MessagePriorityEnum> priority;
std::optional<v2::MessageStateEnum> state;
std::optional<DateTime> timestamp_from;
std::optional<DateTime> timestamp_to;
std::optional<std::string> identifier_id;
std::optional<IdentifierType> identifier_type;
DisplayMessageContent message;
std::optional<std::string> qr_code;
};
struct RunningCostChargingPrice {
std::optional<double> kWh_price;
std::optional<double> hour_price;
std::optional<double> flat_fee;
friend void from_json(const json& j, RunningCostChargingPrice& c);
friend void to_json(json& j, const RunningCostChargingPrice& c);
};
struct RunningCostIdlePrice {
std::optional<std::uint32_t> idle_grace_minutes;
std::optional<double> idle_hour_price;
friend void from_json(const json& j, RunningCostIdlePrice& c);
friend void to_json(json& j, const RunningCostIdlePrice& c);
};
enum class RunningCostState {
Charging,
Idle,
Finished
};
namespace conversions {
RunningCostState string_to_running_cost_state(const std::string& state);
std::string running_cost_state_to_string(const RunningCostState& state);
} // namespace conversions
struct RunningCost {
std::string transaction_id;
std::optional<DateTime> timestamp;
std::optional<std::uint32_t> meter_value;
double cost;
// Running cost state: "Charging" or "Idle". When this is the final price, state will be "Finished".
RunningCostState state;
std::optional<RunningCostChargingPrice> charging_price;
std::optional<RunningCostIdlePrice> idle_price;
std::optional<DateTime> next_period_at_time;
std::optional<RunningCostChargingPrice> next_period_charging_price;
std::optional<RunningCostIdlePrice> next_period_idle_price;
std::optional<std::vector<DisplayMessageContent>> cost_messages;
std::optional<std::string> qr_code_text;
friend void from_json(const json& j, RunningCost& c);
};
struct TriggerMeterValue {
std::optional<DateTime> at_time;
std::optional<int> at_energy_kwh;
std::optional<int> at_power_kw;
std::vector<v16::ChargePointStatus> at_chargepoint_status;
friend void from_json(const json& j, TriggerMeterValue& t);
};
enum class CaCertificateType {
V2G,
MO,
CSMS,
MF,
OEM
};
namespace conversions {
/// \brief Converts the given CaCertificateType \p e to human readable string
/// \returns a string representation of the CaCertificateType
std::string ca_certificate_type_to_string(CaCertificateType e);
/// \brief Converts the given std::string \p s to CaCertificateType
/// \returns a CaCertificateType from a string representation
CaCertificateType string_to_ca_certificate_type(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given CaCertificateType
/// \param ca_certificate_type to the given output stream
/// \param os
/// \returns an output stream with the CaCertificateType written to
std::ostream& operator<<(std::ostream& os, const CaCertificateType& ca_certificate_type);
enum class CertificateValidationResult {
Valid,
Expired,
InvalidSignature,
IssuerNotFound,
InvalidLeafSignature,
InvalidChain,
Unknown,
};
namespace conversions {
/// \brief Converts the given InstallCertificateResult \p e to human readable string
/// \returns a string representation of the InstallCertificateResult
std::string certificate_validation_result_to_string(CertificateValidationResult e);
/// \brief Converts the given std::string \p s to InstallCertificateResult
/// \returns a InstallCertificateResult from a string representation
CertificateValidationResult string_to_certificate_validation_result(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given InstallCertificateResult \p
/// install_certificate_result to the given output stream \p os \returns an output stream with the
/// InstallCertificateResult written to
std::ostream& operator<<(std::ostream& os, const CertificateValidationResult& certificate_validation_result);
enum class InstallCertificateResult {
InvalidSignature,
InvalidCertificateChain,
InvalidFormat,
InvalidCommonName,
NoRootCertificateInstalled,
Expired,
CertificateStoreMaxLengthExceeded,
WriteError,
Accepted
};
namespace conversions {
/// \brief Converts the given InstallCertificateResult \p e to human readable string
/// \returns a string representation of the InstallCertificateResult
std::string install_certificate_result_to_string(InstallCertificateResult e);
/// \brief Converts the given std::string \p s to InstallCertificateResult
/// \returns a InstallCertificateResult from a string representation
InstallCertificateResult string_to_install_certificate_result(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given InstallCertificateResult \p
/// install_certificate_result to the given output stream \p os \returns an output stream with the
/// InstallCertificateResult written to
std::ostream& operator<<(std::ostream& os, const InstallCertificateResult& install_certificate_result);
enum class DeleteCertificateResult {
Accepted,
Failed,
NotFound,
};
namespace conversions {
/// \brief Converts the given DeleteCertificateResult \p e to human readable string
/// \returns a string representation of the DeleteCertificateResult
std::string delete_certificate_result_to_string(DeleteCertificateResult e);
/// \brief Converts the given std::string \p s to DeleteCertificateResult
/// \returns a DeleteCertificateResult from a string representation
DeleteCertificateResult string_to_delete_certificate_result(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given DeleteCertificateResult \p
/// delete_certificate_result to the given output stream \p os \returns an output stream with the
/// DeleteCertificateResult written to
std::ostream& operator<<(std::ostream& os, const DeleteCertificateResult& delete_certificate_result);
// from: GetInstalledCertificateIdsResponse
enum class HashAlgorithmEnumType {
SHA256,
SHA384,
SHA512,
};
namespace conversions {
/// \brief Converts the given HashAlgorithmEnumType \p e to human readable string
/// \returns a string representation of the HashAlgorithmEnumType
std::string hash_algorithm_enum_type_to_string(HashAlgorithmEnumType e);
/// \brief Converts the given std::string \p s to HashAlgorithmEnumType
/// \returns a HashAlgorithmEnumType from a string representation
HashAlgorithmEnumType string_to_hash_algorithm_enum_type(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given HashAlgorithmEnumType \p hash_algorithm_enum_type to the given
/// output stream \p os \returns an output stream with the HashAlgorithmEnumType written to
std::ostream& operator<<(std::ostream& os, const HashAlgorithmEnumType& hash_algorithm_enum_type);
struct CertificateHashDataType {
HashAlgorithmEnumType hashAlgorithm;
CiString<128> issuerNameHash;
CiString<128> issuerKeyHash;
CiString<40> serialNumber;
};
/// \brief Conversion from a given CertificateHashDataType \p k to a given json object \p j
void to_json(json& j, const CertificateHashDataType& k);
/// \brief Conversion from a given json object \p j to a given CertificateHashDataType \p k
void from_json(const json& j, CertificateHashDataType& k);
// \brief Writes the string representation of the given CertificateHashDataType \p k to the given output stream \p os
/// \returns an output stream with the CertificateHashDataType written to
std::ostream& operator<<(std::ostream& os, const CertificateHashDataType& k);
enum class CertificateType {
V2GRootCertificate,
MORootCertificate,
CSMSRootCertificate,
V2GCertificateChain,
MFRootCertificate,
OEMRootCertificate,
};
namespace conversions {
/// \brief Converts the given CertificateType \p e to human readable string
/// \returns a string representation of the CertificateType
std::string certificate_type_to_string(CertificateType e);
/// \brief Converts the given std::string \p s to CertificateType
/// \returns a CertificateType from a string representation
CertificateType string_to_certificate_type(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given CertificateType \p certificate_type to
/// the given output stream \p os \returns an output stream with the CertificateType written to
std::ostream& operator<<(std::ostream& os, const CertificateType& certificate_type);
struct CertificateHashDataChain {
CertificateHashDataType certificateHashData;
CertificateType certificateType;
std::optional<std::vector<CertificateHashDataType>> childCertificateHashData;
};
/// \brief Conversion from a given CertificateHashDataChain \p k to a given json object \p j
void to_json(json& j, const CertificateHashDataChain& k);
/// \brief Conversion from a given json object \p j to a given CertificateHashDataChain \p k
void from_json(const json& j, CertificateHashDataChain& k);
// \brief Writes the string representation of the given CertificateHashDataChain \p k to the given output stream \p os
/// \returns an output stream with the CertificateHashDataChain written to
std::ostream& operator<<(std::ostream& os, const CertificateHashDataChain& k);
enum class OcppProtocolVersion {
v16,
v201,
v21,
Unknown,
};
namespace conversions {
/// \brief Converts the given OcppProtocolVersion \p e to human readable string
/// \returns a string representation of the OcppProtocolVersion
std::string ocpp_protocol_version_to_string(OcppProtocolVersion e);
/// \brief Converts the given std::string \p s to OcppProtocolVersion
/// \returns a OcppProtocolVersion from a string representation
OcppProtocolVersion string_to_ocpp_protocol_version(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given OcppProtocolVersion \p
/// ocpp_protocol_version to the given output stream \p os \returns an output stream with the
/// OcppProtocolVersion written to
std::ostream& operator<<(std::ostream& os, const OcppProtocolVersion& ocpp_protocol_version);
enum class CertificateSigningUseEnum {
ChargingStationCertificate,
V2GCertificate,
ManufacturerCertificate,
V2G20Certificate
};
namespace conversions {
/// \brief Converts the given CertificateSigningUseEnum \p e to human readable string
/// \returns a string representation of the CertificateSigningUseEnum
std::string certificate_signing_use_enum_to_string(CertificateSigningUseEnum e);
/// \brief Converts the given std::string \p s to CertificateSigningUseEnum
/// \returns a CertificateSigningUseEnum from a string representation
CertificateSigningUseEnum string_to_certificate_signing_use_enum(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given CertificateSigningUseEnum \p certificate_signing_use_enum to
/// the given output stream \p os \returns an output stream with the CertificateSigningUseEnum written to
std::ostream& operator<<(std::ostream& os, const CertificateSigningUseEnum& certificate_signing_use_enum);
/// \brief Struct for OCSPRequestData
struct OCSPRequestData {
HashAlgorithmEnumType hashAlgorithm;
std::string issuerNameHash;
std::string issuerKeyHash;
std::string serialNumber;
std::string responderUrl;
};
enum class GetCertificateSignRequestStatus {
Accepted,
InvalidRequestedType, ///< Requested a CSR for non CSMS/V2G leafs
KeyGenError, ///< The key could not be generated with the requested/default parameters
GenerationError, ///< Any other error when creating the CSR
};
enum class GetCertificateInfoStatus {
Accepted,
Rejected,
NotFound,
NotFoundValid,
PrivateKeyNotFound,
};
struct GetCertificateSignRequestResult {
GetCertificateSignRequestStatus status;
std::optional<std::string> csr;
};
struct CertificateOCSP {
CertificateHashDataType hash;
std::optional<fs::path> ocsp_path;
};
struct CertificateInfo {
std::optional<fs::path> certificate_path; // path to the full certificate chain
std::optional<fs::path> certificate_single_path; // path to the single leaf certificate
int certificate_count; // count of certs in the chain
fs::path key_path; // path to private key of the leaf certificate
std::optional<std::string> password; // optional password for the private key
std::vector<CertificateOCSP> ocsp; // OCSP data if requested
};
struct GetCertificateInfoResult {
GetCertificateInfoStatus status = GetCertificateInfoStatus::Rejected;
std::optional<CertificateInfo> info;
};
enum class LeafCertificateType {
CSMS, // Charging Station Management System
V2G, // Vehicle to grid
MF, // Manufacturer
MO // Mobility Operator
};
namespace conversions {
/// \brief Converts the given bool \p b to a string representation of "true" or "false"
/// \returns a string representation of the given bool
std::string bool_to_string(bool b);
/// \brief Converts the given string \p s to a bool value. "true" is converted into true, anything else to false
/// \returns a bool from the given string representation
bool string_to_bool(const std::string& s);
/// \brief Converts the given double \p d to a string representation with the given \p precision
/// \returns a string representation of the given double using the given precision
std::string double_to_string(double d, int precision);
/// \brief Converts the given double \p d to a string representation with a fixed precision of 2
/// \returns a string representation of the given double using a fixed precision of 2
std::string double_to_string(double d);
} // namespace conversions
enum class FirmwareStatusNotification {
Downloaded,
DownloadFailed,
Downloading,
DownloadScheduled,
DownloadPaused,
Idle,
InstallationFailed,
Installing,
Installed,
InstallRebooting,
InstallScheduled,
InstallVerificationFailed,
InvalidSignature,
SignatureVerified
};
namespace conversions {
/// \brief Converts GetCertificateSignRequestStatus to string
std::string generate_certificate_signing_request_status_to_string(const GetCertificateSignRequestStatus status);
} // namespace conversions
namespace conversions {
/// \brief Converts ocpp::FirmwareStatusNotification to v16::FirmwareStatus
v16::FirmwareStatus firmware_status_notification_to_firmware_status(const FirmwareStatusNotification status);
/// \brief Converts ocpp::FirmwareStatusNotification to v16::FirmwareStatusEnumType
v16::FirmwareStatusEnumType
firmware_status_notification_to_firmware_status_enum_type(const FirmwareStatusNotification status);
} // namespace conversions
namespace security {
// The security profiles defined in OCPP 2.0.1 resp. in the OCPP 1.6 security-whitepaper.
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class): used in implicit `switch`-comparisons to `int security_profile`
enum SecurityProfile {
OCPP_1_6_ONLY_UNSECURED_TRANSPORT_WITHOUT_BASIC_AUTHENTICATION = 0,
UNSECURED_TRANSPORT_WITH_BASIC_AUTHENTICATION = 1,
TLS_WITH_BASIC_AUTHENTICATION = 2,
TLS_WITH_CLIENT_SIDE_CERTIFICATES = 3,
};
} // namespace security
namespace security_events {
// This is the list of security events defined in OCPP 2.0.1 (and the 1.6 security whitepper).
// Security events that are marked critical should be pushed to the CSMS.
// This is a non-exhaustive list of security events, when a security event matches the description in the OCPP
// specification of one of the Security Events in this list, for interoperability reasons, the Security Event from this
// list shall be used, instead of adding a new (proprietary) Security Event.
inline const std::string FIRMWARE_UPDATED = "FirmwareUpdated"; // CRITICAL
inline const std::string FAILEDTOAUTHENTICATEATCSMS = "FailedToAuthenticateAtCsms";
inline const std::string CSMSFAILEDTOAUTHENTICATE = "CsmsFailedToAuthenticate";
inline const std::string CSRGENERATIONFAILED = "CSRGenerationFailed";
inline const std::string SETTINGSYSTEMTIME = "SettingSystemTime"; // CRITICAL
inline const std::string RESET_OR_REBOOT = "ResetOrReboot"; // CRITICAL
inline const std::string STARTUP_OF_THE_DEVICE = "StartupOfTheDevice"; // CRITICAL
inline const std::string SECURITYLOGWASCLEARED = "SecurityLogWasCleared"; // CRITICAL
inline const std::string RECONFIGURATIONOFSECURITYPARAMETERS = "ReconfigurationOfSecurityParameters";
inline const std::string MEMORYEXHAUSTION = "MemoryExhaustion"; // CRITICAL
inline const std::string INVALIDMESSAGES = "InvalidMessages";
inline const std::string ATTEMPTEDREPLAYATTACKS = "AttemptedReplayAttacks";
inline const std::string TAMPERDETECTIONACTIVATED = "TamperDetectionActivated"; // CRITICAL
inline const std::string INVALIDFIRMWARESIGNATURE = "InvalidFirmwareSignature";
inline const std::string INVALIDFIRMWARESIGNINGCERTIFICATE = "InvalidFirmwareSigningCertificate";
inline const std::string INVALIDCSMSCERTIFICATE = "InvalidCsmsCertificate";
inline const std::string INVALIDCENTRALSYSTEMCERTIFICATE = "InvalidCentralSystemCertificate";
inline const std::string INVALIDCHARGINGSTATIONCERTIFICATE = "InvalidChargingStationCertificate";
inline const std::string INVALIDCHARGEPOINTCERTIFICATE = "InvalidChargePointCertificate"; // for OCPP1.6
inline const std::string INVALIDTLSVERSION = "InvalidTLSVersion";
inline const std::string INVALIDTLSCIPHERSUITE = "InvalidTLSCipherSuite";
inline const std::string MAINTENANCELOGINACCEPTED = "MaintenanceLoginAccepted";
inline const std::string MAINTENANCELOGINFAILED = "MaintenanceLoginFailed";
} // namespace security_events
enum class MessageDirection {
CSMSToChargingStation,
ChargingStationToCSMS
};
enum class ConnectionFailedReason {
InvalidCSMSCertificate = 0,
FailedToAuthenticateAtCsms
};
///
/// \brief Reason why a websocket closes its connection
///
enum class WebsocketCloseReason : uint8_t {
/// Normal closure
Normal = 1,
ForceTcpDrop,
GoingAway,
AbnormalClose,
ServiceRestart
};
/// \brief This can be used to distinguish the different queue types
enum class QueueType {
Normal,
Transaction,
None,
};
namespace conversions {
/// \brief Converts GetCertificateSignRequestStatus to string
std::string queue_type_to_string(const QueueType queue_type);
} // namespace conversions
/// \brief Struct containing default limits for amps, watts and number of phases
struct CompositeScheduleDefaultLimits {
std::int32_t amps;
std::int32_t watts;
std::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

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_COMMON_UTILS_HPP
#define OCPP_COMMON_UTILS_HPP
#include <limits>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
namespace ocpp {
/// \brief Case insensitive compare for a case insensitive (Ci)String
bool iequals(const std::string& lhs, const std::string rhs);
bool is_integer(const std::string& value);
std::tuple<bool, int> is_positive_integer(const std::string& value);
bool is_decimal_number(const std::string& value);
bool is_rfc3339_datetime(const std::string& value);
bool is_boolean(const std::string& value);
bool is_equal(const float& value1, const float& value2, const double& epsilon = std::numeric_limits<double>::epsilon());
bool is_equal(const double& value1, const double& value2,
const double& epsilon = std::numeric_limits<double>::epsilon());
/// \brief True if \p v is empty, or holds a value that is not NaN and not +/-Inf.
bool is_finite_or_unset(const std::optional<float>& v);
///
/// \brief Split string on a given character.
/// \param string_to_split The string to split.
/// \param c The character to split the string on.
/// \param trim True if all strings must be trimmed as well. Defaults to 'false'.
/// \return A vector with the string 'segments'.
///
std::vector<std::string> split_string(const std::string& string_to_split, const char c, const bool trim = false);
///
/// \brief Trim string, removing leading and trailing white spaces.
/// \param string_to_trim The string to trim.
/// \return The trimmed string.
///
std::string trim_string(const std::string& string_to_trim);
///
/// \brief Clamp the value to the maximum value of the given type
/// \param len The value to clamp
/// \return The clamped value
template <typename T, typename U> T constexpr clamp_to(U len) {
return (len <= std::numeric_limits<T>::max()) ? static_cast<T>(len) : std::numeric_limits<T>::max();
}
std::size_t convert_to_positive_size_t(float value);
} // namespace ocpp
#endif

View File

@@ -0,0 +1,76 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_WEBSOCKET_HPP
#define OCPP_WEBSOCKET_HPP
#include <ocpp/common/evse_security.hpp>
#include <ocpp/common/ocpp_logging.hpp>
#include <ocpp/common/websocket/websocket_base.hpp>
namespace ocpp {
///
/// \brief contains a websocket abstraction that can connect to TLS and non-TLS websocket endpoints
///
class Websocket {
private:
// unique_ptr holds address of base - requires WebSocketBase to have a virtual destructor
std::unique_ptr<WebsocketBase> websocket;
std::function<void(OcppProtocolVersion protocol)> connected_callback;
std::function<void()> disconnected_callback;
std::function<void(const WebsocketCloseReason reason)> stopped_connecting_callback;
std::function<void(const std::string& message)> message_callback;
std::shared_ptr<MessageLogging> logging;
public:
/// \brief Creates a new Websocket object with the provided \p connection_options
explicit Websocket(const WebsocketConnectionOptions& connection_options,
std::shared_ptr<EvseSecurity> evse_security, std::shared_ptr<MessageLogging> logging);
~Websocket() = default;
/// \brief Starts the connection attempts. It will init the websocket processing thread
/// \returns true if the websocket is successfully initialized, false otherwise. Does
/// not wait for a successful connection
bool start_connecting();
void set_connection_options(const WebsocketConnectionOptions& connection_options);
/// \brief disconnect the websocket
void disconnect(const WebsocketCloseReason code);
// \brief reconnects the websocket after the delay
void reconnect(long delay);
/// \brief indicates if the websocket is connected
bool is_connected();
/// \brief register a \p callback that is called when the websocket is connected successfully
void register_connected_callback(const std::function<void(OcppProtocolVersion protocol)>& callback);
/// \brief register a \p callback that is called when the websocket connection is disconnected
void register_disconnected_callback(const std::function<void()>& callback);
/// \brief register a \p callback that is called when the websocket connection has been stopped and will not attempt
/// to reconnect
void register_stopped_connecting_callback(const std::function<void(const WebsocketCloseReason)>& callback);
/// \brief register a \p callback that is called when the websocket receives a message
void register_message_callback(const std::function<void(const std::string& message)>& callback);
/// \brief register a \p callback that is called when the websocket could not connect with a specific reason
void register_connection_failed_callback(const std::function<void(ConnectionFailedReason)>& callback);
/// \brief send a \p message over the websocket
/// \returns true if the message was sent successfully
bool send(const std::string& message);
/// \brief set the websocket ping interval \p ping_interval_s in seconds and pong timeout \p pong_interval_s in
/// seconds
void set_websocket_ping_interval(std::int32_t ping_interval_s, std::int32_t pong_interval_s);
/// \brief set the \p authorization_key of the connection_options
void set_authorization_key(const std::string& authorization_key);
};
} // namespace ocpp
#endif // OCPP_WEBSOCKET_HPP

View File

@@ -0,0 +1,148 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_WEBSOCKET_BASE_HPP
#define OCPP_WEBSOCKET_BASE_HPP
#include <functional>
#include <memory>
#include <mutex>
#include <thread>
#include <everest/timer.hpp>
#include <ocpp/common/types.hpp>
#include <ocpp/common/websocket/websocket_uri.hpp>
namespace ocpp {
struct WebsocketConnectionOptions {
std::vector<OcppProtocolVersion> ocpp_versions; // List of allowed protocols ordered by preference
Uri csms_uri; // the URI of the CSMS
int security_profile; // FIXME: change type to `SecurityProfile`
std::optional<std::string> authorization_key;
std::chrono::milliseconds message_timeout;
int retry_backoff_random_range_s;
int retry_backoff_repeat_times;
int retry_backoff_wait_minimum_s;
int max_connection_attempts;
std::string supported_ciphers_12;
std::string supported_ciphers_13;
int ping_interval_s;
std::string ping_payload;
int pong_timeout_s;
bool use_ssl_default_verify_paths;
std::optional<bool> additional_root_certificate_check;
std::optional<std::string> hostName;
bool verify_csms_common_name;
bool use_tpm_tls;
bool verify_csms_allow_wildcards;
std::optional<std::string> iface; // Optional interface where the socket is created. Only usable for libwebsocket
bool enable_tls_keylog = false; ///< If set to true enables logging of TLS secrets to the keylog_file
std::optional<std::filesystem::path> keylog_file; ///< Optional path to a keylog file
std::optional<std::string> everest_version;
};
///
/// \brief contains a websocket abstraction
///
class WebsocketBase {
protected:
std::atomic_bool m_is_connected;
WebsocketConnectionOptions connection_options;
std::function<void(OcppProtocolVersion protocol)> connected_callback;
std::function<void()> disconnected_callback;
std::function<void(const WebsocketCloseReason reason)> stopped_connecting_callback;
std::function<void(const std::string& message)> message_callback;
std::function<void(ConnectionFailedReason)> connection_failed_callback;
std::shared_ptr<boost::asio::steady_timer> reconnect_timer;
std::unique_ptr<Everest::SteadyTimer> ping_timer;
std::atomic_bool ping_cleared;
std::int32_t ping_elapsed_s;
std::int32_t pong_elapsed_s;
std::mutex reconnect_mutex;
std::mutex connection_mutex;
std::atomic_int reconnect_backoff_ms;
std::atomic_int connection_attempts;
std::atomic_bool shutting_down;
/// \brief Indicates if the required callbacks are registered
/// \returns true if the websocket is properly initialized
bool initialized();
/// \brief getter for authorization header for connection with basic authentication
std::optional<std::string> getAuthorizationHeader();
/// \brief Logs websocket connection error
static void log_on_fail(const std::error_code& ec, const boost::system::error_code& transport_ec,
const int http_status);
/// \brief Calculates and returns the reconnect interval based on int retry_backoff_random_range_s,
/// retry_backoff_repeat_times, int retry_backoff_wait_minimum_s of the WebsocketConnectionOptions
long get_reconnect_interval();
// \brief cancels the reconnect timer
void cancel_reconnect_timer();
/// \brief send a websocket ping
virtual void ping() = 0;
/// \brief Called when a websocket pong timeout is received
void on_pong_timeout(std::string msg);
public:
/// \brief Creates a new WebsocketBase object. The `connection_options` must be initialised with
/// `set_connection_options()`
explicit WebsocketBase();
virtual ~WebsocketBase();
/// \brief Starts the connection attempts. It will init the websocket processing thread
/// \returns true if the websocket is successfully initialized, false otherwise. Does
/// not wait for a successful connection
virtual bool start_connecting() = 0;
/// \brief sets this connection_options to the given \p connection_options and resets the connection_attempts
virtual void set_connection_options(const WebsocketConnectionOptions& connection_options) = 0;
void set_connection_options_base(const WebsocketConnectionOptions& connection_options);
/// \brief reconnect the websocket after the delay
virtual void reconnect(long delay) = 0;
/// \brief disconnect the websocket
void disconnect(const WebsocketCloseReason code);
/// \brief indicates if the websocket is connected
bool is_connected();
/// \brief closes the websocket
virtual void close(const WebsocketCloseReason code, const std::string& reason) = 0;
/// \brief register a \p callback that is called when the websocket is connected successfully
void register_connected_callback(const std::function<void(OcppProtocolVersion protocol)>& callback);
/// \brief register a \p callback that is called when the websocket connection is disconnected
void register_disconnected_callback(const std::function<void()>& callback);
/// \brief register a \p callback that is called when the websocket connection has been closed and will not attempt
/// to reconnect
void register_stopped_connecting_callback(const std::function<void(const WebsocketCloseReason reason)>& callback);
/// \brief register a \p callback that is called when the websocket receives a message
void register_message_callback(const std::function<void(const std::string& message)>& callback);
/// \brief register a \p callback that is called when the websocket could not connect with a specific reason
void register_connection_failed_callback(const std::function<void(ConnectionFailedReason)>& callback);
/// \brief send a \p message over the websocket
/// \returns true if the message was sent successfully
virtual bool send(const std::string& message) = 0;
/// \brief starts a timer that sends a websocket ping at the given \p ping_interval_s and
/// waits for a pong response in \p pong_timeout_s
void set_websocket_ping_interval(std::int32_t ping_interval_s, std::int32_t pong_timeout_s);
/// \brief set the \p authorization_key of the connection_options
void set_authorization_key(const std::string& authorization_key);
};
} // namespace ocpp
#endif // OCPP_WEBSOCKET_BASE_HPP

View File

@@ -0,0 +1,121 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_WEBSOCKET_TLS_TPM_HPP
#define OCPP_WEBSOCKET_TLS_TPM_HPP
#include <ocpp/common/evse_security.hpp>
#include <ocpp/common/safe_queue.hpp>
#include <ocpp/common/websocket/websocket_base.hpp>
#include <memory>
#include <optional>
#include <string>
struct ssl_ctx_st;
namespace ocpp {
struct ConnectionData;
struct WebsocketMessage;
/// \brief Experimental libwebsockets TLS connection
class WebsocketLibwebsockets final : public WebsocketBase {
public:
/// \brief Creates a new Websocket object with the providede \p connection_options
explicit WebsocketLibwebsockets(const WebsocketConnectionOptions& connection_options,
std::shared_ptr<EvseSecurity> evse_security);
~WebsocketLibwebsockets() override;
void set_connection_options(const WebsocketConnectionOptions& connection_options) override;
bool start_connecting() override;
void reconnect(long delay) override;
void close(const WebsocketCloseReason code, const std::string& reason) override;
bool send(const std::string& message) override;
void ping() override;
/// \brief Indicates if the websocket has a valid connection data and is trying to
/// connect/reconnect internally even if for the moment it might not be connected
/// \return True if the websocket is connected or trying to connect, false otherwise
bool is_trying_to_connect();
int process_callback(void* wsi_ptr, int callback_reason, void* user, void* in, size_t len);
private:
bool is_trying_to_connect_internal();
void close_internal(const WebsocketCloseReason code, const std::string& reason);
/// \brief Initializes the connection options, including the security info
/// \return True if it was successful, false otherwise
bool initialize_connection_options(std::shared_ptr<ConnectionData>& new_connection_data);
bool tls_init(struct ssl_ctx_st* ctx, const std::string& path_chain, const std::string& path_key,
std::optional<std::string>& password);
/// \brief Websocket processing thread loop
void thread_websocket_client_loop(std::shared_ptr<ConnectionData> local_data);
/// \brief Function to handle received messages. Required since from the received message
/// callback we also send messages that must block and wait on the client thread
void thread_websocket_message_recv_loop(std::shared_ptr<ConnectionData> local_data);
/// \brief Function to handle the deferred callbacks
void thread_deferred_callback_queue();
/// \brief Called when a TLS websocket connection is established, calls the connected callback
void on_conn_connected(ConnectionData* conn_data);
/// \brief Called when a TLS websocket connection is closed
void on_conn_close(ConnectionData* conn_data);
/// \brief Called when a TLS websocket connection fails to be established
void on_conn_fail(ConnectionData* conn_data);
/// \brief When the connection can send data
void on_conn_writable();
/// \brief Called when a message is received over the TLS websocket, calls the message callback
void on_conn_message(std::string&& message);
/// \brief Requests a message write, awakes the websocket loop from 'poll'
void request_write();
void poll_message(const std::shared_ptr<WebsocketMessage>& msg);
/// \brief Add a callback to the queue of callbacks to be executed. All will be executed from a single thread
void push_deferred_callback(const std::function<void()>& callback);
// \brief Safely closes the already running connection threads
void safe_close_threads();
/// \brief Clears all messages and message queues both incoming and outgoing
void clear_all_queues();
std::shared_ptr<EvseSecurity> evse_security;
// Connection related data
Everest::SteadyTimer reconnect_timer_tpm;
std::unique_ptr<std::thread> websocket_thread;
std::shared_ptr<ConnectionData> conn_data;
// Queue of outgoing messages, notify thread only when we remove messages
SafeQueue<std::shared_ptr<WebsocketMessage>> message_queue;
std::unique_ptr<std::thread> recv_message_thread;
SafeQueue<std::string> recv_message_queue;
std::string recv_buffered_message;
std::unique_ptr<std::thread> deferred_callback_thread;
SafeQueue<std::function<void()>> deferred_callback_queue;
std::atomic_bool stop_deferred_handler;
OcppProtocolVersion connected_ocpp_version;
};
} // namespace ocpp
#endif // OCPP_WEBSOCKET_HPP

View File

@@ -0,0 +1,83 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_WEBSOCKET_URI_HPP
#define OCPP_WEBSOCKET_URI_HPP
#include <cstdint>
#include <string>
#include <string_view>
#include <websocketpp_utils/uri.hpp>
namespace ocpp {
using ev_uri = ocpp::uri;
class Uri {
public:
Uri() = default;
// clang-format off
/// \brief parse_and_validate parses the \p uri and checks
/// 1. the general validity of it and
/// 2. if optional scheme fits to given \p security_profile
///
/// \param uri The whole URI with optional scheme and \p chargepoint_id as last segment (as backward-compatibility).
/// \param chargepoint_id The identifier unique to the CSMS.
/// \param security_profile The security-profile.
/// \returns Uri
/// \throws std::invalid_argument for several checks
// clang-format on
static Uri parse_and_validate(std::string uri, std::string chargepoint_id, int security_profile);
/// \brief set_secure defines if the connection is done via TLS
///
/// \param secure true: connect via TLS; false: connect as plaintext
void set_secure(bool secure) {
this->secure = secure;
}
std::string get_hostname() {
return this->host;
}
std::string get_chargepoint_id() {
return this->chargepoint_id;
}
std::string get_path() {
return this->path_without_chargepoint_id;
}
uint16_t get_port() const {
return this->port;
}
std::string string() {
auto uri = get_websocketpp_uri();
return uri.str();
}
ev_uri get_websocketpp_uri() { // FIXME: wrap needed `websocketpp:uri` functionality inside `Uri`
return ev_uri(this->secure, this->host, this->port,
this->path_without_chargepoint_id /* is normalized with ending slash */ + this->chargepoint_id);
}
private:
Uri(bool secure, const std::string& host, uint16_t port, const std::string& path_without_chargepoint_id,
const std::string& chargepoint_id) :
secure(secure),
host(host),
port(port),
path_without_chargepoint_id(path_without_chargepoint_id),
chargepoint_id(chargepoint_id) {
}
bool secure = false;
std::string host;
uint16_t port = 0;
std::string path_without_chargepoint_id;
std::string chargepoint_id;
};
} // namespace ocpp
#endif // OCPP_WEBSOCKET_URI_HPP */

View File

@@ -0,0 +1,663 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_HPP
#define OCPP_V16_CHARGE_POINT_HPP
#include <ocpp/common/cistring.hpp>
#include <ocpp/common/evse_security.hpp>
#include <ocpp/common/evse_security_impl.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <ocpp/v16/charge_point_configuration_interface.hpp>
#include <ocpp/v16/charge_point_state_machine.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/smart_charging.hpp>
#include <ocpp/v16/types.hpp>
#include <ocpp/v16/messages/BootNotification.hpp>
#include <ocpp/v16/messages/DataTransfer.hpp>
#include <ocpp/v16/messages/GetConfiguration.hpp>
#include <ocpp/v16/messages/GetDiagnostics.hpp>
#include <ocpp/v16/messages/GetLog.hpp>
#include <ocpp/v16/messages/SignedUpdateFirmware.hpp>
#include <ocpp/v16/messages/UpdateFirmware.hpp>
// for OCPP1.6 PnC
#include "ocpp/v16/messages/ChangeAvailability.hpp"
#include <ocpp/v2/messages/Authorize.hpp>
#include <ocpp/v2/messages/CertificateSigned.hpp>
#include <ocpp/v2/messages/DeleteCertificate.hpp>
#include <ocpp/v2/messages/Get15118EVCertificate.hpp>
#include <ocpp/v2/messages/GetCertificateStatus.hpp>
#include <ocpp/v2/messages/GetInstalledCertificateIds.hpp>
#include <ocpp/v2/messages/InstallCertificate.hpp>
#include <ocpp/v2/messages/SignCertificate.hpp>
#include <ocpp/v2/messages/TriggerMessage.hpp>
#include <optional>
namespace ocpp {
namespace v16 {
class ChargePointImpl;
/// \brief Contains a ChargePoint implementation compatible with OCPP-J 1.6
class ChargePoint {
private:
std::unique_ptr<ChargePointImpl> charge_point;
/// \addtogroup chargepoint_constructors Chargepoint constructors
/// Constructors for chargepoint, 1.6 and 2.0.1
/// @{
/// @name Constructors for 1.6
/// @{
public:
/// \brief The main entrypoint for libOCPP for OCPP 1.6
/// \param cfg a reference to the configuration provider
/// \param share_path This path contains the following files and directories and is installed by the libocpp install
/// target
/// \param database_path this points to the location of the sqlite database that libocpp uses to keep track of
/// connector availability, the authorization cache and auth list, charging profiles and transaction data
/// \param sql_init_path this points to the init.sql file which contains the database schema used by libocpp for its
/// sqlite database
/// \param message_log_path this points to the directory in which libocpp can put OCPP communication logfiles for
/// debugging purposes. This behavior can be controlled by the "LogMessages" (set to true by default) and
/// "LogMessagesFormat" (set to ["log", "html", "session_logging"] by default, "console" and "console_detailed" are
/// also available) configuration keys in the "Internal" section of the config file. Please note that this is
/// intended for debugging purposes only as it logs all communication, including authentication messages.
/// \param evse_security Pointer to evse_security that manages security related operations; if nullptr
/// security_configuration must be set
/// \param security_configuration specifies the file paths that are required to set up the internal evse_security
/// implementation
/// \param message_callback A callback that will get all OCPP messages sent or received to/from the CSMS
explicit ChargePoint(
ChargePointConfigurationInterface& cfg, const fs::path& share_path, const fs::path& database_path,
const fs::path& sql_init_path, const fs::path& message_log_path,
const std::shared_ptr<EvseSecurity> evse_security,
const std::optional<SecurityConfiguration> security_configuration = std::nullopt,
const std::function<void(const std::string& message, MessageDirection direction)>& message_callback = nullptr);
virtual ~ChargePoint();
/// @} // End constructors 1.6 group
/// @} // End chargepoint constructors topic
/// \brief Allow to update the ChargePoint core information which will be sent in BootNotification.req
/// While `vendor` and `model` strings are both required, all other values are optional.
/// Passing `std::nullopt` keeps the current existing value, i.e. does not touch the current
/// value at all, other strings replace the corresponding current value.
void update_chargepoint_information(const std::string& vendor, const std::string& model,
const std::optional<std::string>& serialnumber,
const std::optional<std::string>& chargebox_serialnumber,
const std::optional<std::string>& firmware_version);
/// \brief Allow to update the ChargePoint's modem information which will be sent in BootNotification.req
/// Passing `std::nullopt` keeps the current existing value, i.e. does not touch the current value at all.
/// Passing other strings replace the corresponding current value.
void update_modem_information(const std::optional<std::string>& iccid, const std::optional<std::string>& imsi);
/// \brief Allow to update the ChargePoint's meter information which will be sent in BootNotification.req
/// Passing `std::nullopt` keeps the current existing value, i.e. does not touch the current value at all,
/// other strings replace the corresponding current value.
void update_meter_information(const std::optional<std::string>& meter_serialnumber,
const std::optional<std::string>& meter_type);
/// \brief Initializes the ChargePoint and all of it's connectors, the state machine and message queue. This method
/// should be called if a more granular start of the process is necessary. Notably if it is necessary for the state
/// machine and the connectors (and their statuses) need to be updated prior to initiating connection with the CSMS.
/// \param connector_status_map initial state of connectors including connector 0 with reduced set of states
/// (Available, Unavailable, Faulted)
/// \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 init(const std::map<int, ChargePointStatus>& connector_status_map = {},
const std::set<std::string>& resuming_session_ids = {});
/// \brief Starts the ChargePoint, initializes and connects to the Websocket endpoint and initializes a
/// BootNotification.req
/// \param connector_status_map initial state of connectors including connector 0 with reduced set of states
/// (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
/// \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,
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
/// \param connector_status_map initial state of connectors including connector 0 with reduced set of states
/// (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
bool restart(const std::map<int, ChargePointStatus>& connector_status_map = {},
BootReasonEnum bootreason = BootReasonEnum::ApplicationReset);
// \brief Resets the internal state machine for the connectors using the given \p connector_status_map
/// \param connector_status_map state of connectors including connector 0 with reduced set of states (Available,
/// Unavailable, Faulted)
void reset_state_machine(const std::map<int, ChargePointStatus>& connector_status_map);
/// \brief Stops the ChargePoint, stops timers, transactions and the message queue and disconnects from the
/// websocket
bool stop();
/// \brief Initializes the websocket and connects to CSMS if it is not yet connected
void connect_websocket();
/// \brief Disconnects the the websocket connection to the CSMS if it is connected
void disconnect_websocket();
/// \brief Calls the set_connection_timeout_callback that can be registered. This function is used to notify an
/// Authorization mechanism about a changed ConnectionTimeout configuration key.
void call_set_connection_timeout();
// public API for Core profile
/// \brief Authorizes the provided \p id_token against the central system, LocalAuthorizationList or
/// AuthorizationCache depending on the values of the ConfigurationKeys LocalPreAuthorize, LocalAuthorizeOffline,
/// LocalAuthListEnabled and AuthorizationCacheEnabled
/// \returns the EnhancedIdTagInfo that contains the result of the authorization and an optional tarriff message
EnhancedIdTagInfo authorize_id_token(CiString<20> id_token);
// for plug&charge 1.6 whitepaper
/// \brief Uses data_transfer mechanism to authorize given \p emaid , \p certificate and
/// \p iso15118_certificate_hash_data locally or by requesting authorzation at CSMS. This function can be called
/// when the authorization mechanism Plug&Charge is specified as part of the ISO15118 PaymentDetailsRequest
/// \param emaid
/// \param certificate contract certificate that the EVCC provides
/// \param iso15118_certificate_hash_data
/// \return
ocpp::v2::AuthorizeResponse data_transfer_pnc_authorize(
const std::string& emaid, const std::optional<std::string>& certificate,
const std::optional<std::vector<ocpp::v2::OCSPRequestData>>& iso15118_certificate_hash_data);
/// \brief Uses data transfer mechanism to get 15118 ev certificate from CSMS. This function can be called when the
/// EVCC requests the update or installation of a contract certificate as part of the ISO15118
/// CertificateInstallRequest or CertificateUpdateRequest
/// \param connector_id
/// \param exi_request provided by the EVCC
/// \param iso15118_schema_version provided by the EVCC
/// \param certificate_action Install or Update
void data_transfer_pnc_get_15118_ev_certificate(const std::int32_t connector_id, const std::string& exi_request,
const std::string& iso15118_schema_version,
const ocpp::v2::CertificateActionEnum& certificate_action);
/// \brief Allows the exchange of arbitrary \p data identified by a \p vendorId and \p messageId with a central
/// system \returns the DataTransferResponse
/// \param vendorId
/// \param messageId
/// \param data
/// \return the DataTransferResponse from the CSMS. In case no response is received from the CSMS because the
/// message timed out or the charging station is offline, std::nullopt is returned
std::optional<DataTransferResponse> data_transfer(const CiString<255>& vendorId,
const std::optional<CiString<50>>& messageId,
const std::optional<std::string>& data);
/// \brief Calculates ChargingProfiles configured by the CSMS of all connectors from now until now + given \p
/// duration_s and the given \p unit
/// \param duration_s
/// \param unit defaults to A
/// \return ChargingSchedules of all connectors
std::map<std::int32_t, ChargingSchedule>
get_all_composite_charging_schedules(const std::int32_t duration_s,
const ChargingRateUnit unit = ChargingRateUnit::A);
/// \brief Calculates EnhancedChargingSchedule(s) configured by the CSMS of all connectors from now until now +
/// given \p duration_s and the given \p unit . EnhancedChargingSchedules contain EnhancedChargingSchedulePeriod(s)
/// that are enhanced by the stackLevel that was provided for the ChargingProfile
/// \param duration_s
/// \param unit defaults to A
/// \return ChargingSchedules of all connectors
std::map<std::int32_t, EnhancedChargingSchedule>
get_all_enhanced_composite_charging_schedules(const std::int32_t duration_s,
const ChargingRateUnit unit = ChargingRateUnit::A);
/// \addtogroup ocpp16_handlers OCPP 1.6 handlers
/// Handlers that can be called from the implementing class.
/// @{
/// @name Handlers
/// The handlers
/// @{
/// \brief Stores the given \p powermeter values for the given \p connector . This function can be called when a new
/// meter value is present.
/// \param connector
/// \param measurement structure that can contain all kinds of measurands
void on_meter_values(std::int32_t connector, const Measurement& measurement);
/// \brief Stores the given \p max_current for the given \p connector offered to the EV. This function can be called
/// when the value for the maximum current for the connector changes. It will be used to report the Measurand
/// Current_Offered if it is configured
/// \param connector
/// \param max_current in Amps
void on_max_current_offered(std::int32_t connector, std::int32_t max_current);
/// \brief Stores the given \p max_power for the given \p connector offered to the EV. This function can be called
/// when the value for the maximum power for the connector changes. It will be used to report the Measurand
/// Power_Offered if it is configured
/// \param connector
/// \param max_power in Watts
void on_max_power_offered(std::int32_t connector, std::int32_t max_power);
/// \brief Notifies chargepoint that a new session with the given \p session_id has been started at the given \p
/// connector with the given \p reason . The logs of the session will be written into \p session_logging_path if
/// present. This function must be called when first interaction with user or EV occurs. This can be a valid
/// authorization or the connection of cable and/or EV to the given \p connector
/// \param connector
/// \param session_id unique id of the session
/// \param reason for the initiation of the session
/// \param session_logging_path optional filesystem path to where the session log should be written
void on_session_started(std::int32_t connector, const std::string& session_id, const SessionStartedReason reason,
const std::optional<std::string>& session_logging_path);
/// \brief Notifies chargepoint that a session has been stopped at the given \p connector. This function must be
/// called when the EV disconnects from the given \p connector .
/// \param connector
/// \param session_id
void on_session_stopped(std::int32_t connector, const std::string& session_id);
/// \brief Notifies chargepoint that a transaction at the given \p connector with the given parameters has been
/// started. This function must be called at the point that all conditions for charging are met, for instance, EV is
/// connected to Charge Point and user has been authorized.
/// \param connector
/// \param session_id
/// \param id_token that has been used to authorize the transaction
/// \param meter_start start meter value in Wh
/// \param reservation_id
/// \param timestamp of the start of transaction
/// \param signed_meter_value e.g. in OCMF format
void on_transaction_started(const std::int32_t& connector, const std::string& session_id,
const std::string& id_token, const double meter_start,
std::optional<std::int32_t> reservation_id, const ocpp::DateTime& timestamp,
std::optional<std::string> signed_meter_value);
/// \brief Notifies chargepoint that the transaction on the given \p connector with the given \p reason has been
/// stopped. This function must be called at the point where one of the preconditions for charging irrevocably
/// becomes false, for instance when a user swipes to stop the transaction and the stop is authorized or if the EV
/// disconnects.
/// \param connector
/// \param session_id
/// \param reason
/// \param timestamp of the end of transaction
/// \param energy_wh_import stop meter value in Wh
/// \param id_tag_end
/// \param signed_meter_value e.g. in OCMF format
void on_transaction_stopped(const std::int32_t connector, const std::string& session_id, const Reason& reason,
ocpp::DateTime timestamp, float energy_wh_import,
std::optional<CiString<20>> id_tag_end, std::optional<std::string> signed_meter_value);
/// \brief This function should be called when EV indicates that it suspends charging on the given \p connector
/// \param connector
/// \param reason
void on_suspend_charging_ev(std::int32_t connector, const std::optional<CiString<50>> info = std::nullopt);
/// \brief This function should be called when EVSE indicates that it suspends charging on the given \p connector
/// \param connector
/// \param reason
void on_suspend_charging_evse(std::int32_t connector, const std::optional<CiString<50>> info = std::nullopt);
/// \brief This function should be called when charging resumes on the given \p connector
/// \param connector
void on_resume_charging(std::int32_t connector);
/// \brief This function should be called if an error with the given \p error_info is present. This function will
/// trigger a StatusNotification.req containing the given \p error_info . It will change the present state of
/// the state machine to faulted, in case the corresponding flag is set in the given \p error_info. This function
/// can be called multiple times for different errors. Errors reported using this function stay active as long as
/// they are cleared by \ref on_error_cleared().
/// \param connector
/// \param error_info Additional information related to
/// the error
void on_error(std::int32_t connector, const ErrorInfo& error_info);
/// \brief This function should be called if an error with the given \p uuid has been cleared. If this leads to the
/// fact that no other error is active anymore, this function will initiate a StatusNotification.req that reports
/// the current state and no error
/// \param connector
/// \param uuid of a previously reported error. If uuid is not
/// known, the event will be ignored
void on_error_cleared(std::int32_t connector, const std::string uuid);
/// \brief Clears all previously reported errors at the same time for the given \p connector . This will
/// clear a previously reported "Faulted" state if present
/// \param connector
void on_all_errors_cleared(std::int32_t connector);
/// \brief Chargepoint notifies about new log status \p log_status . This function should be called during a
/// Diagnostics / Log upload to indicate the current \p log_status .
/// \param request_id A \p request_id of -1 indicates a DiagnosticsStatusNotification.req, else a
/// LogStatusNotification.req.
/// \param log_status The \p log_status should be either be convertable to the
/// ocpp::v16::UploadLogStatusEnumType enum or ocpp::v16::DiagnosticsStatus enum depending on the previous request,
/// which could have been a DiagnosticsUpload.req or a GetLog.req (Security Whitepaper)
void on_log_status_notification(std::int32_t request_id, std::string log_status);
/// \brief Chargepoint notifies about new firmware update status \p firmware_update_status . This function should be
/// called during a Firmware Update to indicate the current \p firmware_update_status .
/// \param request_id A \p request_id of -1 indicates a FirmwareStatusNotification.req, else a
/// SignedFirmwareUpdateStatusNotification.req .
/// \param firmware_update_status The \p firmware_update_status
void on_firmware_update_status_notification(std::int32_t request_id,
const ocpp::FirmwareStatusNotification firmware_update_status);
/// \brief This function must be called when a reservation is started at the given \p connector .
/// \param connector
void on_reservation_start(std::int32_t connector);
/// \brief This function must be called when a reservation ends at the given \p connector
/// \param connector
void on_reservation_end(std::int32_t connector);
/// \brief Notifies chargepoint that the \p connector is enabled . This function should be called when the \p
/// connector becomes functional and operational
/// \param connector
void on_enabled(std::int32_t connector);
/// \brief Notifies chargepoint that the \p connector is disabled . This function should be called when the \p
/// connector becomes inoperative
/// \param connector
void on_disabled(std::int32_t connector);
/// \brief Notifies chargepoint that a ConnectionTimeout occured for the given \p connector . This function should
/// be called when an EV is plugged in but the authorization is present within the specified ConnectionTimeout
void on_plugin_timeout(std::int32_t connector);
/// \brief Notifies chargepoint that a SecurityEvent occurs. This will send a SecurityEventNotification.req to the
/// CSMS
/// \param event_type type of the security event
/// \param tech_info additional info of the security event
/// \param critical if set this overwrites the default criticality recommended in the OCPP 1.6 security whitepaper.
/// A critical security event is transmitted as a message to the CSMS, a non-critical one is just written to the
/// security log
/// \param timestamp when this security event occured, if absent the current datetime is assumed
void on_security_event(const CiString<50>& event_type, const std::optional<CiString<255>>& tech_info,
const std::optional<bool>& critical = std::nullopt,
const std::optional<DateTime>& timestamp = std::nullopt);
/// \brief Handles an internal ChangeAvailabilityRequest (in the same way as if it was emitted by the CSMS).
/// \param request
ChangeAvailabilityResponse on_change_availability(const ChangeAvailabilityRequest& request);
/// @} // End handlers group
/// @}
/// @addtogroup ocpp16_callbacks OCPP 1.6 callbacks
/// Callbacks will call be called when necessary and must be implemented by the calling class.
/// @{
/// @name Callbacks
/// Callbacks
/// @{
/// registers a \p callback function that can be used to receive a arbitrary data transfer for the given \p
/// vendorId and \p messageId
/// \param vendorId
/// \param messageId
/// \param callback
void register_data_transfer_callback(
const CiString<255>& vendorId, const CiString<50>& messageId,
const std::function<DataTransferResponse(const std::optional<std::string>& msg)>& callback);
/// registers a \p callback function that can be used to handle arbitrary data transfers for all vendorId an
/// messageId
/// \param callback
void register_data_transfer_callback(
const std::function<DataTransferResponse(const DataTransferRequest& request)>& callback);
/// \brief registers a \p callback function that can be used to enable the evse. The enable_evse_callback is called
/// when a ChangeAvailaibility.req is received.
/// \param callback
void register_enable_evse_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to disable the evse. The disable_evse_callback is
/// called when a ChangeAvailaibility.req is received.
/// \param callback
void register_disable_evse_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to pause charging. The pause_charging_callback is
/// called when the idTagInfo.status of a StartTransaction.conf is not Accepted
/// \param callback
void register_pause_charging_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to resume charging
/// \param callback
void register_resume_charging_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to provide an \p id_token for the given \p
/// referenced_connectors to an authorization handler. \p prevalidated signals to the authorization handler that no
/// further authorization is necessary. The provide_token_callback is called when a RemoteStartTransaction.req is
/// received.
/// \param callback
void register_provide_token_callback(
const std::function<void(const std::string& id_token, std::vector<std::int32_t> referenced_connectors,
bool prevalidated)>& callback);
/// \brief registers a \p callback function that can be used to stop a transaction. Ths stop_transaction_callback is
/// called
/// - when the idTagInfo.status of a StartTransaction.conf is not Accepted
/// - when a RemoteStopTransaction.req is received
/// - when a UnlockConnector.req is received
/// \param callback
void register_stop_transaction_callback(const std::function<bool(std::int32_t connector, Reason reason)>& callback);
/// \brief registers a \p callback function that can be used to reserve a connector for a idTag until a timeout
/// is reached. The reserve_now_callback is called when a ReserveNow.req is received.
/// \param callback
void register_reserve_now_callback(
const std::function<ReservationStatus(std::int32_t reservation_id, std::int32_t connector,
ocpp::DateTime expiryDate, CiString<20> idTag,
std::optional<CiString<20>> parent_id)>& callback);
/// \brief registers a \p callback function that can be used to cancel a reservation on a connector. Callback
/// function should return false if the reservation could not be cancelled, else true . The
/// cancel_reservation_callback is called when a CancelReservation.req is received
/// \param callback
void register_cancel_reservation_callback(const std::function<bool(std::int32_t reservation_id)>& callback);
/// \brief registers a \p callback function that can be used to unlock the connector. In case a transaction is
// active at the specified connector, the \p callback shall stop the transaction before unlocking the connector. The
// unlock_connector_callback is called:
/// - when receiving a UnlockConnector.req and
/// - when a transaction has on_transaction_stopped is called and the configuration key
/// UnlockConnectorOnEVSideDisconnect is true
/// \param callback
void register_unlock_connector_callback(const std::function<UnlockStatus(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to trigger an upload of diagnostics. This callback
/// should trigger a process of a diagnostics upload using the given parameters of the request. This process should
/// call the on_log_status_notification handler in order to update the status of the file upload. The
/// upload_diagnostics_callback is called when a GetDiagnostics.req is received
/// \param callback
void register_upload_diagnostics_callback(
const std::function<GetLogResponse(const GetDiagnosticsRequest& request)>& callback);
/// \brief registers a \p callback function that can be used to trigger a firmware update. This callback
/// should trigger a process of a firmware update using the given parameters of the request. This process should
/// call the on_firmware_update_status_notification handler in order to update the status of the update. The
/// update_firmware_callback is called when a FirmwareUpdate.req is received
/// \param callback
void register_update_firmware_callback(const std::function<void(const UpdateFirmwareRequest msg)>& callback);
/// \brief registers a \p callback function that can be used to trigger a signed firmware update. This callback
/// should trigger a process of a signed firmware update using the given parameters of the request. This process
/// should call the on_firmware_update_status_notification handler in order to update the status of the signed
/// firmware update. The signed_update_firmware_callback is called when a SignedUpdateFirmware.req is received.
/// \param callback
void register_signed_update_firmware_callback(
const std::function<UpdateFirmwareStatusEnumType(const SignedUpdateFirmwareRequest msg)>& callback);
/// \brief registers a \p callback function that is called when all connectors are set to unavailable.
/// This can be used to then trigger the installation of the firmware update
void register_all_connectors_unavailable_callback(const std::function<void()>& callback);
/// \brief registers a \p callback function that can be used to upload logfiles. This callback
/// should trigger a process of a log upload using the given parameters of the request. This process should
/// call the on_log_status_notification handler in order to update the status of the file upload. The
/// upload_logs_callback is called when a GetLog.req is received
/// \param callback
void register_upload_logs_callback(const std::function<GetLogResponse(GetLogRequest req)>& callback);
/// \brief registers a \p callback function that can be used to set the authorization or plug in connection timeout.
/// The set_connection_timeout_callback is called when the configuration key ConnectionTimeout has been changed by
/// the CSMS.
/// \param callback
void register_set_connection_timeout_callback(const std::function<void(std::int32_t connection_timeout)>& callback);
/// \brief registers a \p callback function that can be used to check if a reset is allowed . The
/// is_reset_allowed_callback is called when a Reset.req is received.
/// \param callback
void register_is_reset_allowed_callback(const std::function<bool(const ResetType& reset_type)>& callback);
/// \brief registers a \p callback function that can be used to trigger a reset of the chargepoint. The
/// reset_callback is called when a Reset.req is received and a previous execution of the is_reset_allowed_callback
/// returned true
/// \param callback
void register_reset_callback(const std::function<void(const ResetType& reset_type)>& callback);
/// \brief registers a \p callback function that can be used to set the system time.
/// \param callback
void register_set_system_time_callback(const std::function<void(const std::string& system_time)>& callback);
/// \brief registers a \p callback function that can be used receive the BootNotificationResponse
/// \param callback
void register_boot_notification_response_callback(
const std::function<void(const BootNotificationResponse& boot_notification_response)>& callback);
/// \brief registers a \p callback function that can be used to signal that the chargepoint received a
/// SetChargingProfile.req . The set_charging_profiles_callback is called when a SetChargingProfile.req is received
/// and was accepted. The registered callback could make use of the get_all_composite_charging_schedules in order to
/// retrieve the ChargingProfiles that have been set by the CSMS.
/// \param callback
void register_signal_set_charging_profiles_callback(const std::function<void()>& callback);
/// \brief registers a \p callback function that can be used when the connection state to CSMS changes. The
/// connection_state_changed_callback is called when chargepoint has connected to or disconnected from the CSMS.
/// \param callback
void register_connection_state_changed_callback(const std::function<void(bool is_connected)>& callback);
/// \brief registers a \p callback function that can be used to publish the response to a Get15118Certificate.req
/// wrapped in a DataTransfer.req . The get_15118_ev_certificate_response_callback is called after the response to a
/// DataTransfer.req(Get15118EVCertificate) has been accepted.
/// \param callback
void register_get_15118_ev_certificate_response_callback(
const std::function<void(const std::int32_t connector,
const ocpp::v2::Get15118EVCertificateResponse& certificate_response,
const ocpp::v2::CertificateActionEnum& certificate_action)>& callback);
/// \brief registers a \p callback function that is called when a StartTransaction.req message is sent by the
/// chargepoint
/// \param callback
void register_transaction_started_callback(
const std::function<void(const std::int32_t connector, const std::string& session_id)>& callback);
/// \brief registers a \p callback function that is called when a StopTransaction.req message is sent by the
/// chargepoint
/// \param callback
void register_transaction_stopped_callback(
const std::function<void(const std::int32_t connector, const std::string& session_id,
const std::int32_t transaction_id)>& callback);
/// \brief registers a \p callback function that is called when a StartTransaction.conf message is received by the
/// CSMS. This includes the transactionId.
/// \param callback
void register_transaction_updated_callback(
const std::function<void(const std::int32_t connector, const std::string& session_id,
const std::int32_t transaction_id, const IdTagInfo& id_tag_info)>& callback);
/// \brief registers a \p callback function that can be used to react on changed configuration keys. This
/// callback is called when a configuration key has been successfully changed by the CSMS or internally using the
/// set_custom_configuration_key function
/// \param key the configuration key for which the callback is registered
/// \param callback executed when this configuration key changed
void register_configuration_key_changed_callback(const CiString<50>& key,
const std::function<void(const KeyValue& key_value)>& callback);
/// \brief registers a \p callback function that can be used to react on changed configuration key and value. This
/// callback is called when a configuration key has been changed by the CSMS, where no key based callback is
/// assigned
/// \param callback executed when this configuration key and its value changed
void
register_generic_configuration_key_changed_callback(const std::function<void(const KeyValue& key_value)>& callback);
/// \brief registers a \p callback function that can be used to react to a security event callback. This callback is
/// called only if the SecurityEvent occured internally within libocpp
void register_security_event_callback(
const std::function<void(const std::string& type, const std::string& tech_info)>& callback);
/// \brief registers a \p callback function that can be used to check, if the \p connector is reserved for the given
/// \p id_token. The is_token_reserved_for_connector_callback is called when a RemoteStartTransaction.req is
/// received.
/// \param callback
/// \ingroup ocpp16_callbacks
void register_is_token_reserved_for_connector_callback(
const std::function<ReservationCheckStatus(const std::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.
/// \ingroup ocpp16_callbacks
void register_session_cost_callback(
const std::function<DataTransferResponse(const RunningCost& session_cost,
const std::uint32_t number_of_decimals)>& session_cost_callback);
/// \brief Registers a callback function for the tariff text message (California Pricing Requirements). The
/// callback is executed when the CSMS sends a DataTransfer.req(SetUserPrice). The callback should return a
/// DataTransferResponse with the response to the CSMS.
/// \param tariff_message_callback The callback
/// \ingroup ocpp16_callbacks
void register_tariff_message_callback(
const std::function<DataTransferResponse(const TariffMessage& message)>& tariff_message_callback);
/// \brief Registers a callback function for the default price. The callback is called on startup and whenever the
/// applicable default price changes (e.g. after a connectivity state change or a configuration update).
/// \param callback Called with the currently applicable default price text.
/// \ingroup ocpp16_callbacks
void register_default_price_callback(const std::function<void(const TariffMessage& message)>& callback);
/// \brief Register a callback function for display messages (used in California Pricing Requirements)
/// \param set_display_message_callback The callback.
/// \ingroup ocpp16_callbacks
void register_set_display_message_callback(
const std::function<DataTransferResponse(const std::vector<DisplayMessage>&)> set_display_message_callback);
/// @} // End ocpp 16 callbacks group / topic
/// @} // End group
/// \brief Gets the configured configuration key requested in the given \p request
/// \param request specifies the keys that should be returned. If empty or not set, all keys will be reported
/// \return a response containing the requested key(s) including the values and unkown keys if present
GetConfigurationResponse get_configuration_key(const GetConfigurationRequest& request);
/// \brief Sets a configuration key
/// \param key
/// \param value
/// \return Indicates the result of the operation
ConfigurationStatus set_configuration_key(CiString<50> key, CiString<500> value);
/// \brief Delay draining the message queue after reconnecting, so the CSMS can perform post-reconnect checks first
/// \param delay The delay period (seconds)
void set_message_queue_resume_delay(std::chrono::seconds delay);
/// \brief Sets the public key of the powermeter for the given connector
/// \param connector The connector for which the public key is set
/// \param public_key_pem The public key in PEM format
/// \return true if the public key was set successfully, false otherwise
bool set_powermeter_public_key(const int32_t connector, const std::string& public_key_pem);
};
} // namespace v16
} // namespace ocpp
#endif

View File

@@ -0,0 +1,542 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_CONFIGURATION_HPP
#define OCPP_V16_CHARGE_POINT_CONFIGURATION_HPP
#include <map>
#include <mutex>
#include <optional>
#include <set>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <ocpp/v16/charge_point_configuration_base.hpp>
#include <ocpp/v16/charge_point_configuration_interface.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/types.hpp>
namespace ocpp {
namespace v16 {
/// \brief contains the configuration of the charge point
class ChargePointConfiguration : private ChargePointConfigurationBase, public ChargePointConfigurationInterface {
private:
json config;
json custom_schema;
json internal_schema;
bool core_schema_unlock_connector_on_ev_side_disconnect_ro_value;
fs::path user_config_path;
std::recursive_mutex configuration_mutex;
bool validate_measurands(const json& config);
json get_user_config();
void setInUserConfig(const std::string& profile, const std::string& key, json value);
void setChargepointInformationProperty(json& user_config, const std::string& key,
const std::optional<std::string>& value);
public:
ChargePointConfiguration(const std::string& config, const fs::path& ocpp_main_path,
const fs::path& user_config_path);
ChargePointConfiguration() = delete;
ChargePointConfiguration(const ChargePointConfiguration&) = delete;
ChargePointConfiguration(ChargePointConfiguration&&) = delete;
ChargePointConfiguration& operator=(const ChargePointConfiguration&) = delete;
ChargePointConfiguration& operator=(ChargePointConfiguration&&) = delete;
virtual ~ChargePointConfiguration() = default;
void setChargepointInformation(const std::string& chargePointVendor, const std::string& chargePointModel,
const std::optional<std::string>& chargePointSerialNumber,
const std::optional<std::string>& chargeBoxSerialNumber,
const std::optional<std::string>& firmwareVersion) override;
void setChargepointModemInformation(const std::optional<std::string>& ICCID,
const std::optional<std::string>& IMSI) override;
void setChargepointMeterInformation(const std::optional<std::string>& meterSerialNumber,
const std::optional<std::string>& meterType) override;
// Internal config options
std::string getChargePointId() override;
KeyValue getChargePointIdKeyValue() override;
std::string getCentralSystemURI() override;
void setCentralSystemURI(const std::string& ocpp_uri) override;
KeyValue getCentralSystemURIKeyValue() override;
std::string getChargeBoxSerialNumber() override;
KeyValue getChargeBoxSerialNumberKeyValue() override;
CiString<20> getChargePointModel() override;
KeyValue getChargePointModelKeyValue() override;
std::optional<CiString<25>> getChargePointSerialNumber() override;
std::optional<KeyValue> getChargePointSerialNumberKeyValue() override;
CiString<20> getChargePointVendor() override;
KeyValue getChargePointVendorKeyValue() override;
CiString<50> getFirmwareVersion() override;
KeyValue getFirmwareVersionKeyValue() override;
std::optional<CiString<20>> getICCID() override;
std::optional<KeyValue> getICCIDKeyValue() override;
std::optional<CiString<20>> getIMSI() override;
std::optional<KeyValue> getIMSIKeyValue() override;
std::optional<CiString<25>> getMeterSerialNumber() override;
std::optional<KeyValue> getMeterSerialNumberKeyValue() override;
std::optional<CiString<25>> getMeterType() override;
std::optional<KeyValue> getMeterTypeKeyValue() override;
bool getAuthorizeConnectorZeroOnConnectorOne() override;
KeyValue getAuthorizeConnectorZeroOnConnectorOneKeyValue() override;
bool getLogMessages() override;
KeyValue getLogMessagesKeyValue() override;
bool getLogMessagesRaw() override;
KeyValue getLogMessagesRawKeyValue() override;
std::vector<std::string> getLogMessagesFormat() override;
KeyValue getLogMessagesFormatKeyValue() override;
bool getLogRotation() override;
KeyValue getLogRotationKeyValue() override;
bool getLogRotationDateSuffix() override;
KeyValue getLogRotationDateSuffixKeyValue() override;
uint64_t getLogRotationMaximumFileSize() override;
KeyValue getLogRotationMaximumFileSizeKeyValue() override;
uint64_t getLogRotationMaximumFileCount() override;
KeyValue getLogRotationMaximumFileCountKeyValue() override;
std::vector<ChargingProfilePurposeType> getSupportedChargingProfilePurposeTypes() override;
KeyValue getSupportedChargingProfilePurposeTypesKeyValue() override;
std::vector<ChargingProfilePurposeType> getIgnoredProfilePurposesOffline() override;
std::optional<KeyValue> getIgnoredProfilePurposesOfflineKeyValue() override;
bool setIgnoredProfilePurposesOffline(const std::string& ignored_profile_purposes_offline) override;
std::int32_t getMaxCompositeScheduleDuration() override;
KeyValue getMaxCompositeScheduleDurationKeyValue() override;
std::optional<std::int32_t> getCompositeScheduleDefaultLimitAmps() override;
std::optional<KeyValue> getCompositeScheduleDefaultLimitAmpsKeyValue() override;
void setCompositeScheduleDefaultLimitAmps(std::int32_t limit_amps) override;
std::optional<std::int32_t> getCompositeScheduleDefaultLimitWatts() override;
std::optional<KeyValue> getCompositeScheduleDefaultLimitWattsKeyValue() override;
void setCompositeScheduleDefaultLimitWatts(std::int32_t limit_watts) override;
std::optional<std::int32_t> getCompositeScheduleDefaultNumberPhases() override;
std::optional<KeyValue> getCompositeScheduleDefaultNumberPhasesKeyValue() override;
void setCompositeScheduleDefaultNumberPhases(std::int32_t number_phases) override;
std::optional<std::int32_t> getSupplyVoltage() override;
std::optional<KeyValue> getSupplyVoltageKeyValue() override;
void setSupplyVoltage(std::int32_t supply_voltage) override;
std::string getSupportedCiphers12() override;
KeyValue getSupportedCiphers12KeyValue() override;
std::string getSupportedCiphers13() override;
KeyValue getSupportedCiphers13KeyValue() override;
bool getUseSslDefaultVerifyPaths() override;
KeyValue getUseSslDefaultVerifyPathsKeyValue() override;
bool getVerifyCsmsCommonName() override;
KeyValue getVerifyCsmsCommonNameKeyValue() override;
bool getVerifyCsmsAllowWildcards() override;
void setVerifyCsmsAllowWildcards(bool verify_csms_allow_wildcards) override;
KeyValue getVerifyCsmsAllowWildcardsKeyValue() override;
bool getUseTPM() override;
KeyValue getUseTPMKeyValue() override;
bool getUseTPMSeccLeafCertificate() override;
KeyValue getUseTPMSeccLeafCertificateKeyValue() override;
std::string getSupportedMeasurands() override;
KeyValue getSupportedMeasurandsKeyValue() override;
int getMaxMessageSize() override;
KeyValue getMaxMessageSizeKeyValue() override;
bool getEnableTLSKeylog() override;
KeyValue getEnableTLSKeylogKeyValue() override;
std::string getTLSKeylogFile() override;
KeyValue getTLSKeylogFileKeyValue() override;
bool getStopTransactionIfUnlockNotSupported() override;
void setStopTransactionIfUnlockNotSupported(bool stop_transaction_if_unlock_not_supported) override;
KeyValue getStopTransactionIfUnlockNotSupportedKeyValue() override;
std::int32_t getRetryBackoffRandomRange() override;
void setRetryBackoffRandomRange(std::int32_t retry_backoff_random_range) override;
KeyValue getRetryBackoffRandomRangeKeyValue() override;
std::int32_t getRetryBackoffRepeatTimes() override;
void setRetryBackoffRepeatTimes(std::int32_t retry_backoff_repeat_times) override;
KeyValue getRetryBackoffRepeatTimesKeyValue() override;
std::int32_t getRetryBackoffWaitMinimum() override;
void setRetryBackoffWaitMinimum(std::int32_t retry_backoff_wait_minimum) override;
KeyValue getRetryBackoffWaitMinimumKeyValue() override;
std::set<MessageType> getSupportedMessageTypesSending() override;
std::set<MessageType> getSupportedMessageTypesReceiving() override;
std::string getWebsocketPingPayload() override;
KeyValue getWebsocketPingPayloadKeyValue() override;
std::int32_t getWebsocketPongTimeout() override;
KeyValue getWebsocketPongTimeoutKeyValue() override;
std::optional<std::string> getHostName() override;
std::optional<KeyValue> getHostNameKeyValue() override;
std::optional<std::string> getIFace() override;
std::optional<KeyValue> getIFaceKeyValue() override;
std::optional<bool> getQueueAllMessages() override;
std::optional<KeyValue> getQueueAllMessagesKeyValue() override;
std::optional<std::string> getMessageTypesDiscardForQueueing() override;
std::optional<KeyValue> getMessageTypesDiscardForQueueingKeyValue() override;
std::optional<int> getMessageQueueSizeThreshold() override;
std::optional<KeyValue> getMessageQueueSizeThresholdKeyValue() override;
// Core Profile - optional
std::optional<bool> getAllowOfflineTxForUnknownId() override;
void setAllowOfflineTxForUnknownId(bool enabled) override;
std::optional<KeyValue> getAllowOfflineTxForUnknownIdKeyValue() override;
// Core Profile - optional
std::optional<bool> getAuthorizationCacheEnabled() override;
void setAuthorizationCacheEnabled(bool enabled) override;
std::optional<KeyValue> getAuthorizationCacheEnabledKeyValue() override;
// Core Profile
bool getAuthorizeRemoteTxRequests() override;
void setAuthorizeRemoteTxRequests(bool enabled) override;
KeyValue getAuthorizeRemoteTxRequestsKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getBlinkRepeat() override;
void setBlinkRepeat(std::int32_t blink_repeat) override;
std::optional<KeyValue> getBlinkRepeatKeyValue() override;
// Core Profile
std::int32_t getClockAlignedDataInterval() override;
void setClockAlignedDataInterval(std::int32_t interval) override;
KeyValue getClockAlignedDataIntervalKeyValue() override;
// Core Profile
std::int32_t getConnectionTimeOut() override;
void setConnectionTimeOut(std::int32_t timeout) override;
KeyValue getConnectionTimeOutKeyValue() override;
// Core Profile
std::string getConnectorPhaseRotation() override;
void setConnectorPhaseRotation(const std::string& connector_phase_rotation) override;
KeyValue getConnectorPhaseRotationKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getConnectorPhaseRotationMaxLength() override;
std::optional<KeyValue> getConnectorPhaseRotationMaxLengthKeyValue() override;
// Core Profile
std::int32_t getGetConfigurationMaxKeys() override;
KeyValue getGetConfigurationMaxKeysKeyValue() override;
// Core Profile
std::int32_t getHeartbeatInterval() override;
void setHeartbeatInterval(std::int32_t interval) override;
KeyValue getHeartbeatIntervalKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getLightIntensity() override;
void setLightIntensity(std::int32_t light_intensity) override;
std::optional<KeyValue> getLightIntensityKeyValue() override;
// Core Profile
bool getLocalAuthorizeOffline() override;
void setLocalAuthorizeOffline(bool local_authorize_offline) override;
KeyValue getLocalAuthorizeOfflineKeyValue() override;
// Core Profile
bool getLocalPreAuthorize() override;
void setLocalPreAuthorize(bool local_pre_authorize) override;
KeyValue getLocalPreAuthorizeKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getMaxEnergyOnInvalidId() override;
void setMaxEnergyOnInvalidId(std::int32_t max_energy) override;
std::optional<KeyValue> getMaxEnergyOnInvalidIdKeyValue() override;
// Core Profile
std::string getMeterValuesAlignedData() override;
bool setMeterValuesAlignedData(const std::string& meter_values_aligned_data) override;
KeyValue getMeterValuesAlignedDataKeyValue() override;
std::vector<MeasurandWithPhase> getMeterValuesAlignedDataVector() override;
// Core Profile - optional
std::optional<std::int32_t> getMeterValuesAlignedDataMaxLength() override;
std::optional<KeyValue> getMeterValuesAlignedDataMaxLengthKeyValue() override;
// Core Profile
std::string getMeterValuesSampledData() override;
bool setMeterValuesSampledData(const std::string& meter_values_sampled_data) override;
KeyValue getMeterValuesSampledDataKeyValue() override;
std::vector<MeasurandWithPhase> getMeterValuesSampledDataVector() override;
// Core Profile - optional
std::optional<std::int32_t> getMeterValuesSampledDataMaxLength() override;
std::optional<KeyValue> getMeterValuesSampledDataMaxLengthKeyValue() override;
// Core Profile
std::int32_t getMeterValueSampleInterval() override;
void setMeterValueSampleInterval(std::int32_t interval) override;
KeyValue getMeterValueSampleIntervalKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getMinimumStatusDuration() override;
void setMinimumStatusDuration(std::int32_t minimum_status_duration) override;
std::optional<KeyValue> getMinimumStatusDurationKeyValue() override;
// Core Profile
std::int32_t getNumberOfConnectors() override;
KeyValue getNumberOfConnectorsKeyValue() override;
// Reservation Profile
std::optional<bool> getReserveConnectorZeroSupported() override;
std::optional<KeyValue> getReserveConnectorZeroSupportedKeyValue() override;
// Core Profile
std::int32_t getResetRetries() override;
void setResetRetries(std::int32_t retries) override;
KeyValue getResetRetriesKeyValue() override;
// Core Profile - optional
std::optional<bool> getStopTransactionOnEVSideDisconnect() override;
std::optional<KeyValue> getStopTransactionOnEVSideDisconnectKeyValue() override;
// Core Profile
bool getStopTransactionOnInvalidId() override;
void setStopTransactionOnInvalidId(bool stop_transaction_on_invalid_id) override;
KeyValue getStopTransactionOnInvalidIdKeyValue() override;
// Core Profile
std::string getStopTxnAlignedData() override;
bool setStopTxnAlignedData(const std::string& stop_txn_aligned_data) override;
KeyValue getStopTxnAlignedDataKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getStopTxnAlignedDataMaxLength() override;
std::optional<KeyValue> getStopTxnAlignedDataMaxLengthKeyValue() override;
// Core Profile
std::string getStopTxnSampledData() override;
bool setStopTxnSampledData(const std::string& stop_txn_sampled_data) override;
KeyValue getStopTxnSampledDataKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getStopTxnSampledDataMaxLength() override;
std::optional<KeyValue> getStopTxnSampledDataMaxLengthKeyValue() override;
// Core Profile
std::string getSupportedFeatureProfiles() override;
KeyValue getSupportedFeatureProfilesKeyValue() override;
std::set<SupportedFeatureProfiles> getSupportedFeatureProfilesSet() override;
// Core Profile - optional
std::optional<std::int32_t> getSupportedFeatureProfilesMaxLength() override;
std::optional<KeyValue> getSupportedFeatureProfilesMaxLengthKeyValue() override;
// Core Profile
std::int32_t getTransactionMessageAttempts() override;
void setTransactionMessageAttempts(std::int32_t attempts) override;
KeyValue getTransactionMessageAttemptsKeyValue() override;
// Core Profile
std::int32_t getTransactionMessageRetryInterval() override;
void setTransactionMessageRetryInterval(std::int32_t retry_interval) override;
KeyValue getTransactionMessageRetryIntervalKeyValue() override;
// Core Profile
bool getUnlockConnectorOnEVSideDisconnect() override;
void setUnlockConnectorOnEVSideDisconnect(bool unlock_connector_on_ev_side_disconnect) override;
KeyValue getUnlockConnectorOnEVSideDisconnectKeyValue() override;
// Core Profile - optional
std::optional<std::int32_t> getWebsocketPingInterval() override;
void setWebsocketPingInterval(std::int32_t websocket_ping_interval) override;
std::optional<KeyValue> getWebsocketPingIntervalKeyValue() override;
// Core Profile end
// Firmware Management Profile
std::optional<std::string> getSupportedFileTransferProtocols() override;
std::optional<KeyValue> getSupportedFileTransferProtocolsKeyValue() override;
// SmartCharging Profile
std::int32_t getChargeProfileMaxStackLevel() override;
KeyValue getChargeProfileMaxStackLevelKeyValue() override;
// SmartCharging Profile
std::string getChargingScheduleAllowedChargingRateUnit() override;
KeyValue getChargingScheduleAllowedChargingRateUnitKeyValue() override;
std::vector<ChargingRateUnit> getChargingScheduleAllowedChargingRateUnitVector() override;
// SmartCharging Profile
std::int32_t getChargingScheduleMaxPeriods() override;
KeyValue getChargingScheduleMaxPeriodsKeyValue() override;
// SmartCharging Profile - optional
std::optional<bool> getConnectorSwitch3to1PhaseSupported() override;
std::optional<KeyValue> getConnectorSwitch3to1PhaseSupportedKeyValue() override;
// SmartCharging Profile
std::int32_t getMaxChargingProfilesInstalled() override;
KeyValue getMaxChargingProfilesInstalledKeyValue() override;
// SmartCharging Profile end
// Security profile - optional
std::optional<bool> getAdditionalRootCertificateCheck() override;
std::optional<KeyValue> getAdditionalRootCertificateCheckKeyValue() override;
// Security profile - optional
std::optional<std::string> getAuthorizationKey() override;
void setAuthorizationKey(const std::string& authorization_key) override;
std::optional<KeyValue> getAuthorizationKeyKeyValue() override;
// Security profile - optional
std::optional<std::int32_t> getCertificateSignedMaxChainSize() override;
std::optional<KeyValue> getCertificateSignedMaxChainSizeKeyValue() override;
// Security profile - optional
std::optional<std::int32_t> getCertificateStoreMaxLength() override;
std::optional<KeyValue> getCertificateStoreMaxLengthKeyValue() override;
// Security profile - optional
std::optional<std::string> getCpoName() override;
void setCpoName(const std::string& cpo_name) override;
std::optional<KeyValue> getCpoNameKeyValue() override;
// // Security profile - optional in ocpp but mandatory websocket connection
std::int32_t getSecurityProfile() override;
void setSecurityProfile(std::int32_t security_profile) override;
KeyValue getSecurityProfileKeyValue() override;
// // Security profile - optional with default
bool getDisableSecurityEventNotifications() override;
void setDisableSecurityEventNotifications(bool disable_security_event_notifications) override;
KeyValue getDisableSecurityEventNotificationsKeyValue() override;
// Local Auth List Management Profile
bool getLocalAuthListEnabled() override;
void setLocalAuthListEnabled(bool local_auth_list_enabled) override;
KeyValue getLocalAuthListEnabledKeyValue() override;
// Local Auth List Management Profile
std::int32_t getLocalAuthListMaxLength() override;
KeyValue getLocalAuthListMaxLengthKeyValue() override;
// Local Auth List Management Profile
std::int32_t getSendLocalListMaxLength() override;
KeyValue getSendLocalListMaxLengthKeyValue() override;
// PnC
bool getISO15118CertificateManagementEnabled() override;
void setISO15118CertificateManagementEnabled(bool iso15118_certificate_management_enabled) override;
KeyValue getISO15118CertificateManagementEnabledKeyValue() override;
bool getISO15118PnCEnabled() override;
void setISO15118PnCEnabled(bool iso15118_pnc_enabled) override;
KeyValue getISO15118PnCEnabledKeyValue() override;
std::optional<bool> getCentralContractValidationAllowed() override;
void setCentralContractValidationAllowed(bool central_contract_validation_allowed) override;
std::optional<KeyValue> getCentralContractValidationAllowedKeyValue() override;
std::optional<std::int32_t> getCertSigningWaitMinimum() override;
void setCertSigningWaitMinimum(std::int32_t cert_signing_wait_minimum) override;
std::optional<KeyValue> getCertSigningWaitMinimumKeyValue() override;
std::optional<std::int32_t> getCertSigningRepeatTimes() override;
void setCertSigningRepeatTimes(std::int32_t cert_signing_repeat_times) override;
std::optional<KeyValue> getCertSigningRepeatTimesKeyValue() override;
bool getContractValidationOffline() override;
void setContractValidationOffline(bool contract_validation_offline) override;
KeyValue getContractValidationOfflineKeyValue() override;
std::int32_t getOcspRequestInterval() override;
void setOcspRequestInterval(std::int32_t ocsp_request_interval) override;
KeyValue getOcspRequestIntervalKeyValue() override;
std::optional<std::string> getSeccLeafSubjectCommonName() override;
void setSeccLeafSubjectCommonName(const std::string& secc_leaf_subject_common_name) override;
std::optional<KeyValue> getSeccLeafSubjectCommonNameKeyValue() override;
std::optional<std::string> getSeccLeafSubjectCountry() override;
void setSeccLeafSubjectCountry(const std::string& secc_leaf_subject_country) override;
std::optional<KeyValue> getSeccLeafSubjectCountryKeyValue() override;
std::optional<std::string> getSeccLeafSubjectOrganization() override;
void setSeccLeafSubjectOrganization(const std::string& secc_leaf_subject_organization) override;
std::optional<KeyValue> getSeccLeafSubjectOrganizationKeyValue() override;
std::optional<std::string> getConnectorEvseIds() override;
void setConnectorEvseIds(const std::string& connector_evse_ids) override;
std::optional<KeyValue> getConnectorEvseIdsKeyValue() override;
std::optional<bool> getAllowChargingProfileWithoutStartSchedule() override;
void setAllowChargingProfileWithoutStartSchedule(bool allow) override;
std::optional<KeyValue> getAllowChargingProfileWithoutStartScheduleKeyValue() override;
std::int32_t getWaitForStopTransactionsOnResetTimeout() override;
void setWaitForStopTransactionsOnResetTimeout(std::int32_t wait_for_stop_transactions_on_reset_timeout) override;
KeyValue getWaitForStopTransactionsOnResetTimeoutKeyValue() override;
// California Pricing Requirements
bool getCustomDisplayCostAndPriceEnabled() override;
KeyValue getCustomDisplayCostAndPriceEnabledKeyValue() override;
std::optional<std::uint32_t> getPriceNumberOfDecimalsForCostValues() override;
std::optional<KeyValue> getPriceNumberOfDecimalsForCostValuesKeyValue() override;
std::optional<std::string> getDefaultPriceText(const std::string& language) override;
TariffMessage getDefaultTariffMessage(bool offline) override;
ConfigurationStatus setDefaultPriceText(const CiString<50>& key, const CiString<500>& value) override;
KeyValue getDefaultPriceTextKeyValue(const std::string& language) override;
std::optional<std::vector<KeyValue>> getAllDefaultPriceTextKeyValues() override;
std::optional<std::string> getDefaultPrice() override;
ConfigurationStatus setDefaultPrice(const std::string& value) override;
std::optional<KeyValue> getDefaultPriceKeyValue() override;
std::optional<std::string> getDisplayTimeOffset() override;
ConfigurationStatus setDisplayTimeOffset(const std::string& offset) override;
std::optional<KeyValue> getDisplayTimeOffsetKeyValue() override;
std::optional<std::string> getNextTimeOffsetTransitionDateTime() override;
ConfigurationStatus setNextTimeOffsetTransitionDateTime(const std::string& date_time) override;
std::optional<KeyValue> getNextTimeOffsetTransitionDateTimeKeyValue() override;
std::optional<std::string> getTimeOffsetNextTransition() override;
ConfigurationStatus setTimeOffsetNextTransition(const std::string& offset) override;
std::optional<KeyValue> getTimeOffsetNextTransitionKeyValue() override;
std::optional<bool> getCustomIdleFeeAfterStop() override;
void setCustomIdleFeeAfterStop(bool value) override;
std::optional<KeyValue> getCustomIdleFeeAfterStopKeyValue() override;
std::optional<bool> getCustomMultiLanguageMessagesEnabled() override;
std::optional<KeyValue> getCustomMultiLanguageMessagesEnabledKeyValue() override;
std::optional<std::string> getMultiLanguageSupportedLanguages() override;
std::optional<KeyValue> getMultiLanguageSupportedLanguagesKeyValue() override;
std::optional<std::string> getLanguage() override;
void setLanguage(const std::string& language) override;
std::optional<KeyValue> getLanguageKeyValue() override;
std::optional<std::int32_t> getWaitForSetUserPriceTimeout() override;
void setWaitForSetUserPriceTimeout(std::int32_t wait_for_set_user_price_timeout) override;
std::optional<KeyValue> getWaitForSetUserPriceTimeoutKeyValue() override;
// Signed Meter Values
std::optional<KeyValue> getPublicKeyKeyValue(std::uint32_t connector_id) override;
std::optional<std::vector<KeyValue>> getAllMeterPublicKeyKeyValues() override;
bool setMeterPublicKey(std::int32_t connector_id, const std::string& public_key_pem) override;
// custom
std::optional<KeyValue> getCustomKeyValue(const CiString<50>& key) override;
ConfigurationStatus setCustomKey(const CiString<50>& key, const CiString<500>& value, bool force) override;
std::optional<KeyValue> get(const CiString<50>& key) override;
std::vector<KeyValue> get_all_key_value() override;
std::optional<ConfigurationStatus> set(const CiString<50>& key, const CiString<500>& value) override;
};
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CHARGE_POINT_CONFIGURATION_HPP

View File

@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_CONFIGURATION_BASE_HPP
#define OCPP_V16_CHARGE_POINT_CONFIGURATION_BASE_HPP
#include <ocpp/v16/types.hpp>
#include <cstddef>
#include <filesystem>
#include <map>
#include <optional>
#include <set>
#include <string_view>
namespace ocpp::v16 {
constexpr std::size_t AUTHORIZATION_KEY_MIN_LENGTH = 8;
constexpr std::size_t OCSP_REQUEST_INTERVAL_MIN = 86400;
constexpr std::size_t SECC_LEAF_SUBJECT_COMMON_NAME_MIN_LENGTH = 7;
constexpr std::size_t SECC_LEAF_SUBJECT_COMMON_NAME_MAX_LENGTH = 64;
constexpr std::size_t SECC_LEAF_SUBJECT_COUNTRY_LENGTH = 2;
constexpr std::size_t SECC_LEAF_SUBJECT_ORGANIZATION_MAX_LENGTH = 64;
constexpr std::size_t CONNECTOR_EVSE_IDS_MAX_LENGTH = 1000;
constexpr std::int32_t MAX_WAIT_FOR_SET_USER_PRICE_TIMEOUT_MS = 30000;
/// \brief contains the configuration of the charge point
class ChargePointConfigurationBase {
public:
using MessagesSet = std::set<MessageType>;
using ProfilesSet = std::set<SupportedFeatureProfiles>;
using FeaturesMap = std::map<SupportedFeatureProfiles, MessagesSet>;
using MeasurandsMap = std::map<Measurand, std::vector<Phase>>;
using MeasurandWithPhaseList = std::vector<MeasurandWithPhase>;
protected:
static const FeaturesMap supported_message_types_from_charge_point;
static const FeaturesMap supported_message_types_from_central_system;
MessagesSet supported_message_types_receiving;
MessagesSet supported_message_types_sending;
ProfilesSet supported_feature_profiles;
MeasurandsMap supported_measurands;
std::filesystem::path ocpp_main_path;
void initialise(const ProfilesSet& initial_set, const std::optional<std::string>& supported_profiles_csl,
const std::optional<std::string>& supported_measurands_csl);
public:
ChargePointConfigurationBase(const std::string_view& ocpp_main_path) : ocpp_main_path(ocpp_main_path) {
}
ChargePointConfigurationBase(const std::filesystem::path& ocpp_main_path) : ocpp_main_path(ocpp_main_path) {
}
ChargePointConfigurationBase() = delete;
ChargePointConfigurationBase(const ChargePointConfigurationBase&) = delete;
ChargePointConfigurationBase(ChargePointConfigurationBase&&) = delete;
ChargePointConfigurationBase& operator=(const ChargePointConfigurationBase&) = delete;
ChargePointConfigurationBase& operator=(ChargePointConfigurationBase&&) = delete;
virtual ~ChargePointConfigurationBase() = default;
bool validate(const std::string_view& schema_file, const json& object) const;
bool isValidSupportedMeasurands(const std::string& csl) const;
std::optional<MeasurandWithPhaseList> csvToMeasurandWithPhaseVector(const std::string& csl) const;
static std::optional<std::uint32_t> extractConnectorIdFromMeterPublicKey(const std::string& str);
static std::string meterPublicKeyString(std::uint32_t connector_id);
static bool toBool(const std::string& value);
static bool isBool(const std::string& str);
static bool isPositiveInteger(const std::string& str);
static bool isConnectorPhaseRotationValid(std::int32_t num_connectors, const std::string& value);
static bool isTimeOffset(const std::string& offset);
static bool areValidEvseIds(const std::string& value);
static std::string hexToString(const std::string& s);
static bool isHexNotation(const std::string& s);
};
} // namespace ocpp::v16
#endif // OCPP_V16_CHARGE_POINT_CONFIGURATION_BASE_HPP

View File

@@ -0,0 +1,504 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_CONFIGURATION_DEVICEMODEL_HPP
#define OCPP_V16_CHARGE_POINT_CONFIGURATION_DEVICEMODEL_HPP
#include <ocpp/v16/charge_point_configuration_base.hpp>
#include <ocpp/v16/charge_point_configuration_interface.hpp>
#include <ocpp/v16/types.hpp>
#include <set>
#include <vector>
namespace ocpp {
namespace v2 {
class DeviceModelInterface;
}
namespace v16 {
/// \brief contains the configuration of the charge point
class ChargePointConfigurationDeviceModel : private ChargePointConfigurationBase,
public ChargePointConfigurationInterface {
public:
using SetResult = v2::SetVariableStatusEnum;
protected:
std::unique_ptr<v2::DeviceModelInterface> storage;
SetResult setInternalAllowChargingProfileWithoutStartSchedule(const std::string& value);
SetResult setInternalCentralSystemURI(const std::string& value);
SetResult setInternalCompositeScheduleDefaultLimitAmps(const std::string& value);
SetResult setInternalCompositeScheduleDefaultLimitWatts(const std::string& value);
SetResult setInternalCompositeScheduleDefaultNumberPhases(const std::string& value);
SetResult setInternalConnectorEvseIds(const std::string& value);
SetResult setInternalIgnoredProfilePurposesOffline(const std::string& value);
SetResult setInternalOcspRequestInterval(const std::string& value);
SetResult setInternalRetryBackoffRandomRange(const std::string& value);
SetResult setInternalRetryBackoffRepeatTimes(const std::string& value);
SetResult setInternalRetryBackoffWaitMinimum(const std::string& value);
SetResult setInternalSeccLeafSubjectCommonName(const std::string& value);
SetResult setInternalSeccLeafSubjectCountry(const std::string& value);
SetResult setInternalSeccLeafSubjectOrganization(const std::string& value);
SetResult setInternalStopTransactionIfUnlockNotSupported(const std::string& value);
SetResult setInternalSupplyVoltage(const std::string& value);
SetResult setInternalVerifyCsmsAllowWildcards(const std::string& value);
SetResult setInternalWaitForStopTransactionsOnResetTimeout(const std::string& value);
SetResult setInternalAllowOfflineTxForUnknownId(const std::string& value);
SetResult setInternalAuthorizationCacheEnabled(const std::string& value);
SetResult setInternalAuthorizeRemoteTxRequests(const std::string& value);
SetResult setInternalBlinkRepeat(const std::string& value);
SetResult setInternalClockAlignedDataInterval(const std::string& value);
SetResult setInternalConnectionTimeOut(const std::string& value);
SetResult setInternalConnectorPhaseRotation(const std::string& value);
SetResult setInternalHeartbeatInterval(const std::string& value);
SetResult setInternalLightIntensity(const std::string& value);
SetResult setInternalLocalAuthorizeOffline(const std::string& value);
SetResult setInternalLocalPreAuthorize(const std::string& value);
SetResult setInternalMaxEnergyOnInvalidId(const std::string& value);
SetResult setInternalMeterValuesAlignedData(const std::string& value);
SetResult setInternalMeterValuesSampledData(const std::string& value);
SetResult setInternalMeterValueSampleInterval(const std::string& value);
SetResult setInternalMinimumStatusDuration(const std::string& value);
SetResult setInternalResetRetries(const std::string& value);
SetResult setInternalStopTransactionOnInvalidId(const std::string& value);
SetResult setInternalStopTxnAlignedData(const std::string& value);
SetResult setInternalStopTxnSampledData(const std::string& value);
SetResult setInternalTransactionMessageAttempts(const std::string& value);
SetResult setInternalTransactionMessageRetryInterval(const std::string& value);
SetResult setInternalUnlockConnectorOnEVSideDisconnect(const std::string& value);
SetResult setInternalWebsocketPingInterval(const std::string& value);
SetResult setInternalAuthorizationKey(const std::string& value);
SetResult setInternalCpoName(const std::string& value);
SetResult setInternalDisableSecurityEventNotifications(const std::string& value);
SetResult setInternalSecurityProfile(const std::string& value);
SetResult setInternalISO15118CertificateManagementEnabled(const std::string& value);
SetResult setInternalLocalAuthListEnabled(const std::string& value);
SetResult setInternalContractValidationOffline(const std::string& value);
SetResult setInternalCentralContractValidationAllowed(const std::string& value);
SetResult setInternalCertSigningRepeatTimes(const std::string& value);
SetResult setInternalCertSigningWaitMinimum(const std::string& value);
SetResult setInternalISO15118PnCEnabled(const std::string& value);
SetResult setInternalCustomIdleFeeAfterStop(const std::string& value);
SetResult setInternalDefaultPrice(const std::string& value);
SetResult setInternalDefaultPriceText(const std::string& key, const std::string& value);
SetResult setInternalDisplayTimeOffset(const std::string& value);
SetResult setInternalLanguage(const std::string& value);
SetResult setInternalNextTimeOffsetTransitionDateTime(const std::string& value);
SetResult setInternalTimeOffsetNextTransition(const std::string& value);
SetResult setInternalWaitForSetUserPriceTimeout(const std::string& value);
std::optional<std::string> calculateEvseIds();
std::string calculateSupportedMeasurands();
public:
explicit ChargePointConfigurationDeviceModel(const std::string_view& ocpp_main_path,
std::unique_ptr<v2::DeviceModelInterface> device_model_interface);
virtual ~ChargePointConfigurationDeviceModel() = default;
// UserConfig and Internal
std::string getChargeBoxSerialNumber() override;
std::optional<CiString<25>> getChargePointSerialNumber() override;
CiString<50> getFirmwareVersion() override;
std::optional<CiString<20>> getICCID() override;
std::optional<CiString<20>> getIMSI() override;
std::optional<CiString<25>> getMeterSerialNumber() override;
std::optional<CiString<25>> getMeterType() override;
KeyValue getChargeBoxSerialNumberKeyValue() override;
KeyValue getFirmwareVersionKeyValue() override;
std::optional<KeyValue> getChargePointSerialNumberKeyValue() override;
std::optional<KeyValue> getICCIDKeyValue() override;
std::optional<KeyValue> getIMSIKeyValue() override;
std::optional<KeyValue> getMeterSerialNumberKeyValue() override;
std::optional<KeyValue> getMeterTypeKeyValue() override;
void setChargepointInformation(const std::string& chargePointVendor, const std::string& chargePointModel,
const std::optional<std::string>& chargePointSerialNumber,
const std::optional<std::string>& chargeBoxSerialNumber,
const std::optional<std::string>& firmwareVersion) override;
void setChargepointMeterInformation(const std::optional<std::string>& meterSerialNumber,
const std::optional<std::string>& meterType) override;
void setChargepointModemInformation(const std::optional<std::string>& ICCID,
const std::optional<std::string>& IMSI) override;
// Internal
std::string getCentralSystemURI() override;
std::string getChargePointId() override;
std::string getSupportedCiphers12() override;
std::string getSupportedCiphers13() override;
std::string getSupportedMeasurands() override;
std::string getTLSKeylogFile() override;
std::string getWebsocketPingPayload() override;
CiString<20> getChargePointModel() override;
CiString<20> getChargePointVendor() override;
bool getAuthorizeConnectorZeroOnConnectorOne() override;
bool getEnableTLSKeylog() override;
bool getLogMessages() override;
bool getLogMessagesRaw() override;
bool getLogRotation() override;
bool getLogRotationDateSuffix() override;
bool getStopTransactionIfUnlockNotSupported() override;
bool getUseSslDefaultVerifyPaths() override;
bool getUseTPM() override;
bool getUseTPMSeccLeafCertificate() override;
bool getVerifyCsmsAllowWildcards() override;
bool getVerifyCsmsCommonName() override;
int getMaxMessageSize() override;
std::int32_t getMaxCompositeScheduleDuration() override;
std::int32_t getOcspRequestInterval() override;
std::int32_t getRetryBackoffRandomRange() override;
std::int32_t getRetryBackoffRepeatTimes() override;
std::int32_t getRetryBackoffWaitMinimum() override;
std::int32_t getWaitForStopTransactionsOnResetTimeout() override;
std::int32_t getWebsocketPongTimeout() override;
std::uint64_t getLogRotationMaximumFileCount() override;
std::uint64_t getLogRotationMaximumFileSize() override;
std::vector<std::string> getLogMessagesFormat() override;
std::vector<ChargingProfilePurposeType> getIgnoredProfilePurposesOffline() override;
std::vector<ChargingProfilePurposeType> getSupportedChargingProfilePurposeTypes() override;
std::optional<std::string> getConnectorEvseIds() override;
std::optional<std::string> getHostName() override;
std::optional<std::string> getIFace() override;
std::optional<std::string> getMessageTypesDiscardForQueueing() override;
std::optional<std::string> getSeccLeafSubjectCommonName() override;
std::optional<std::string> getSeccLeafSubjectCountry() override;
std::optional<std::string> getSeccLeafSubjectOrganization() override;
std::optional<bool> getAllowChargingProfileWithoutStartSchedule() override;
std::optional<bool> getQueueAllMessages() override;
std::optional<int> getMessageQueueSizeThreshold() override;
std::optional<std::int32_t> getCompositeScheduleDefaultLimitAmps() override;
std::optional<std::int32_t> getCompositeScheduleDefaultLimitWatts() override;
std::optional<std::int32_t> getCompositeScheduleDefaultNumberPhases() override;
std::optional<std::int32_t> getSupplyVoltage() override;
std::optional<std::vector<KeyValue>> getAllMeterPublicKeyKeyValues() override;
std::set<MessageType> getSupportedMessageTypesSending() override;
std::set<MessageType> getSupportedMessageTypesReceiving() override;
KeyValue getAuthorizeConnectorZeroOnConnectorOneKeyValue() override;
KeyValue getCentralSystemURIKeyValue() override;
KeyValue getChargePointIdKeyValue() override;
KeyValue getChargePointModelKeyValue() override;
KeyValue getChargePointVendorKeyValue() override;
KeyValue getEnableTLSKeylogKeyValue() override;
KeyValue getLogMessagesFormatKeyValue() override;
KeyValue getLogMessagesKeyValue() override;
KeyValue getLogMessagesRawKeyValue() override;
KeyValue getLogRotationDateSuffixKeyValue() override;
KeyValue getLogRotationKeyValue() override;
KeyValue getLogRotationMaximumFileCountKeyValue() override;
KeyValue getLogRotationMaximumFileSizeKeyValue() override;
KeyValue getMaxCompositeScheduleDurationKeyValue() override;
KeyValue getMaxMessageSizeKeyValue() override;
KeyValue getOcspRequestIntervalKeyValue() override;
KeyValue getRetryBackoffRandomRangeKeyValue() override;
KeyValue getRetryBackoffRepeatTimesKeyValue() override;
KeyValue getRetryBackoffWaitMinimumKeyValue() override;
KeyValue getStopTransactionIfUnlockNotSupportedKeyValue() override;
KeyValue getSupportedChargingProfilePurposeTypesKeyValue() override;
KeyValue getSupportedCiphers12KeyValue() override;
KeyValue getSupportedCiphers13KeyValue() override;
KeyValue getSupportedMeasurandsKeyValue() override;
KeyValue getTLSKeylogFileKeyValue() override;
KeyValue getUseSslDefaultVerifyPathsKeyValue() override;
KeyValue getUseTPMKeyValue() override;
KeyValue getUseTPMSeccLeafCertificateKeyValue() override;
KeyValue getVerifyCsmsAllowWildcardsKeyValue() override;
KeyValue getVerifyCsmsCommonNameKeyValue() override;
KeyValue getWaitForStopTransactionsOnResetTimeoutKeyValue() override;
KeyValue getWebsocketPingPayloadKeyValue() override;
KeyValue getWebsocketPongTimeoutKeyValue() override;
std::optional<KeyValue> getAllowChargingProfileWithoutStartScheduleKeyValue() override;
std::optional<KeyValue> getCompositeScheduleDefaultLimitAmpsKeyValue() override;
std::optional<KeyValue> getCompositeScheduleDefaultLimitWattsKeyValue() override;
std::optional<KeyValue> getCompositeScheduleDefaultNumberPhasesKeyValue() override;
std::optional<KeyValue> getConnectorEvseIdsKeyValue() override;
std::optional<KeyValue> getHostNameKeyValue() override;
std::optional<KeyValue> getIFaceKeyValue() override;
std::optional<KeyValue> getIgnoredProfilePurposesOfflineKeyValue() override;
std::optional<KeyValue> getMessageTypesDiscardForQueueingKeyValue() override;
std::optional<KeyValue> getMessageQueueSizeThresholdKeyValue() override;
std::optional<KeyValue> getPublicKeyKeyValue(std::uint32_t connector_id) override;
std::optional<KeyValue> getQueueAllMessagesKeyValue() override;
std::optional<KeyValue> getSeccLeafSubjectCommonNameKeyValue() override;
std::optional<KeyValue> getSeccLeafSubjectCountryKeyValue() override;
std::optional<KeyValue> getSeccLeafSubjectOrganizationKeyValue() override;
std::optional<KeyValue> getSupplyVoltageKeyValue() override;
void setAllowChargingProfileWithoutStartSchedule(bool allow) override;
void setCentralSystemURI(const std::string& ocpp_uri) override;
void setCompositeScheduleDefaultLimitAmps(std::int32_t limit_amps) override;
void setCompositeScheduleDefaultLimitWatts(std::int32_t limit_watts) override;
void setCompositeScheduleDefaultNumberPhases(std::int32_t number_phases) override;
void setConnectorEvseIds(const std::string& connector_evse_ids) override;
bool setIgnoredProfilePurposesOffline(const std::string& ignored_profile_purposes_offline) override;
bool setMeterPublicKey(std::int32_t connector_id, const std::string& public_key_pem) override;
void setOcspRequestInterval(std::int32_t ocsp_request_interval) override;
void setRetryBackoffRandomRange(std::int32_t retry_backoff_random_range) override;
void setRetryBackoffRepeatTimes(std::int32_t retry_backoff_repeat_times) override;
void setRetryBackoffWaitMinimum(std::int32_t retry_backoff_wait_minimum) override;
void setSeccLeafSubjectCommonName(const std::string& secc_leaf_subject_common_name) override;
void setSeccLeafSubjectCountry(const std::string& secc_leaf_subject_country) override;
void setSeccLeafSubjectOrganization(const std::string& secc_leaf_subject_organization) override;
void setStopTransactionIfUnlockNotSupported(bool stop_transaction_if_unlock_not_supported) override;
void setSupplyVoltage(std::int32_t supply_voltage) override;
void setVerifyCsmsAllowWildcards(bool verify_csms_allow_wildcards) override;
void setWaitForStopTransactionsOnResetTimeout(std::int32_t wait_for_stop_transactions_on_reset_timeout) override;
// Core Profile
std::string getConnectorPhaseRotation() override;
std::string getMeterValuesAlignedData() override;
std::string getMeterValuesSampledData() override;
std::string getStopTxnAlignedData() override;
std::string getStopTxnSampledData() override;
std::string getSupportedFeatureProfiles() override;
bool getAuthorizeRemoteTxRequests() override;
bool getLocalAuthorizeOffline() override;
bool getLocalPreAuthorize() override;
bool getStopTransactionOnInvalidId() override;
bool getUnlockConnectorOnEVSideDisconnect() override;
std::int32_t getClockAlignedDataInterval() override;
std::int32_t getConnectionTimeOut() override;
std::int32_t getGetConfigurationMaxKeys() override;
std::int32_t getHeartbeatInterval() override;
std::int32_t getMeterValueSampleInterval() override;
std::int32_t getNumberOfConnectors() override;
std::int32_t getResetRetries() override;
std::int32_t getTransactionMessageAttempts() override;
std::int32_t getTransactionMessageRetryInterval() override;
std::vector<MeasurandWithPhase> getMeterValuesAlignedDataVector() override;
std::vector<MeasurandWithPhase> getMeterValuesSampledDataVector() override;
std::optional<bool> getAllowOfflineTxForUnknownId() override;
std::optional<bool> getAuthorizationCacheEnabled() override;
std::optional<bool> getReserveConnectorZeroSupported() override;
std::optional<bool> getStopTransactionOnEVSideDisconnect() override;
std::optional<std::int32_t> getBlinkRepeat() override;
std::optional<std::int32_t> getConnectorPhaseRotationMaxLength() override;
std::optional<std::int32_t> getLightIntensity() override;
std::optional<std::int32_t> getMaxEnergyOnInvalidId() override;
std::optional<std::int32_t> getMeterValuesAlignedDataMaxLength() override;
std::optional<std::int32_t> getMeterValuesSampledDataMaxLength() override;
std::optional<std::int32_t> getMinimumStatusDuration() override;
std::optional<std::int32_t> getStopTxnAlignedDataMaxLength() override;
std::optional<std::int32_t> getStopTxnSampledDataMaxLength() override;
std::optional<std::int32_t> getSupportedFeatureProfilesMaxLength() override;
std::optional<std::int32_t> getWebsocketPingInterval() override;
std::set<SupportedFeatureProfiles> getSupportedFeatureProfilesSet() override;
KeyValue getAuthorizeRemoteTxRequestsKeyValue() override;
KeyValue getClockAlignedDataIntervalKeyValue() override;
KeyValue getConnectionTimeOutKeyValue() override;
KeyValue getConnectorPhaseRotationKeyValue() override;
KeyValue getGetConfigurationMaxKeysKeyValue() override;
KeyValue getHeartbeatIntervalKeyValue() override;
KeyValue getLocalAuthorizeOfflineKeyValue() override;
KeyValue getLocalPreAuthorizeKeyValue() override;
KeyValue getMeterValuesAlignedDataKeyValue() override;
KeyValue getMeterValueSampleIntervalKeyValue() override;
KeyValue getMeterValuesSampledDataKeyValue() override;
KeyValue getNumberOfConnectorsKeyValue() override;
KeyValue getResetRetriesKeyValue() override;
KeyValue getStopTransactionOnInvalidIdKeyValue() override;
KeyValue getStopTxnAlignedDataKeyValue() override;
KeyValue getStopTxnSampledDataKeyValue() override;
KeyValue getSupportedFeatureProfilesKeyValue() override;
KeyValue getTransactionMessageAttemptsKeyValue() override;
KeyValue getTransactionMessageRetryIntervalKeyValue() override;
KeyValue getUnlockConnectorOnEVSideDisconnectKeyValue() override;
std::optional<KeyValue> getAllowOfflineTxForUnknownIdKeyValue() override;
std::optional<KeyValue> getAuthorizationCacheEnabledKeyValue() override;
std::optional<KeyValue> getBlinkRepeatKeyValue() override;
std::optional<KeyValue> getConnectorPhaseRotationMaxLengthKeyValue() override;
std::optional<KeyValue> getLightIntensityKeyValue() override;
std::optional<KeyValue> getMaxEnergyOnInvalidIdKeyValue() override;
std::optional<KeyValue> getMeterValuesAlignedDataMaxLengthKeyValue() override;
std::optional<KeyValue> getMeterValuesSampledDataMaxLengthKeyValue() override;
std::optional<KeyValue> getMinimumStatusDurationKeyValue() override;
std::optional<KeyValue> getReserveConnectorZeroSupportedKeyValue() override;
std::optional<KeyValue> getStopTransactionOnEVSideDisconnectKeyValue() override;
std::optional<KeyValue> getStopTxnAlignedDataMaxLengthKeyValue() override;
std::optional<KeyValue> getStopTxnSampledDataMaxLengthKeyValue() override;
std::optional<KeyValue> getSupportedFeatureProfilesMaxLengthKeyValue() override;
std::optional<KeyValue> getWebsocketPingIntervalKeyValue() override;
void setAllowOfflineTxForUnknownId(bool enabled) override;
void setAuthorizationCacheEnabled(bool enabled) override;
void setAuthorizeRemoteTxRequests(bool enabled) override;
void setBlinkRepeat(std::int32_t blink_repeat) override;
void setClockAlignedDataInterval(std::int32_t interval) override;
void setConnectionTimeOut(std::int32_t timeout) override;
void setConnectorPhaseRotation(const std::string& connector_phase_rotation) override;
void setHeartbeatInterval(std::int32_t interval) override;
void setLightIntensity(std::int32_t light_intensity) override;
void setLocalAuthorizeOffline(bool local_authorize_offline) override;
void setLocalPreAuthorize(bool local_pre_authorize) override;
void setMaxEnergyOnInvalidId(std::int32_t max_energy) override;
bool setMeterValuesAlignedData(const std::string& meter_values_aligned_data) override;
bool setMeterValuesSampledData(const std::string& meter_values_sampled_data) override;
void setMeterValueSampleInterval(std::int32_t interval) override;
void setMinimumStatusDuration(std::int32_t minimum_status_duration) override;
void setResetRetries(std::int32_t retries) override;
void setStopTransactionOnInvalidId(bool stop_transaction_on_invalid_id) override;
bool setStopTxnAlignedData(const std::string& stop_txn_aligned_data) override;
bool setStopTxnSampledData(const std::string& stop_txn_sampled_data) override;
void setTransactionMessageAttempts(std::int32_t attempts) override;
void setTransactionMessageRetryInterval(std::int32_t retry_interval) override;
void setUnlockConnectorOnEVSideDisconnect(bool unlock_connector_on_ev_side_disconnect) override;
void setWebsocketPingInterval(std::int32_t websocket_ping_interval) override;
// Firmware Management Profile
std::optional<std::string> getSupportedFileTransferProtocols() override;
std::optional<KeyValue> getSupportedFileTransferProtocolsKeyValue() override;
// Smart Charging Profile
std::string getChargingScheduleAllowedChargingRateUnit() override;
std::int32_t getChargeProfileMaxStackLevel() override;
std::int32_t getChargingScheduleMaxPeriods() override;
std::int32_t getMaxChargingProfilesInstalled() override;
std::optional<bool> getConnectorSwitch3to1PhaseSupported() override;
std::vector<ChargingRateUnit> getChargingScheduleAllowedChargingRateUnitVector() override;
KeyValue getChargeProfileMaxStackLevelKeyValue() override;
KeyValue getChargingScheduleAllowedChargingRateUnitKeyValue() override;
KeyValue getChargingScheduleMaxPeriodsKeyValue() override;
KeyValue getMaxChargingProfilesInstalledKeyValue() override;
std::optional<KeyValue> getConnectorSwitch3to1PhaseSupportedKeyValue() override;
// Security Profile
bool getDisableSecurityEventNotifications() override;
std::int32_t getSecurityProfile() override;
std::optional<std::string> getAuthorizationKey() override;
std::optional<std::string> getCpoName() override;
std::optional<bool> getAdditionalRootCertificateCheck() override;
std::optional<std::int32_t> getCertificateSignedMaxChainSize() override;
std::optional<std::int32_t> getCertificateStoreMaxLength() override;
KeyValue getDisableSecurityEventNotificationsKeyValue() override;
KeyValue getSecurityProfileKeyValue() override;
std::optional<KeyValue> getAdditionalRootCertificateCheckKeyValue() override;
std::optional<KeyValue> getAuthorizationKeyKeyValue() override;
std::optional<KeyValue> getCertificateSignedMaxChainSizeKeyValue() override;
std::optional<KeyValue> getCertificateStoreMaxLengthKeyValue() override;
std::optional<KeyValue> getCpoNameKeyValue() override;
void setAuthorizationKey(const std::string& authorization_key) override;
void setCpoName(const std::string& cpo_name) override;
void setDisableSecurityEventNotifications(bool disable_security_event_notifications) override;
void setSecurityProfile(std::int32_t security_profile) override;
// Local Auth List Management Profile
bool getLocalAuthListEnabled() override;
std::int32_t getLocalAuthListMaxLength() override;
std::int32_t getSendLocalListMaxLength() override;
KeyValue getLocalAuthListEnabledKeyValue() override;
KeyValue getLocalAuthListMaxLengthKeyValue() override;
KeyValue getSendLocalListMaxLengthKeyValue() override;
void setLocalAuthListEnabled(bool local_auth_list_enabled) override;
// PnC
bool getContractValidationOffline() override;
bool getISO15118CertificateManagementEnabled() override;
bool getISO15118PnCEnabled() override;
std::optional<bool> getCentralContractValidationAllowed() override;
std::optional<std::int32_t> getCertSigningRepeatTimes() override;
std::optional<std::int32_t> getCertSigningWaitMinimum() override;
KeyValue getContractValidationOfflineKeyValue() override;
KeyValue getISO15118CertificateManagementEnabledKeyValue() override;
KeyValue getISO15118PnCEnabledKeyValue() override;
std::optional<KeyValue> getCentralContractValidationAllowedKeyValue() override;
std::optional<KeyValue> getCertSigningRepeatTimesKeyValue() override;
std::optional<KeyValue> getCertSigningWaitMinimumKeyValue() override;
void setContractValidationOffline(bool contract_validation_offline) override;
void setCentralContractValidationAllowed(bool central_contract_validation_allowed) override;
void setCertSigningRepeatTimes(std::int32_t cert_signing_repeat_times) override;
void setCertSigningWaitMinimum(std::int32_t cert_signing_wait_minimum) override;
void setISO15118CertificateManagementEnabled(bool iso15118_certificate_management_enabled) override;
void setISO15118PnCEnabled(bool iso15118_pnc_enabled) override;
// California Pricing Requirements
bool getCustomDisplayCostAndPriceEnabled() override;
TariffMessage getDefaultTariffMessage(bool offline) override;
std::optional<std::string> getDefaultPrice() override;
std::optional<std::string> getDefaultPriceText(const std::string& language) override;
std::optional<std::string> getDisplayTimeOffset() override;
std::optional<std::string> getLanguage() override;
std::optional<std::string> getMultiLanguageSupportedLanguages() override;
std::optional<std::string> getNextTimeOffsetTransitionDateTime() override;
std::optional<std::string> getTimeOffsetNextTransition() override;
std::optional<bool> getCustomIdleFeeAfterStop() override;
std::optional<bool> getCustomMultiLanguageMessagesEnabled() override;
std::optional<std::int32_t> getWaitForSetUserPriceTimeout() override;
std::optional<std::uint32_t> getPriceNumberOfDecimalsForCostValues() override;
KeyValue getCustomDisplayCostAndPriceEnabledKeyValue() override;
KeyValue getDefaultPriceTextKeyValue(const std::string& language) override;
std::optional<KeyValue> getCustomIdleFeeAfterStopKeyValue() override;
std::optional<KeyValue> getCustomMultiLanguageMessagesEnabledKeyValue() override;
std::optional<KeyValue> getDefaultPriceKeyValue() override;
std::optional<KeyValue> getDisplayTimeOffsetKeyValue() override;
std::optional<KeyValue> getLanguageKeyValue() override;
std::optional<KeyValue> getMultiLanguageSupportedLanguagesKeyValue() override;
std::optional<KeyValue> getNextTimeOffsetTransitionDateTimeKeyValue() override;
std::optional<KeyValue> getPriceNumberOfDecimalsForCostValuesKeyValue() override;
std::optional<KeyValue> getTimeOffsetNextTransitionKeyValue() override;
std::optional<KeyValue> getWaitForSetUserPriceTimeoutKeyValue() override;
std::optional<std::vector<KeyValue>> getAllDefaultPriceTextKeyValues() override;
void setCustomIdleFeeAfterStop(bool value) override;
ConfigurationStatus setDefaultPrice(const std::string& value) override;
ConfigurationStatus setDefaultPriceText(const CiString<50>& key, const CiString<500>& value) override;
ConfigurationStatus setDisplayTimeOffset(const std::string& offset) override;
void setLanguage(const std::string& language) override;
ConfigurationStatus setNextTimeOffsetTransitionDateTime(const std::string& date_time) override;
ConfigurationStatus setTimeOffsetNextTransition(const std::string& offset) override;
void setWaitForSetUserPriceTimeout(std::int32_t wait_for_set_user_price_timeout) override;
// Custom
std::optional<KeyValue> getCustomKeyValue(const CiString<50>& key) override;
std::optional<KeyValue> get(const CiString<50>& key) override;
std::vector<KeyValue> get_all_key_value() override;
ConfigurationStatus setCustomKey(const CiString<50>& key, const CiString<500>& value, bool force) override;
std::optional<ConfigurationStatus> set(const CiString<50>& key, const CiString<500>& value) override;
};
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CHARGE_POINT_CONFIGURATION_DEVICEMODEL_HPP

View File

@@ -0,0 +1,425 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_CONFIGURATION_INTERFACE_HPP
#define OCPP_V16_CHARGE_POINT_CONFIGURATION_INTERFACE_HPP
#include <cstdint>
#include <optional>
#include <set>
#include <string>
#include <vector>
#include <ocpp/common/cistring.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/types.hpp>
namespace ocpp::v16 {
struct KeyValue;
/// \brief contains the configuration of the charge point
class ChargePointConfigurationInterface {
public:
virtual ~ChargePointConfigurationInterface() = default;
// UserConfig and Internal
virtual std::string getChargeBoxSerialNumber() = 0;
virtual std::optional<CiString<25>> getChargePointSerialNumber() = 0;
virtual CiString<50> getFirmwareVersion() = 0;
virtual std::optional<CiString<20>> getICCID() = 0;
virtual std::optional<CiString<20>> getIMSI() = 0;
virtual std::optional<CiString<25>> getMeterSerialNumber() = 0;
virtual std::optional<CiString<25>> getMeterType() = 0;
virtual KeyValue getChargeBoxSerialNumberKeyValue() = 0;
virtual KeyValue getFirmwareVersionKeyValue() = 0;
virtual std::optional<KeyValue> getChargePointSerialNumberKeyValue() = 0;
virtual std::optional<KeyValue> getICCIDKeyValue() = 0;
virtual std::optional<KeyValue> getIMSIKeyValue() = 0;
virtual std::optional<KeyValue> getMeterSerialNumberKeyValue() = 0;
virtual std::optional<KeyValue> getMeterTypeKeyValue() = 0;
virtual void setChargepointInformation(const std::string& chargePointVendor, const std::string& chargePointModel,
const std::optional<std::string>& chargePointSerialNumber,
const std::optional<std::string>& chargeBoxSerialNumber,
const std::optional<std::string>& firmwareVersion) = 0;
virtual void setChargepointMeterInformation(const std::optional<std::string>& meterSerialNumber,
const std::optional<std::string>& meterType) = 0;
virtual void setChargepointModemInformation(const std::optional<std::string>& ICCID,
const std::optional<std::string>& IMSI) = 0;
// Internal
virtual std::string getCentralSystemURI() = 0;
virtual std::string getChargePointId() = 0;
virtual std::string getSupportedCiphers12() = 0;
virtual std::string getSupportedCiphers13() = 0;
virtual std::string getSupportedMeasurands() = 0;
virtual std::string getTLSKeylogFile() = 0;
virtual std::string getWebsocketPingPayload() = 0;
virtual CiString<20> getChargePointModel() = 0;
virtual CiString<20> getChargePointVendor() = 0;
virtual bool getAuthorizeConnectorZeroOnConnectorOne() = 0;
virtual bool getEnableTLSKeylog() = 0;
virtual bool getLogMessages() = 0;
virtual bool getLogMessagesRaw() = 0;
virtual bool getLogRotation() = 0;
virtual bool getLogRotationDateSuffix() = 0;
virtual bool getStopTransactionIfUnlockNotSupported() = 0;
virtual bool getUseSslDefaultVerifyPaths() = 0;
virtual bool getUseTPM() = 0;
virtual bool getUseTPMSeccLeafCertificate() = 0;
virtual bool getVerifyCsmsAllowWildcards() = 0;
virtual bool getVerifyCsmsCommonName() = 0;
virtual int getMaxMessageSize() = 0;
virtual std::int32_t getMaxCompositeScheduleDuration() = 0;
virtual std::int32_t getOcspRequestInterval() = 0;
virtual std::int32_t getRetryBackoffRandomRange() = 0;
virtual std::int32_t getRetryBackoffRepeatTimes() = 0;
virtual std::int32_t getRetryBackoffWaitMinimum() = 0;
virtual std::int32_t getWaitForStopTransactionsOnResetTimeout() = 0;
virtual std::int32_t getWebsocketPongTimeout() = 0;
virtual std::uint64_t getLogRotationMaximumFileCount() = 0;
virtual std::uint64_t getLogRotationMaximumFileSize() = 0;
virtual std::vector<std::string> getLogMessagesFormat() = 0;
virtual std::vector<ChargingProfilePurposeType> getIgnoredProfilePurposesOffline() = 0;
virtual std::vector<ChargingProfilePurposeType> getSupportedChargingProfilePurposeTypes() = 0;
virtual std::optional<std::string> getConnectorEvseIds() = 0;
virtual std::optional<std::string> getHostName() = 0;
virtual std::optional<std::string> getIFace() = 0;
virtual std::optional<std::string> getMessageTypesDiscardForQueueing() = 0;
virtual std::optional<std::string> getSeccLeafSubjectCommonName() = 0;
virtual std::optional<std::string> getSeccLeafSubjectCountry() = 0;
virtual std::optional<std::string> getSeccLeafSubjectOrganization() = 0;
virtual std::optional<bool> getAllowChargingProfileWithoutStartSchedule() = 0;
virtual std::optional<bool> getQueueAllMessages() = 0;
virtual std::optional<int> getMessageQueueSizeThreshold() = 0;
virtual std::optional<std::int32_t> getCompositeScheduleDefaultLimitAmps() = 0;
virtual std::optional<std::int32_t> getCompositeScheduleDefaultLimitWatts() = 0;
virtual std::optional<std::int32_t> getCompositeScheduleDefaultNumberPhases() = 0;
virtual std::optional<std::int32_t> getSupplyVoltage() = 0;
virtual std::optional<std::vector<KeyValue>> getAllMeterPublicKeyKeyValues() = 0;
virtual std::set<MessageType> getSupportedMessageTypesSending() = 0;
virtual std::set<MessageType> getSupportedMessageTypesReceiving() = 0;
virtual KeyValue getAuthorizeConnectorZeroOnConnectorOneKeyValue() = 0;
virtual KeyValue getCentralSystemURIKeyValue() = 0;
virtual KeyValue getChargePointIdKeyValue() = 0;
virtual KeyValue getChargePointModelKeyValue() = 0;
virtual KeyValue getChargePointVendorKeyValue() = 0;
virtual KeyValue getEnableTLSKeylogKeyValue() = 0;
virtual KeyValue getLogMessagesFormatKeyValue() = 0;
virtual KeyValue getLogMessagesKeyValue() = 0;
virtual KeyValue getLogMessagesRawKeyValue() = 0;
virtual KeyValue getLogRotationDateSuffixKeyValue() = 0;
virtual KeyValue getLogRotationKeyValue() = 0;
virtual KeyValue getLogRotationMaximumFileCountKeyValue() = 0;
virtual KeyValue getLogRotationMaximumFileSizeKeyValue() = 0;
virtual KeyValue getMaxCompositeScheduleDurationKeyValue() = 0;
virtual KeyValue getMaxMessageSizeKeyValue() = 0;
virtual KeyValue getOcspRequestIntervalKeyValue() = 0;
virtual KeyValue getRetryBackoffRandomRangeKeyValue() = 0;
virtual KeyValue getRetryBackoffRepeatTimesKeyValue() = 0;
virtual KeyValue getRetryBackoffWaitMinimumKeyValue() = 0;
virtual KeyValue getStopTransactionIfUnlockNotSupportedKeyValue() = 0;
virtual KeyValue getSupportedChargingProfilePurposeTypesKeyValue() = 0;
virtual KeyValue getSupportedCiphers12KeyValue() = 0;
virtual KeyValue getSupportedCiphers13KeyValue() = 0;
virtual KeyValue getSupportedMeasurandsKeyValue() = 0;
virtual KeyValue getTLSKeylogFileKeyValue() = 0;
virtual KeyValue getUseSslDefaultVerifyPathsKeyValue() = 0;
virtual KeyValue getUseTPMKeyValue() = 0;
virtual KeyValue getUseTPMSeccLeafCertificateKeyValue() = 0;
virtual KeyValue getVerifyCsmsAllowWildcardsKeyValue() = 0;
virtual KeyValue getVerifyCsmsCommonNameKeyValue() = 0;
virtual KeyValue getWaitForStopTransactionsOnResetTimeoutKeyValue() = 0;
virtual KeyValue getWebsocketPingPayloadKeyValue() = 0;
virtual KeyValue getWebsocketPongTimeoutKeyValue() = 0;
virtual std::optional<KeyValue> getAllowChargingProfileWithoutStartScheduleKeyValue() = 0;
virtual std::optional<KeyValue> getCompositeScheduleDefaultLimitAmpsKeyValue() = 0;
virtual std::optional<KeyValue> getCompositeScheduleDefaultLimitWattsKeyValue() = 0;
virtual std::optional<KeyValue> getCompositeScheduleDefaultNumberPhasesKeyValue() = 0;
virtual std::optional<KeyValue> getConnectorEvseIdsKeyValue() = 0;
virtual std::optional<KeyValue> getHostNameKeyValue() = 0;
virtual std::optional<KeyValue> getIFaceKeyValue() = 0;
virtual std::optional<KeyValue> getIgnoredProfilePurposesOfflineKeyValue() = 0;
virtual std::optional<KeyValue> getMessageTypesDiscardForQueueingKeyValue() = 0;
virtual std::optional<KeyValue> getMessageQueueSizeThresholdKeyValue() = 0;
virtual std::optional<KeyValue> getPublicKeyKeyValue(std::uint32_t connector_id) = 0;
virtual std::optional<KeyValue> getQueueAllMessagesKeyValue() = 0;
virtual std::optional<KeyValue> getSeccLeafSubjectCommonNameKeyValue() = 0;
virtual std::optional<KeyValue> getSeccLeafSubjectCountryKeyValue() = 0;
virtual std::optional<KeyValue> getSeccLeafSubjectOrganizationKeyValue() = 0;
virtual std::optional<KeyValue> getSupplyVoltageKeyValue() = 0;
virtual void setAllowChargingProfileWithoutStartSchedule(bool allow) = 0;
virtual void setCentralSystemURI(const std::string& ocpp_uri) = 0;
virtual void setCompositeScheduleDefaultLimitAmps(std::int32_t limit_amps) = 0;
virtual void setCompositeScheduleDefaultLimitWatts(std::int32_t limit_watts) = 0;
virtual void setCompositeScheduleDefaultNumberPhases(std::int32_t number_phases) = 0;
virtual void setConnectorEvseIds(const std::string& connector_evse_ids) = 0;
virtual bool setIgnoredProfilePurposesOffline(const std::string& ignored_profile_purposes_offline) = 0;
virtual bool setMeterPublicKey(std::int32_t connector_id, const std::string& public_key_pem) = 0;
virtual void setOcspRequestInterval(std::int32_t ocsp_request_interval) = 0;
virtual void setRetryBackoffRandomRange(std::int32_t retry_backoff_random_range) = 0;
virtual void setRetryBackoffRepeatTimes(std::int32_t retry_backoff_repeat_times) = 0;
virtual void setRetryBackoffWaitMinimum(std::int32_t retry_backoff_wait_minimum) = 0;
virtual void setSeccLeafSubjectCommonName(const std::string& secc_leaf_subject_common_name) = 0;
virtual void setSeccLeafSubjectCountry(const std::string& secc_leaf_subject_country) = 0;
virtual void setSeccLeafSubjectOrganization(const std::string& secc_leaf_subject_organization) = 0;
virtual void setStopTransactionIfUnlockNotSupported(bool stop_transaction_if_unlock_not_supported) = 0;
virtual void setSupplyVoltage(std::int32_t supply_voltage) = 0;
virtual void setVerifyCsmsAllowWildcards(bool verify_csms_allow_wildcards) = 0;
virtual void setWaitForStopTransactionsOnResetTimeout(std::int32_t wait_for_stop_transactions_on_reset_timeout) = 0;
// Core Profile
virtual std::string getConnectorPhaseRotation() = 0;
virtual std::string getMeterValuesAlignedData() = 0;
virtual std::string getMeterValuesSampledData() = 0;
virtual std::string getStopTxnAlignedData() = 0;
virtual std::string getStopTxnSampledData() = 0;
virtual std::string getSupportedFeatureProfiles() = 0;
virtual bool getAuthorizeRemoteTxRequests() = 0;
virtual bool getLocalAuthorizeOffline() = 0;
virtual bool getLocalPreAuthorize() = 0;
virtual bool getStopTransactionOnInvalidId() = 0;
virtual bool getUnlockConnectorOnEVSideDisconnect() = 0;
virtual std::int32_t getClockAlignedDataInterval() = 0;
virtual std::int32_t getConnectionTimeOut() = 0;
virtual std::int32_t getGetConfigurationMaxKeys() = 0;
virtual std::int32_t getHeartbeatInterval() = 0;
virtual std::int32_t getMeterValueSampleInterval() = 0;
virtual std::int32_t getNumberOfConnectors() = 0;
virtual std::int32_t getResetRetries() = 0;
virtual std::int32_t getTransactionMessageAttempts() = 0;
virtual std::int32_t getTransactionMessageRetryInterval() = 0;
virtual std::vector<MeasurandWithPhase> getMeterValuesAlignedDataVector() = 0;
virtual std::vector<MeasurandWithPhase> getMeterValuesSampledDataVector() = 0;
virtual std::optional<bool> getAllowOfflineTxForUnknownId() = 0;
virtual std::optional<bool> getAuthorizationCacheEnabled() = 0;
virtual std::optional<bool> getReserveConnectorZeroSupported() = 0;
virtual std::optional<bool> getStopTransactionOnEVSideDisconnect() = 0;
virtual std::optional<std::int32_t> getBlinkRepeat() = 0;
virtual std::optional<std::int32_t> getConnectorPhaseRotationMaxLength() = 0;
virtual std::optional<std::int32_t> getLightIntensity() = 0;
virtual std::optional<std::int32_t> getMaxEnergyOnInvalidId() = 0;
virtual std::optional<std::int32_t> getMeterValuesAlignedDataMaxLength() = 0;
virtual std::optional<std::int32_t> getMeterValuesSampledDataMaxLength() = 0;
virtual std::optional<std::int32_t> getMinimumStatusDuration() = 0;
virtual std::optional<std::int32_t> getStopTxnAlignedDataMaxLength() = 0;
virtual std::optional<std::int32_t> getStopTxnSampledDataMaxLength() = 0;
virtual std::optional<std::int32_t> getSupportedFeatureProfilesMaxLength() = 0;
virtual std::optional<std::int32_t> getWebsocketPingInterval() = 0;
virtual std::set<SupportedFeatureProfiles> getSupportedFeatureProfilesSet() = 0;
virtual KeyValue getAuthorizeRemoteTxRequestsKeyValue() = 0;
virtual KeyValue getClockAlignedDataIntervalKeyValue() = 0;
virtual KeyValue getConnectionTimeOutKeyValue() = 0;
virtual KeyValue getConnectorPhaseRotationKeyValue() = 0;
virtual KeyValue getGetConfigurationMaxKeysKeyValue() = 0;
virtual KeyValue getHeartbeatIntervalKeyValue() = 0;
virtual KeyValue getLocalAuthorizeOfflineKeyValue() = 0;
virtual KeyValue getLocalPreAuthorizeKeyValue() = 0;
virtual KeyValue getMeterValuesAlignedDataKeyValue() = 0;
virtual KeyValue getMeterValueSampleIntervalKeyValue() = 0;
virtual KeyValue getMeterValuesSampledDataKeyValue() = 0;
virtual KeyValue getNumberOfConnectorsKeyValue() = 0;
virtual KeyValue getResetRetriesKeyValue() = 0;
virtual KeyValue getStopTransactionOnInvalidIdKeyValue() = 0;
virtual KeyValue getStopTxnAlignedDataKeyValue() = 0;
virtual KeyValue getStopTxnSampledDataKeyValue() = 0;
virtual KeyValue getSupportedFeatureProfilesKeyValue() = 0;
virtual KeyValue getTransactionMessageAttemptsKeyValue() = 0;
virtual KeyValue getTransactionMessageRetryIntervalKeyValue() = 0;
virtual KeyValue getUnlockConnectorOnEVSideDisconnectKeyValue() = 0;
virtual std::optional<KeyValue> getAllowOfflineTxForUnknownIdKeyValue() = 0;
virtual std::optional<KeyValue> getAuthorizationCacheEnabledKeyValue() = 0;
virtual std::optional<KeyValue> getBlinkRepeatKeyValue() = 0;
virtual std::optional<KeyValue> getConnectorPhaseRotationMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getLightIntensityKeyValue() = 0;
virtual std::optional<KeyValue> getMaxEnergyOnInvalidIdKeyValue() = 0;
virtual std::optional<KeyValue> getMeterValuesAlignedDataMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getMeterValuesSampledDataMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getMinimumStatusDurationKeyValue() = 0;
virtual std::optional<KeyValue> getReserveConnectorZeroSupportedKeyValue() = 0;
virtual std::optional<KeyValue> getStopTransactionOnEVSideDisconnectKeyValue() = 0;
virtual std::optional<KeyValue> getStopTxnAlignedDataMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getStopTxnSampledDataMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getSupportedFeatureProfilesMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getWebsocketPingIntervalKeyValue() = 0;
virtual void setAllowOfflineTxForUnknownId(bool enabled) = 0;
virtual void setAuthorizationCacheEnabled(bool enabled) = 0;
virtual void setAuthorizeRemoteTxRequests(bool enabled) = 0;
virtual void setBlinkRepeat(std::int32_t blink_repeat) = 0;
virtual void setClockAlignedDataInterval(std::int32_t interval) = 0;
virtual void setConnectionTimeOut(std::int32_t timeout) = 0;
virtual void setConnectorPhaseRotation(const std::string& connector_phase_rotation) = 0;
virtual void setHeartbeatInterval(std::int32_t interval) = 0;
virtual void setLightIntensity(std::int32_t light_intensity) = 0;
virtual void setLocalAuthorizeOffline(bool local_authorize_offline) = 0;
virtual void setLocalPreAuthorize(bool local_pre_authorize) = 0;
virtual void setMaxEnergyOnInvalidId(std::int32_t max_energy) = 0;
virtual bool setMeterValuesAlignedData(const std::string& meter_values_aligned_data) = 0;
virtual bool setMeterValuesSampledData(const std::string& meter_values_sampled_data) = 0;
virtual void setMeterValueSampleInterval(std::int32_t interval) = 0;
virtual void setMinimumStatusDuration(std::int32_t minimum_status_duration) = 0;
virtual void setResetRetries(std::int32_t retries) = 0;
virtual void setStopTransactionOnInvalidId(bool stop_transaction_on_invalid_id) = 0;
virtual bool setStopTxnAlignedData(const std::string& stop_txn_aligned_data) = 0;
virtual bool setStopTxnSampledData(const std::string& stop_txn_sampled_data) = 0;
virtual void setTransactionMessageAttempts(std::int32_t attempts) = 0;
virtual void setTransactionMessageRetryInterval(std::int32_t retry_interval) = 0;
virtual void setUnlockConnectorOnEVSideDisconnect(bool unlock_connector_on_ev_side_disconnect) = 0;
virtual void setWebsocketPingInterval(std::int32_t websocket_ping_interval) = 0;
// Firmware Management Profile
virtual std::optional<std::string> getSupportedFileTransferProtocols() = 0;
virtual std::optional<KeyValue> getSupportedFileTransferProtocolsKeyValue() = 0;
// Smart Charging Profile
virtual std::string getChargingScheduleAllowedChargingRateUnit() = 0;
virtual std::int32_t getChargeProfileMaxStackLevel() = 0;
virtual std::int32_t getChargingScheduleMaxPeriods() = 0;
virtual std::int32_t getMaxChargingProfilesInstalled() = 0;
virtual std::optional<bool> getConnectorSwitch3to1PhaseSupported() = 0;
virtual std::vector<ChargingRateUnit> getChargingScheduleAllowedChargingRateUnitVector() = 0;
virtual KeyValue getChargeProfileMaxStackLevelKeyValue() = 0;
virtual KeyValue getChargingScheduleAllowedChargingRateUnitKeyValue() = 0;
virtual KeyValue getChargingScheduleMaxPeriodsKeyValue() = 0;
virtual KeyValue getMaxChargingProfilesInstalledKeyValue() = 0;
virtual std::optional<KeyValue> getConnectorSwitch3to1PhaseSupportedKeyValue() = 0;
// Security Profile
virtual bool getDisableSecurityEventNotifications() = 0;
virtual std::int32_t getSecurityProfile() = 0;
virtual std::optional<std::string> getAuthorizationKey() = 0;
virtual std::optional<std::string> getCpoName() = 0;
virtual std::optional<bool> getAdditionalRootCertificateCheck() = 0;
virtual std::optional<std::int32_t> getCertificateSignedMaxChainSize() = 0;
virtual std::optional<std::int32_t> getCertificateStoreMaxLength() = 0;
virtual KeyValue getDisableSecurityEventNotificationsKeyValue() = 0;
virtual KeyValue getSecurityProfileKeyValue() = 0;
virtual std::optional<KeyValue> getAdditionalRootCertificateCheckKeyValue() = 0;
virtual std::optional<KeyValue> getAuthorizationKeyKeyValue() = 0;
virtual std::optional<KeyValue> getCertificateSignedMaxChainSizeKeyValue() = 0;
virtual std::optional<KeyValue> getCertificateStoreMaxLengthKeyValue() = 0;
virtual std::optional<KeyValue> getCpoNameKeyValue() = 0;
virtual void setAuthorizationKey(const std::string& authorization_key) = 0;
virtual void setCpoName(const std::string& cpo_name) = 0;
virtual void setDisableSecurityEventNotifications(bool disable_security_event_notifications) = 0;
virtual void setSecurityProfile(std::int32_t security_profile) = 0;
// Local Auth List Management Profile
virtual bool getLocalAuthListEnabled() = 0;
virtual std::int32_t getLocalAuthListMaxLength() = 0;
virtual std::int32_t getSendLocalListMaxLength() = 0;
virtual KeyValue getLocalAuthListEnabledKeyValue() = 0;
virtual KeyValue getLocalAuthListMaxLengthKeyValue() = 0;
virtual KeyValue getSendLocalListMaxLengthKeyValue() = 0;
virtual void setLocalAuthListEnabled(bool local_auth_list_enabled) = 0;
// PnC
virtual bool getContractValidationOffline() = 0;
virtual bool getISO15118CertificateManagementEnabled() = 0;
virtual bool getISO15118PnCEnabled() = 0;
virtual std::optional<bool> getCentralContractValidationAllowed() = 0;
virtual std::optional<std::int32_t> getCertSigningRepeatTimes() = 0;
virtual std::optional<std::int32_t> getCertSigningWaitMinimum() = 0;
virtual KeyValue getContractValidationOfflineKeyValue() = 0;
virtual KeyValue getISO15118CertificateManagementEnabledKeyValue() = 0;
virtual KeyValue getISO15118PnCEnabledKeyValue() = 0;
virtual std::optional<KeyValue> getCentralContractValidationAllowedKeyValue() = 0;
virtual std::optional<KeyValue> getCertSigningRepeatTimesKeyValue() = 0;
virtual std::optional<KeyValue> getCertSigningWaitMinimumKeyValue() = 0;
virtual void setContractValidationOffline(bool contract_validation_offline) = 0;
virtual void setCentralContractValidationAllowed(bool central_contract_validation_allowed) = 0;
virtual void setCertSigningRepeatTimes(std::int32_t cert_signing_repeat_times) = 0;
virtual void setCertSigningWaitMinimum(std::int32_t cert_signing_wait_minimum) = 0;
virtual void setISO15118CertificateManagementEnabled(bool iso15118_certificate_management_enabled) = 0;
virtual void setISO15118PnCEnabled(bool iso15118_pnc_enabled) = 0;
// California Pricing Requirements
virtual bool getCustomDisplayCostAndPriceEnabled() = 0;
virtual TariffMessage getDefaultTariffMessage(bool offline) = 0;
virtual std::optional<std::string> getDefaultPrice() = 0;
virtual std::optional<std::string> getDefaultPriceText(const std::string& language) = 0;
virtual std::optional<std::string> getDisplayTimeOffset() = 0;
virtual std::optional<std::string> getLanguage() = 0;
virtual std::optional<std::string> getMultiLanguageSupportedLanguages() = 0;
virtual std::optional<std::string> getNextTimeOffsetTransitionDateTime() = 0;
virtual std::optional<std::string> getTimeOffsetNextTransition() = 0;
virtual std::optional<bool> getCustomIdleFeeAfterStop() = 0;
virtual std::optional<bool> getCustomMultiLanguageMessagesEnabled() = 0;
virtual std::optional<std::int32_t> getWaitForSetUserPriceTimeout() = 0;
virtual std::optional<std::uint32_t> getPriceNumberOfDecimalsForCostValues() = 0;
virtual KeyValue getCustomDisplayCostAndPriceEnabledKeyValue() = 0;
virtual KeyValue getDefaultPriceTextKeyValue(const std::string& language) = 0;
virtual std::optional<KeyValue> getCustomIdleFeeAfterStopKeyValue() = 0;
virtual std::optional<KeyValue> getCustomMultiLanguageMessagesEnabledKeyValue() = 0;
virtual std::optional<KeyValue> getDefaultPriceKeyValue() = 0;
virtual std::optional<KeyValue> getDisplayTimeOffsetKeyValue() = 0;
virtual std::optional<KeyValue> getLanguageKeyValue() = 0;
virtual std::optional<KeyValue> getMultiLanguageSupportedLanguagesKeyValue() = 0;
virtual std::optional<KeyValue> getNextTimeOffsetTransitionDateTimeKeyValue() = 0;
virtual std::optional<KeyValue> getPriceNumberOfDecimalsForCostValuesKeyValue() = 0;
virtual std::optional<KeyValue> getTimeOffsetNextTransitionKeyValue() = 0;
virtual std::optional<KeyValue> getWaitForSetUserPriceTimeoutKeyValue() = 0;
virtual std::optional<std::vector<KeyValue>> getAllDefaultPriceTextKeyValues() = 0;
virtual void setCustomIdleFeeAfterStop(bool value) = 0;
virtual ConfigurationStatus setDefaultPrice(const std::string& value) = 0;
virtual ConfigurationStatus setDefaultPriceText(const CiString<50>& key, const CiString<500>& value) = 0;
virtual ConfigurationStatus setDisplayTimeOffset(const std::string& offset) = 0;
virtual void setLanguage(const std::string& language) = 0;
virtual ConfigurationStatus setNextTimeOffsetTransitionDateTime(const std::string& date_time) = 0;
virtual ConfigurationStatus setTimeOffsetNextTransition(const std::string& offset) = 0;
virtual void setWaitForSetUserPriceTimeout(std::int32_t wait_for_set_user_price_timeout) = 0;
// Signed Meter Values
// Custom
virtual std::optional<KeyValue> getCustomKeyValue(const CiString<50>& key) = 0;
virtual std::optional<KeyValue> get(const CiString<50>& key) = 0;
virtual std::vector<KeyValue> get_all_key_value() = 0;
virtual ConfigurationStatus setCustomKey(const CiString<50>& key, const CiString<500>& value, bool force) = 0;
virtual std::optional<ConfigurationStatus> set(const CiString<50>& key, const CiString<500>& value) = 0;
};
} // namespace ocpp::v16
#endif // OCPP_V16_CHARGE_POINT_CONFIGURATION_INTERFACE_HPP

View File

@@ -0,0 +1,958 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_IMPL_HPP
#define OCPP_V16_CHARGE_POINT_IMPL_HPP
#include "ocpp/v16/ocpp_enums.hpp"
#include <atomic>
#include <chrono>
#include <date/date.h>
#include <date/tz.h>
#include <future>
#include <iostream>
#include <mutex>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <optional>
#include <set>
#include <everest/timer.hpp>
#include <ocpp/common/aligned_timer.hpp>
#include <ocpp/common/charging_station_base.hpp>
#include <ocpp/common/message_dispatcher.hpp>
#include <ocpp/common/message_queue.hpp>
#include <ocpp/common/schemas.hpp>
#include <ocpp/common/types.hpp>
#include <ocpp/common/websocket/websocket.hpp>
#include <ocpp/v16/charge_point_configuration_interface.hpp>
#include <ocpp/v16/connector.hpp>
#include <ocpp/v16/database_handler.hpp>
#include <ocpp/v16/message_dispatcher.hpp>
#include <ocpp/v16/messages/Authorize.hpp>
#include <ocpp/v16/messages/BootNotification.hpp>
#include <ocpp/v16/messages/CancelReservation.hpp>
#include <ocpp/v16/messages/CertificateSigned.hpp>
#include <ocpp/v16/messages/ChangeAvailability.hpp>
#include <ocpp/v16/messages/ChangeConfiguration.hpp>
#include <ocpp/v16/messages/ClearCache.hpp>
#include <ocpp/v16/messages/ClearChargingProfile.hpp>
#include <ocpp/v16/messages/DataTransfer.hpp>
#include <ocpp/v16/messages/DeleteCertificate.hpp>
#include <ocpp/v16/messages/DiagnosticsStatusNotification.hpp>
#include <ocpp/v16/messages/ExtendedTriggerMessage.hpp>
#include <ocpp/v16/messages/FirmwareStatusNotification.hpp>
#include <ocpp/v16/messages/GetCompositeSchedule.hpp>
#include <ocpp/v16/messages/GetConfiguration.hpp>
#include <ocpp/v16/messages/GetDiagnostics.hpp>
#include <ocpp/v16/messages/GetInstalledCertificateIds.hpp>
#include <ocpp/v16/messages/GetLocalListVersion.hpp>
#include <ocpp/v16/messages/GetLog.hpp>
#include <ocpp/v16/messages/Heartbeat.hpp>
#include <ocpp/v16/messages/InstallCertificate.hpp>
#include <ocpp/v16/messages/LogStatusNotification.hpp>
#include <ocpp/v16/messages/MeterValues.hpp>
#include <ocpp/v16/messages/RemoteStartTransaction.hpp>
#include <ocpp/v16/messages/RemoteStopTransaction.hpp>
#include <ocpp/v16/messages/ReserveNow.hpp>
#include <ocpp/v16/messages/Reset.hpp>
#include <ocpp/v16/messages/SecurityEventNotification.hpp>
#include <ocpp/v16/messages/SendLocalList.hpp>
#include <ocpp/v16/messages/SetChargingProfile.hpp>
#include <ocpp/v16/messages/SignCertificate.hpp>
#include <ocpp/v16/messages/SignedFirmwareStatusNotification.hpp>
#include <ocpp/v16/messages/SignedUpdateFirmware.hpp>
#include <ocpp/v16/messages/StartTransaction.hpp>
#include <ocpp/v16/messages/StatusNotification.hpp>
#include <ocpp/v16/messages/StopTransaction.hpp>
#include <ocpp/v16/messages/TriggerMessage.hpp>
#include <ocpp/v16/messages/UnlockConnector.hpp>
#include <ocpp/v16/messages/UpdateFirmware.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/smart_charging.hpp>
#include <ocpp/v16/transaction.hpp>
#include <ocpp/v16/types.hpp>
// for OCPP1.6 PnC
#include <ocpp/v2/messages/Authorize.hpp>
#include <ocpp/v2/messages/CertificateSigned.hpp>
#include <ocpp/v2/messages/DeleteCertificate.hpp>
#include <ocpp/v2/messages/Get15118EVCertificate.hpp>
#include <ocpp/v2/messages/GetCertificateStatus.hpp>
#include <ocpp/v2/messages/GetInstalledCertificateIds.hpp>
#include <ocpp/v2/messages/InstallCertificate.hpp>
#include <ocpp/v2/messages/SignCertificate.hpp>
#include <ocpp/v2/messages/TriggerMessage.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a ChargePoint implementation compatible with OCPP-J 1.6
class ChargePointImpl : ocpp::ChargingStationBase {
private:
ChargePointConfigurationInterface& configuration;
BootReasonEnum bootreason{BootReasonEnum::PowerUp};
bool initialized{false};
bool InvalidCSMSCertificate_logged{false};
bool wants_to_be_connected{false};
ChargePointConnectionState connection_state{ChargePointConnectionState::Disconnected};
std::atomic<RegistrationStatus> registration_status{RegistrationStatus::Pending};
DiagnosticsStatus diagnostics_status{DiagnosticsStatus::Idle};
FirmwareStatus firmware_status{FirmwareStatus::Idle};
UploadLogStatusEnumType log_status{UploadLogStatusEnumType::Idle};
std::string message_log_path;
fs::path share_path;
bool boot_notification_callerror;
bool firmware_update_is_pending = false;
std::unique_ptr<Websocket> websocket;
std::unique_ptr<ocpp::MessageDispatcherInterface<MessageType>> message_dispatcher;
Everest::SteadyTimer websocket_timer;
std::unique_ptr<MessageQueue<v16::MessageType>> message_queue;
std::map<std::int32_t, std::shared_ptr<Connector>> connectors;
std::unique_ptr<SmartChargingHandler> smart_charging_handler;
std::int32_t heartbeat_interval;
bool stopped;
std::chrono::time_point<date::utc_clock> boot_time;
std::set<MessageType> allowed_message_types;
std::mutex allowed_message_types_mutex;
std::unique_ptr<ChargePointStates> status;
std::shared_ptr<ocpp::v16::DatabaseHandler> database_handler;
std::unique_ptr<Everest::SteadyTimer> boot_notification_timer;
std::unique_ptr<Everest::SteadyTimer> heartbeat_timer;
std::unique_ptr<ClockAlignedTimer> clock_aligned_meter_values_timer;
std::vector<std::unique_ptr<Everest::SteadyTimer>> status_notification_timers;
std::unique_ptr<Everest::SteadyTimer> ocsp_request_timer;
std::unique_ptr<Everest::SteadyTimer> client_certificate_timer;
std::unique_ptr<Everest::SteadyTimer> v2g_certificate_timer;
std::unique_ptr<Everest::SystemTimer> change_time_offset_timer;
std::chrono::time_point<date::utc_clock> clock_aligned_meter_values_time_point;
std::mutex meter_values_mutex;
std::mutex measurement_mutex;
std::map<std::int32_t, AvailabilityChange> change_availability_queue; // TODO: move to Connectors
std::mutex change_availability_mutex; // TODO: move to Connectors
std::unique_ptr<TransactionHandler> transaction_handler;
std::vector<v16::MessageType> external_notify;
std::map<std::string,
std::map<std::string, std::function<DataTransferResponse(const std::optional<std::string>& msg)>>>
data_transfer_callbacks;
std::function<DataTransferResponse(const DataTransferRequest& request)> data_transfer_callback;
std::map<std::string, std::function<void(Call<DataTransferRequest> call)>> data_transfer_pnc_callbacks;
std::mutex data_transfer_callbacks_mutex;
std::map<CiString<50>, std::function<void(const KeyValue& key_value)>> configuration_key_changed_callbacks;
std::function<void(const KeyValue& key_value)> generic_configuration_key_changed_callback;
std::mutex stop_transaction_mutex;
std::condition_variable stop_transaction_cv;
std::mutex user_price_map_mutex;
std::map<std::string, std::condition_variable> user_price_cvs;
std::map<std::string, TariffMessage> tariff_messages_by_id_token;
std::thread reset_thread;
int log_status_request_id;
FirmwareStatusEnumType signed_firmware_status;
int signed_firmware_status_request_id;
/// \brief optional delay to resumption of message queue after reconnecting to the CSMS
std::chrono::seconds message_queue_resume_delay = std::chrono::seconds(0);
// callbacks
std::function<bool(std::int32_t connector)> enable_evse_callback;
std::function<bool(std::int32_t connector)> disable_evse_callback;
std::function<bool(std::int32_t connector)> pause_charging_callback;
std::function<bool(std::int32_t connector)> resume_charging_callback;
std::function<void(const std::string& id_token, std::vector<std::int32_t> referenced_connectors, bool prevalidated)>
provide_token_callback;
std::function<bool(std::int32_t connector, Reason reason)> stop_transaction_callback;
std::function<UnlockStatus(std::int32_t connector)> unlock_connector_callback;
std::function<bool(std::int32_t connector, std::int32_t max_current)> set_max_current_callback;
std::function<bool(const ResetType& reset_type)> is_reset_allowed_callback;
std::function<void(const ResetType& reset_type)> reset_callback;
std::function<void(const std::string& system_time)> set_system_time_callback;
std::function<void(const BootNotificationResponse& boot_notification_response)> boot_notification_response_callback;
std::function<void()> signal_set_charging_profiles_callback;
std::function<void(bool is_connected)> connection_state_changed_callback;
std::function<GetLogResponse(const GetDiagnosticsRequest& request)> upload_diagnostics_callback;
std::function<void(const UpdateFirmwareRequest msg)> update_firmware_callback;
std::function<UpdateFirmwareStatusEnumType(const SignedUpdateFirmwareRequest msg)> signed_update_firmware_callback;
std::function<void(const std::string& type, const std::string& tech_info)> security_event_callback;
std::function<void()> all_connectors_unavailable_callback;
std::function<ReservationStatus(std::int32_t reservation_id, std::int32_t connector, ocpp::DateTime expiryDate,
CiString<20> idTag, std::optional<CiString<20>> parent_id)>
reserve_now_callback;
std::function<bool(std::int32_t reservation_id)> cancel_reservation_callback;
std::function<void()> switch_security_profile_callback;
std::function<GetLogResponse(GetLogRequest msg)> upload_logs_callback;
std::function<void(std::int32_t connection_timeout)> set_connection_timeout_callback;
std::function<void(const std::int32_t connector, const std::string& session_id)> transaction_started_callback;
std::function<void(const std::int32_t connector, const std::string& session_id, const std::int32_t transaction_id,
const IdTagInfo& id_tag_info)>
transaction_updated_callback;
std::function<void(const std::int32_t connector, const std::string& session_id, const std::int32_t transaction_id)>
transaction_stopped_callback;
std::function<ocpp::ReservationCheckStatus(const std::int32_t connector, const std::string& id_token)>
is_token_reserved_for_connector_callback;
// iso15118 callback
std::function<void(const std::int32_t connector,
const ocpp::v2::Get15118EVCertificateResponse& certificate_response,
const ocpp::v2::CertificateActionEnum& certificate_action)>
get_15118_ev_certificate_response_callback;
// tariff and cost callback
std::function<DataTransferResponse(const RunningCost& running_cost, const std::uint32_t number_of_decimals)>
session_cost_callback;
std::function<DataTransferResponse(const std::vector<DisplayMessage>& display_message)>
set_display_message_callback;
std::function<DataTransferResponse(const TariffMessage& message)> tariff_message_callback;
std::function<void(const TariffMessage& message)> default_price_callback;
/// \brief This function is called after a successful connection to the Websocket
void connected_callback();
void init_websocket();
void init_state_machine(const std::map<int, ChargePointStatus>& connector_status_map);
WebsocketConnectionOptions get_ws_connection_options();
std::unique_ptr<ocpp::MessageQueue<v16::MessageType>> create_message_queue();
void message_callback(const std::string& message);
void handle_message(const EnhancedMessage<v16::MessageType>& message);
void heartbeat(bool initiated_by_trigger_message = false);
void boot_notification(bool initiated_by_trigger_message = false);
void clock_aligned_meter_values_sample();
void update_heartbeat_interval();
void update_meter_values_sample_interval();
void update_clock_aligned_meter_values_interval();
std::optional<MeterValue> get_latest_meter_value(std::int32_t connector,
std::vector<MeasurandWithPhase> values_of_interest,
ReadingContext context);
void send_meter_value(std::int32_t connector, MeterValue meter_value, bool initiated_by_trigger_message = false);
void send_meter_value_on_pricing_trigger(const std::int32_t connector_number, std::shared_ptr<Connector> connector,
const Measurement& measurement);
void reset_pricing_triggers(const std::int32_t connector_number);
void status_notification(const std::int32_t connector, const ChargePointErrorCode errorCode,
const ChargePointStatus status, const ocpp::DateTime& timestamp,
const std::optional<CiString<50>>& info = std::nullopt,
const std::optional<CiString<255>>& vendor_id = std::nullopt,
const std::optional<CiString<50>>& vendor_error_code = std::nullopt,
bool initiated_by_trigger_message = false);
void diagnostic_status_notification(DiagnosticsStatus status, bool initiated_by_trigger_message = false);
void firmware_status_notification(FirmwareStatus status, bool initiated_by_trigger_message = false);
void log_status_notification(UploadLogStatusEnumType status, int requestId,
bool initiated_by_trigger_message = false);
void signed_firmware_update_status_notification(FirmwareStatusEnumType status, int requestId,
bool initiated_by_trigger_message = false);
/// \brief Changes all unoccupied connectors to unavailable. If a transaction is running schedule an availabilty
/// change. If all connectors are unavailable signal to the firmware updater that installation of the firmware
/// 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);
void stop_transaction(std::int32_t connector, Reason reason, std::optional<CiString<20>> id_tag_end);
/// \brief Returns transaction data that can be used to set the transactionData field in StopTransaction.req.
/// Filters the meter values of the transaction according to the values set within StopTxnAlignedData and
/// StopTxnSampledData
std::vector<TransactionData> get_filtered_transaction_data(const std::shared_ptr<Transaction>& transaction);
/// \brief Load charging profiles if present in database
void load_charging_profiles();
// security
/// \brief Creates a new public/private key pair and sends a certificate signing request to the central system for
/// the given \p certificate_signing_use
void sign_certificate(const ocpp::CertificateSigningUseEnum& certificate_signing_use,
bool initiated_by_trigger_message = false);
/// \brief Checks if OCSP cache needs to be updated and executes update if necessary by using
/// DataTransfer(GetCertificateStatus.req)
void update_ocsp_cache();
// core profile
void handleBootNotificationResponse(
CallResult<BootNotificationResponse> call_result); // TODO(kai):: async/promise based version?
void handleChangeAvailabilityRequest(Call<ChangeAvailabilityRequest> call);
void handleChangeConfigurationRequest(Call<ChangeConfigurationRequest> call);
void handleClearCacheRequest(Call<ClearCacheRequest> call);
void handleDataTransferRequest(Call<DataTransferRequest> call);
void handleGetConfigurationRequest(Call<GetConfigurationRequest> call);
void handleRemoteStartTransactionRequest(Call<RemoteStartTransactionRequest> call);
void handleRemoteStopTransactionRequest(Call<RemoteStopTransactionRequest> call);
void handleResetRequest(Call<ResetRequest> call);
void handleStartTransactionResponse(CallResult<StartTransactionResponse> call_result);
void handleStopTransactionResponse(const EnhancedMessage<v16::MessageType>& message);
void handleUnlockConnectorRequest(Call<UnlockConnectorRequest> call);
void handleHeartbeatResponse(CallResult<HeartbeatResponse> call_result);
// smart charging profile
void handleSetChargingProfileRequest(Call<SetChargingProfileRequest> call);
void handleGetCompositeScheduleRequest(Call<GetCompositeScheduleRequest> call);
void handleClearChargingProfileRequest(Call<ClearChargingProfileRequest> call);
// plug&charge for 1.6 whitepaper
bool is_iso15118_certificate_management_enabled();
bool is_pnc_enabled();
void data_transfer_pnc_sign_certificate();
void data_transfer_pnc_get_certificate_status(const ocpp::v2::OCSPRequestData& ocsp_request_data);
void handle_data_transfer_pnc_trigger_message(Call<DataTransferRequest> call);
void handle_data_transfer_pnc_certificate_signed(Call<DataTransferRequest> call);
void handle_data_transfer_pnc_get_installed_certificates(Call<DataTransferRequest> call);
void handle_data_transfer_delete_certificate(Call<DataTransferRequest> call);
void handle_data_transfer_install_certificate(Call<DataTransferRequest> call);
/// \brief ReserveNow.req(connectorId, expiryDate, idTag, reservationId, [parentIdTag]): tries to perform the
/// reservation and sends a reservation response. The reservation response: ReserveNow::Status
void handleReserveNowRequest(Call<ReserveNowRequest> call);
/// \brief Receives CancelReservation.req(reservationId)
/// The reservation response: CancelReservationStatus: `Accepted` if the reservationId was found, else
/// `Rejected`
void handleCancelReservationRequest(Call<CancelReservationRequest> call);
// RemoteTrigger profile
void handleTriggerMessageRequest(Call<TriggerMessageRequest> call);
// FirmwareManagement profile
void handleGetDiagnosticsRequest(Call<GetDiagnosticsRequest> call);
void handleUpdateFirmwareRequest(Call<UpdateFirmwareRequest> call);
// Security profile
void handleExtendedTriggerMessageRequest(Call<ExtendedTriggerMessageRequest> call);
void handleCertificateSignedRequest(Call<CertificateSignedRequest> call);
void handleGetInstalledCertificateIdsRequest(Call<GetInstalledCertificateIdsRequest> call);
void handleDeleteCertificateRequest(Call<DeleteCertificateRequest> call);
void handleInstallCertificateRequest(Call<InstallCertificateRequest> call);
void handleGetLogRequest(Call<GetLogRequest> call);
void handleSignedUpdateFirmware(Call<SignedUpdateFirmwareRequest> call);
void securityEventNotification(const CiString<50>& event_type, const std::optional<CiString<255>>& tech_info,
const bool triggered_internally, const std::optional<bool>& critical = std::nullopt,
const std::optional<DateTime>& timestamp = std::nullopt);
void switchSecurityProfile(std::int32_t new_security_profile, std::int32_t max_connection_attempts);
// Local Authorization List profile
void handleSendLocalListRequest(Call<SendLocalListRequest> call);
void handleGetLocalListVersionRequest(Call<GetLocalListVersionRequest> call);
// California Pricing
DataTransferResponse handle_set_user_price(const std::optional<std::string>& msg);
DataTransferResponse handle_set_session_cost(const RunningCostState& type,
const std::optional<std::string>& message);
///
/// \brief Set timer to trigger sending a metervalue at a specific time.
/// \param date_time The date/time to send the metervalue.
/// \param connector The connector to set the timer for.
///
void set_connector_trigger_metervalue_timer(const DateTime& date_time, std::shared_ptr<Connector> connector);
///
/// \brief Set offset timer to change the 'timezone' (time offset) at the given time.
/// \param date_time The date / time to change the time offset.
///
void set_time_offset_timer(const std::string& date_time);
/// \brief Preprocess a ChangeAvailabilityRequest: Determine response;
/// - if connector is 0, availability change is also propagated for all connectors
/// - for each connector (except "0"), if transaction is ongoing the change is scheduled,
/// otherwise the OCPP connector id is appended to the `accepted_connector_availability_changes` vector
void preprocess_change_availability_request(const ChangeAvailabilityRequest& request,
ChangeAvailabilityResponse& response,
std::vector<std::int32_t>& accepted_connector_availability_changes);
/// \brief Executes availability change for the provided connectors:
/// - if persist == true: store availability in database
/// - submit state event (for the whole ChargePoint if "0" in set of connectors; otherwise for each connector
/// individually)
/// - call according EVSE enable or disable callback, respectively
/// \param changed_connectors list of OCPP connector ids (and 0 for whole chargepoint)
/// \param availability new availabillity
/// \param persist if true, persists availability in database
void execute_connectors_availability_change(const std::vector<std::int32_t>& changed_connectors,
const ocpp::v16::AvailabilityType availability, bool persist);
/// \brief Checks scheduled availability queue and exeuctues availability change if required
/// \param connector for which availability change shall be checked and executed
void execute_queued_availability_change(const std::int32_t connector);
/// \brief Sets a configuration key (internal implementation)
/// \param key
/// \param value
/// \param uniqueId used when an OCPP response is sent
/// \return Indicates the result of the operation with an optional response message
/// \note the optional response message will be nullopt when a response has
/// been sent by this method
std::pair<ConfigurationStatus, std::optional<ChangeConfigurationResponse>>
set_configuration_key_internal(CiString<50> key, CiString<500> value, std::optional<MessageId> uniqueId);
public:
/// \brief The main entrypoint for libOCPP for OCPP 1.6
/// \param cfg a reference to the configuration provider
/// \param database_path this points to the location of the sqlite database that libocpp uses to keep track of
/// \param share_path This path contains the following files and directories and is installed by the libocpp install
/// target
/// connector availability, the authorization cache and auth list, charging profiles and transaction
/// data \param sql_init_path this points to the init.sql file which contains the database schema used by libocpp
/// for its sqlite database \param message_log_path this points to the directory in which libocpp can put OCPP
/// communication logfiles for debugging purposes. This behavior can be controlled by the "LogMessages" (set to true
/// by default) and "LogMessagesFormat" (set to ["log", "html", "session_logging"] by default, "console" and
/// "console_detailed" are also available) configuration keys in the "Internal" section of the config file. Please
/// note that this is intended for debugging purposes only as it logs all communication, including authentication
/// messages. \param evse_security Pointer to evse_security that manages security related operations
/// \param message_callback A callback that will get all OCPP messages sent or received to/from the CSMS
explicit ChargePointImpl(
ChargePointConfigurationInterface& cfg, const fs::path& share_path, const fs::path& database_path,
const fs::path& sql_init_path, const fs::path& message_log_path,
const std::shared_ptr<EvseSecurity>& evse_security,
const std::optional<SecurityConfiguration>& security_configuration,
const std::function<void(const std::string& message, MessageDirection direction)>& message_callback);
virtual ~ChargePointImpl() override = default;
/// \brief Allow to update the ChargePoint core information which will be sent in BootNotification.req
void update_chargepoint_information(const std::string& vendor, const std::string& model,
const std::optional<std::string>& serialnumber,
const std::optional<std::string>& chargebox_serialnumber,
const std::optional<std::string>& firmware_version);
/// \brief Allow to update the ChargePoint modem information
void update_modem_information(const std::optional<std::string>& iccid, const std::optional<std::string>& imsi);
/// \brief Allow to update the ChargePoint meter information
void update_meter_information(const std::optional<std::string>& meter_serialnumber,
const std::optional<std::string>& meter_type);
/// \brief Initializes the ChargePoint and all of it's connectors, the state machine and message queue. This method
/// should be called if a more granular start of the process is necessary. Notably if it is necessary for the state
/// machine and the connectors (and their statuses) need to be updated prior to initiating connection with the CSMS.
/// \param connector_status_map initial state of connectors including connector 0 with reduced set of states
/// (Available, Unavailable, Faulted)
/// \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 init(const std::map<int, ChargePointStatus>& connector_status_map,
const std::set<std::string>& resuming_session_ids);
/// \brief Starts the ChargePoint, initializes (if and only if init was not called previously) and connects to the
/// Websocket endpoint and initializes a BootNotification.req
/// \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
/// \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
/// \param connector_status_map initial state of connectors including connector 0 with reduced set of states
/// (Available, Unavailable, Faulted). connector_status_map is empty, last availability states from the persistant
/// storage will be used
/// \param bootreason reason for calling the restart function
bool restart(const std::map<int, ChargePointStatus>& connector_status_map, BootReasonEnum bootreason);
/// \brief Resets the internal state machine for the connectors using the given \p connector_status_map
/// \param connector_status_map state of connectors including connector 0 with reduced set of states (Available,
/// Unavailable, Faulted)
void reset_state_machine(const std::map<int, ChargePointStatus>& connector_status_map);
/// \brief Stops the ChargePoint, stops timers, transactions and the message queue and disconnects from the
/// websocket
bool stop();
/// \brief Initializes the websocket and connects to CSMS if it is not yet connected
void connect_websocket();
/// \brief Disconnects the the websocket connection to the CSMS if it is connected
void disconnect_websocket();
/// \brief Calls the set_connection_timeout_callback that can be registered. This function is used to notify an
/// Authorization mechanism about a changed ConnectionTimeout configuration key.
void call_set_connection_timeout();
// public API for Core profile
/// \brief Authorizes the provided \p id_token against the central system, LocalAuthorizationList or
/// AuthorizationCache depending on the values of the ConfigurationKeys LocalPreAuthorize, LocalAuthorizeOffline,
/// LocalAuthListEnabled and AuthorizationCacheEnabled. If \p authorize_only_locally is true, no Authorize.req will
/// be sent to the CSMS but only LocalAuthorizationList and LocalAuthorizationCache will be used for the validation
/// \returns the EnhancedIdTagInfo that contains the result of the authorization and an optional tarriff message
EnhancedIdTagInfo authorize_id_token(CiString<20> id_token, const bool authorize_only_locally = false);
// for plug&charge 1.6 whitepaper
/// \brief Uses data_transfer mechanism to authorize given \p emaid , \p certificate and
/// \p iso15118_certificate_hash_data locally or by requesting authorzation at CSMS. This function can be called
/// when the authorization mechanism Plug&Charge is specified as part of the ISO15118 PaymentDetailsRequest
/// \param emaid
/// \param certificate contract certificate that the EVCC provides
/// \param iso15118_certificate_hash_data
/// \return
ocpp::v2::AuthorizeResponse data_transfer_pnc_authorize(
const std::string& emaid, const std::optional<std::string>& certificate,
const std::optional<std::vector<ocpp::v2::OCSPRequestData>>& iso15118_certificate_hash_data);
/// \brief Uses data transfer mechanism to get 15118 ev certificate from CSMS. This function can be called when the
/// EVCC requests the update or installation of a contract certificate as part of the ISO15118
/// CertificateInstallRequest or CertificateUpdateRequest
/// \param connector_id
/// \param exi_request provided by the EVCC
/// \param iso15118_schema_version provided by the EVCC
/// \param certificate_action Install or Update
void data_transfer_pnc_get_15118_ev_certificate(const std::int32_t connector_id, const std::string& exi_request,
const std::string& iso15118_schema_version,
const ocpp::v2::CertificateActionEnum& certificate_action);
/// \brief Allows the exchange of arbitrary \p data identified by a \p vendorId and \p messageId with a central
/// system \returns the DataTransferResponse
/// \param vendorId
/// \param messageId
/// \param data
/// \return the DataTransferResponse from the CSMS. In case no response is received from the CSMS because the
/// message timed out or the charging station is offline, std::nullopt is returned
std::optional<DataTransferResponse> data_transfer(const CiString<255>& vendorId,
const std::optional<CiString<50>>& messageId,
const std::optional<std::string>& data);
/// \brief Calculates ChargingProfiles configured by the CSMS of all connectors from now until now + given \p
/// duration_s and the given \p unit
/// \param duration_s
/// \param unit defaults to A
/// \return ChargingSchedules of all connectors
std::map<std::int32_t, ChargingSchedule>
get_all_composite_charging_schedules(const std::int32_t duration_s,
const ChargingRateUnit unit = ChargingRateUnit::A);
/// \brief Calculates EnhancedChargingSchedule(s) configured by the CSMS of all connectors from now until now +
/// given \p duration_s and the given \p unit . EnhancedChargingSchedules contain EnhancedChargingSchedulePeriod(s)
/// that are enhanced by the stackLevel that was provided for the ChargingProfile
/// \param duration_s
/// \param unit
/// defaults to A \return ChargingSchedules of all connectors
std::map<std::int32_t, EnhancedChargingSchedule>
get_all_enhanced_composite_charging_schedules(const std::int32_t duration_s,
const ChargingRateUnit unit = ChargingRateUnit::A);
/// \brief Stores the given \p powermeter values for the given \p connector . This function can be called when a new
/// meter value is present.
/// \param connector
/// \param measurement structure that can contain all kinds of measurands
void on_meter_values(std::int32_t connector, const Measurement& measurement);
/// \brief Stores the given \p max_current for the given \p connector offered to the EV. This function can be called
/// when the value for the maximum current for the connector changes. It will be used to report the Measurand
/// Current_Offered if it is configured
/// \param connector
/// \param max_current in Amps
void on_max_current_offered(std::int32_t connector, std::int32_t max_current);
/// \brief Stores the given \p max_power for the given \p connector offered to the EV. This function can be called
/// when the value for the maximum power for the connector changes. It will be used to report the Measurand
/// Power_Offered if it is configured
/// \param connector
/// \param max_power in Watts
void on_max_power_offered(std::int32_t connector, std::int32_t max_power);
/// \brief Notifies chargepoint that a new session with the given \p session_id has been started at the given \p
/// connector with the given \p reason . The logs of the session will be written into \p session_logging_path if
/// present. This function must be called when first interaction with user or EV occurs. This can be a valid
/// authorization or the connection of cable and/or EV to the given \p connector
/// \param connector
/// \param session_id unique id of the session
/// \param reason for the initiation of the session
/// \param session_logging_path optional filesystem path to where the session log should be written
void on_session_started(std::int32_t connector, const std::string& session_id, const SessionStartedReason reason,
const std::optional<std::string>& session_logging_path);
/// \brief Notifies chargepoint that a session has been stopped at the given \p connector. This function must be
/// called when the EV disconnects from the given \p connector .
/// \param connector
/// \param session_id
void on_session_stopped(std::int32_t connector, const std::string& session_id);
/// \brief Notifies chargepoint that a transaction at the given \p connector with the given parameters has been
/// started. This function must be called at the point that all conditions for charging are met, for instance, EV is
/// connected to Charge Point and user has been authorized.
/// \param connector
/// \param session_id
/// \param id_token that has been used to authorize the transaction
/// \param meter_start start meter value in Wh
/// \param reservation_id
/// \param timestamp of the start of transaction
/// \param signed_meter_value e.g. in OCMF format
void on_transaction_started(const std::int32_t& connector, const std::string& session_id,
const std::string& id_token, const double meter_start,
std::optional<std::int32_t> reservation_id, const ocpp::DateTime& timestamp,
std::optional<std::string> signed_meter_value);
/// \brief Notifies chargepoint that the transaction on the given \p connector with the given \p reason has been
/// stopped. This function must be called at the point where one of the preconditions for charging irrevocably
/// becomes false, for instance when a user swipes to stop the transaction and the stop is authorized or if the EV
/// disconnects.
/// \param connector
/// \param session_id
/// \param reason
/// \param timestamp of the end of transaction
/// \param energy_wh_import stop meter value in Wh
/// \param id_tag_end
/// \param signed_meter_value e.g. in OCMF format
void on_transaction_stopped(const std::int32_t connector, const std::string& session_id, const Reason& reason,
ocpp::DateTime timestamp, float energy_wh_import,
std::optional<CiString<20>> id_tag_end, std::optional<std::string> signed_meter_value);
/// \brief This function should be called when EV indicates that it suspends charging on the given \p connector
/// \param connector
/// \param info
void on_suspend_charging_ev(std::int32_t connector, const std::optional<CiString<50>> info = std::nullopt);
/// \brief This function should be called when EVSE indicates that it suspends charging on the given \p connector
/// \param connector
/// \param info
void on_suspend_charging_evse(std::int32_t connector, const std::optional<CiString<50>> info = std::nullopt);
/// \brief This function should be called when charging resumes on the given \p connector
/// \param connector
void on_resume_charging(std::int32_t connector);
/// \brief This function should be called if an error with the given \p error_info is present. This function will
/// trigger a StatusNotification.req containing the given \p error_info . It will change the present state of
/// the state machine to faulted, in case the corresponding flag is set in the given \p error_info. This function
/// can be called multiple times for different errors. Errors reported using this function stay active as long as
/// they are cleared by \ref on_error_cleared().
/// \param connector
/// \param error_info Additional information related to the error
void on_error(std::int32_t connector, const ErrorInfo& error_info);
/// \brief This function should be called if an error with the given \p uuid has been cleared. If this leads to the
/// fact that no other error is active anymore, this function will initiate a StatusNotification.req that reports
/// the current state and no error
/// \param connector
/// \param uuid of a previously reported error. If uuid is not
/// known, the event will be ignored
void on_error_cleared(std::int32_t connector, const std::string uuid);
/// \brief Clears all previously reported errors at the same time for the given \p connector . This will
/// clear a previously reported "Faulted" state if present
/// \param connector
void on_all_errors_cleared(std::int32_t connector);
/// \brief Chargepoint notifies about new log status \p log_status . This function should be called during a
/// Diagnostics / Log upload to indicate the current \p log_status .
/// \param request_id A \p request_id of -1 indicates a DiagnosticsStatusNotification.req, else a
/// LogStatusNotification.req.
/// \param log_status The \p log_status should be either be convertable to the
/// ocpp::v16::UploadLogStatusEnumType enum or ocpp::v16::DiagnosticsStatus enum depending on the previous request,
/// which could have been a DiagnosticsUpload.req or a GetLog.req (Security Whitepaper)
void on_log_status_notification(std::int32_t request_id, std::string log_status);
/// \brief Chargepoint notifies about new firmware update status \p firmware_update_status . This function should be
/// called during a Firmware Update to indicate the current \p firmware_update_status .
/// \param request_id A \p request_id of -1 indicates a FirmwareStatusNotification.req, else a
/// SignedFirmwareUpdateStatusNotification.req .
/// \param firmware_update_status The \p firmware_update_status
void on_firmware_update_status_notification(std::int32_t request_id,
const ocpp::FirmwareStatusNotification firmware_update_status);
/// \brief This function must be called when a reservation is started at the given \p connector .
/// \param connector
void on_reservation_start(std::int32_t connector);
/// \brief This function must be called when a reservation ends at the given \p connector
/// \param connector
void on_reservation_end(std::int32_t connector);
/// \brief Notifies chargepoint that the \p connector is enabled . This function should be called when the \p
/// connector becomes functional and operational
/// \param connector
void on_enabled(std::int32_t connector);
/// \brief Notifies chargepoint that the \p connector is disabled . This function should be called when the \p
/// connector becomes inoperative
/// \param connector
void on_disabled(std::int32_t connector);
/// \brief Notifies chargepoint that a ConnectionTimeout occured for the given \p connector . This function should
/// be called when an EV is plugged in but the authorization is not present within the specified ConnectionTimeout
void on_plugin_timeout(std::int32_t connector);
/// \brief Notifies chargepoint that a SecurityEvent occurs. This will send a SecurityEventNotification.req to the
/// CSMS
/// \param event_type type of the security event
/// \param tech_info additional info of the security event
/// \param critical if set this overwrites the default criticality recommended in the OCPP 1.6 security whitepaper.
/// A critical security event is transmitted as a message to the CSMS, a non-critical one is just written to the
/// security log
/// \param timestamp when this security event occured, if absent the current datetime is assumed
void on_security_event(const CiString<50>& event_type, const std::optional<CiString<255>>& tech_info,
const std::optional<bool>& critical = std::nullopt,
const std::optional<DateTime>& timestamp = std::nullopt);
/// \brief Handles an internal ChangeAvailabilityRequest (in the same way as if it was emitted by the CSMS).
/// \param request
ChangeAvailabilityResponse on_change_availability(const ChangeAvailabilityRequest& request);
/// registers a \p callback function that can be used to receive a arbitrary data transfer for the given \p
/// vendorId and \p messageId
/// \param vendorId
/// \param messageId
/// \param callback
void register_data_transfer_callback(
const CiString<255>& vendorId, const CiString<50>& messageId,
const std::function<DataTransferResponse(const std::optional<std::string>& msg)>& callback);
/// registers a \p callback function that can be used to handle arbitrary data transfers for all vendorId an
/// messageId
/// \param callback
void register_data_transfer_callback(
const std::function<DataTransferResponse(const DataTransferRequest& request)>& callback);
/// \brief registers a \p callback function that can be used to enable the evse. The enable_evse_callback is called
/// when a ChangeAvailaibility.req is received.
/// \param callback
void register_enable_evse_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to disable the evse. The disable_evse_callback is
/// called when a ChangeAvailaibility.req is received.
/// \param callback
void register_disable_evse_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to pause charging. The pause_charging_callback is
/// called when the idTagInfo.status of a StartTransaction.conf is not Accepted
/// \param callback
void register_pause_charging_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to resume charging
/// \param callback
void register_resume_charging_callback(const std::function<bool(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to provide an \p id_token for the given \p
/// referenced_connectors to an authorization handler. \p prevalidated signals to the authorization handler that no
/// further authorization is necessary. The provide_token_callback is called when a RemoteStartTransaction.req is
/// received.
/// \param callback
void register_provide_token_callback(
const std::function<void(const std::string& id_token, std::vector<std::int32_t> referenced_connectors,
bool prevalidated)>& callback);
/// \brief registers a \p callback function that can be used to stop a transaction. Ths stop_transaction_callback is
/// called
/// - when the idTagInfo.status of a StartTransaction.conf is not Accepted
/// - when a RemoteStopTransaction.req is received
/// - when a UnlockConnector.req is received
/// \param callback
void register_stop_transaction_callback(const std::function<bool(std::int32_t connector, Reason reason)>& callback);
/// \brief registers a \p callback function that can be used to reserve a connector for a idTag until a timeout
/// is reached. The reserve_now_callback is called when a ReserveNow.req is received.
/// \param callback
void register_reserve_now_callback(
const std::function<ReservationStatus(std::int32_t reservation_id, std::int32_t connector,
ocpp::DateTime expiryDate, CiString<20> idTag,
std::optional<CiString<20>> parent_id)>& callback);
/// \brief registers a \p callback function that can be used to cancel a reservation on a connector. Callback
/// function should return false if the reservation could not be cancelled, else true . The
/// cancel_reservation_callback is called when a CancelReservation.req is received
/// \param callback
void register_cancel_reservation_callback(const std::function<bool(std::int32_t reservation_id)>& callback);
/// \brief registers a \p callback function that can be used to unlock the connector. In case a transaction is
// active at the specified connector, the \p callback shall stop the transaction before unlocking the connector. The
// unlock_connector_callback is called:
/// - when receiving a UnlockConnector.req and
/// - when a transaction has on_transaction_stopped is called and the configuration key
/// UnlockConnectorOnEVSideDisconnect is true
/// \param callback
void register_unlock_connector_callback(const std::function<UnlockStatus(std::int32_t connector)>& callback);
/// \brief registers a \p callback function that can be used to trigger an upload of diagnostics. This callback
/// should trigger a process of a diagnostics upload using the given parameters of the request. This process should
/// call the on_log_status_notification handler in order to update the status of the file upload. The
/// upload_diagnostics_callback is called when a GetDiagnostics.req is received
/// \param callback
void register_upload_diagnostics_callback(
const std::function<GetLogResponse(const GetDiagnosticsRequest& request)>& callback);
/// \brief registers a \p callback function that can be used to trigger a firmware update. This callback
/// should trigger a process of a firmware update using the given parameters of the request. This process should
/// call the on_firmware_update_status_notification handler in order to update the status of the update. The
/// update_firmware_callback is called when a FirmwareUpdate.req is received
/// \param callback
void register_update_firmware_callback(const std::function<void(const UpdateFirmwareRequest msg)>& callback);
/// \brief registers a \p callback function that can be used to trigger a signed firmware update. This callback
/// should trigger a process of a signed firmware update using the given parameters of the request. This process
/// should call the on_firmware_update_status_notification handler in order to update the status of the signed
/// firmware update. The signed_update_firmware_callback is called when a SignedUpdateFirmware.req is received.
/// \param callback
void register_signed_update_firmware_callback(
const std::function<UpdateFirmwareStatusEnumType(const SignedUpdateFirmwareRequest msg)>& callback);
/// \brief registers a \p callback function that is called when all connectors are set to unavailable.
/// This can be used to then trigger the installation of the firmware update
void register_all_connectors_unavailable_callback(const std::function<void()>& callback);
/// \brief registers a \p callback function that can be used to upload logfiles. This callback
/// should trigger a process of a log upload using the given parameters of the request. This process should
/// call the on_log_status_notification handler in order to update the status of the file upload. The
/// upload_logs_callback is called when a GetLog.req is received
/// \param callback
void register_upload_logs_callback(const std::function<GetLogResponse(GetLogRequest req)>& callback);
/// \brief registers a \p callback function that can be used to set the authorization or plug in connection timeout.
/// The set_connection_timeout_callback is called when the configuration key ConnectionTimeout has been changed by
/// the CSMS.
/// \param callback
void register_set_connection_timeout_callback(const std::function<void(std::int32_t connection_timeout)>& callback);
/// \brief registers a \p callback function that can be used to check if a reset is allowed . The
/// is_reset_allowed_callback is called when a Reset.req is received.
/// \param callback
void register_is_reset_allowed_callback(const std::function<bool(const ResetType& reset_type)>& callback);
/// \brief registers a \p callback function that can be used to trigger a reset of the chargepoint. The
/// reset_callback is called when a Reset.req is received and a previous execution of the is_reset_allowed_callback
/// returned true
/// \param callback
void register_reset_callback(const std::function<void(const ResetType& reset_type)>& callback);
/// \brief registers a \p callback function that can be used to set the system time.
/// \param callback
void register_set_system_time_callback(const std::function<void(const std::string& system_time)>& callback);
/// \brief registers a \p callback function that can be used receive the BootNotificationResponse
/// \param callback
void register_boot_notification_response_callback(
const std::function<void(const BootNotificationResponse& boot_notification_response)>& callback);
/// \brief registers a \p callback function that can be used to signal that the chargepoint received a
/// SetChargingProfile.req . The set_charging_profiles_callback is called when a SetChargingProfile.req is received
/// and was accepted. The registered callback could make use of the get_all_composite_charging_schedules in order to
/// retrieve the ChargingProfiles that have been set by the CSMS.
/// \param callback
void register_signal_set_charging_profiles_callback(const std::function<void()>& callback);
/// \brief registers a \p callback function that can be used when the connection state to CSMS changes. The
/// connection_state_changed_callback is called when chargepoint has connected to or disconnected from the CSMS.
/// \param callback
void register_connection_state_changed_callback(const std::function<void(bool is_connected)>& callback);
/// \brief registers a \p callback function that can be used to publish the response to a Get15118Certificate.req
/// wrapped in a DataTransfer.req . The get_15118_ev_certificate_response_callback is called after the response to a
/// DataTransfer.req(Get15118EVCertificate) has been accepted.
/// \param callback
void register_get_15118_ev_certificate_response_callback(
const std::function<void(const std::int32_t connector,
const ocpp::v2::Get15118EVCertificateResponse& certificate_response,
const ocpp::v2::CertificateActionEnum& certificate_action)>& callback);
/// \brief registers a \p callback function that is called when a StartTransaction.req message is sent by the
/// chargepoint
/// \param callback
void register_transaction_started_callback(
const std::function<void(const std::int32_t connector, const std::string& session_id)>& callback);
/// \brief registers a \p callback function that is called when a StopTransaction.req message is sent by the
/// chargepoint
/// \param callback
void register_transaction_stopped_callback(
const std::function<void(const std::int32_t connector, const std::string& session_id,
const std::int32_t transaction_id)>& callback);
/// \brief registers a \p callback function that is called when a StartTransaction.conf message is received by the
/// CSMS. This includes the transactionId.
/// \param callback
void register_transaction_updated_callback(
const std::function<void(const std::int32_t connector, const std::string& session_id,
const std::int32_t transaction_id, const IdTagInfo& id_tag_info)>
callback);
/// \brief registers a \p callback function that can be used to react on changed configuration keys. This
/// callback is called when a configuration key has been changed by the CSMS
/// \param key the configuration key for which the callback is registered
/// \param callback executed when this configuration key changed
void register_configuration_key_changed_callback(const CiString<50>& key,
const std::function<void(const KeyValue& key_value)>& callback);
/// \brief registers a \p callback function that can be used to react on changed configuration key. This
/// callback is called when a configuration key and value has been changed by the CSMS, where no key based callback
/// is assigned
/// \param callback executed when this configuration key changed
void
register_generic_configuration_key_changed_callback(const std::function<void(const KeyValue& key_value)>& callback);
/// \brief registers a \p callback function that can be used to react to a security event callback. This callback is
/// called only if the SecurityEvent occured internally within libocpp
void register_security_event_callback(
const std::function<void(const std::string& type, const std::string& tech_info)>& callback);
/// \brief registers a \p callback function that can be used to check, if the \p connector is reserved for the given
/// \p id_token. The is_token_reserved_for_connector_callback is called when a RemoteStartTransaction.req is
/// received.
/// \param callback
void register_is_token_reserved_for_connector_callback(
const std::function<ReservationCheckStatus(const std::int32_t connector, const std::string& id_token)>&
callback);
void register_session_cost_callback(
const std::function<DataTransferResponse(const RunningCost& running_cost,
const std::uint32_t number_of_decimals)>& session_cost_callback);
void register_tariff_message_callback(
const std::function<DataTransferResponse(const TariffMessage& message)>& tariff_message_callback);
void register_default_price_callback(const std::function<void(const TariffMessage& message)>& callback);
void publish_default_price(bool is_offline);
void register_set_display_message_callback(
const std::function<DataTransferResponse(const std::vector<DisplayMessage>&)> set_display_message_callback);
/// \brief Gets the configured configuration key requested in the given \p request
/// \param request specifies the keys that should be returned. If empty or not set, all keys will be reported
/// \return a response containing the requested key(s) including the values and unkown keys if present
GetConfigurationResponse get_configuration_key(const GetConfigurationRequest& request);
/// \brief Sets a configuration key
/// \param key
/// \param value
/// \return Indicates the result of the operation
ConfigurationStatus set_configuration_key(CiString<50> key, CiString<500> value);
/// \brief Delay draining the message queue after reconnecting, so the CSMS can perform post-reconnect checks first
/// \param delay The delay period (seconds)
void set_message_queue_resume_delay(std::chrono::seconds delay) {
this->message_queue_resume_delay = delay;
}
/// \brief Sets the public key of the powermeter for the given connector
/// \param connector The connector for which the public key is set
/// \param public_key_pem The public key in PEM format
/// \return true if the public key was set successfully, false otherwise
bool set_powermeter_public_key(const int32_t connector, const std::string& public_key_pem);
};
} // namespace v16
} // namespace ocpp
#endif

View File

@@ -0,0 +1,125 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CHARGE_POINT_STATE_MACHINE_HPP
#define OCPP_V16_CHARGE_POINT_STATE_MACHINE_HPP
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
namespace ocpp {
namespace v16 {
enum class FSMEvent {
BecomeAvailable,
UsageInitiated,
StartCharging,
PauseChargingEV,
PauseChargingEVSE,
ReserveConnector,
TransactionStoppedAndUserActionRequired,
ChangeAvailabilityToUnavailable,
ReservationEnd,
// FaultDetected - note: this event is handled via a separate function
I1_ReturnToAvailable,
I2_ReturnToPreparing,
I3_ReturnToCharging,
I4_ReturnToSuspendedEV,
I5_ReturnToSuspendedEVSE,
I6_ReturnToFinishing,
I7_ReturnToReserved,
I8_ReturnToUnavailable,
};
/// \brief Contains all relevant information to handle errros in OCPP1.6
struct ErrorInfo {
std::string uuid; // uuid
ChargePointErrorCode error_code; /// defined by OCPP1.6
bool is_fault; /// indicates if state should change to "Faulted", if not set, state will not change and error is
/// only informational
std::optional<CiString<50>> info; /// defined by OCPP1.6
std::optional<CiString<255>> vendor_id; /// defined by OCPP1.6
std::optional<CiString<50>> vendor_error_code; /// defined by OCPP1.6
DateTime timestamp; // timestamp
ErrorInfo(const std::string uuid, const ChargePointErrorCode error_code, const bool is_fault);
ErrorInfo(const std::string uuid, const ChargePointErrorCode error_code, const bool is_fault,
const std::optional<std::string> info);
ErrorInfo(const std::string uuid, const ChargePointErrorCode error_code, const bool is_fault,
const std::optional<std::string> info, const std::optional<std::string> vendor_id);
ErrorInfo(const std::string uuid, const ChargePointErrorCode error_code, const bool is_fault,
const std::optional<std::string> info, const std::optional<std::string> vendor_id,
const std::optional<std::string> vendor_error_code);
};
using FSMState = ChargePointStatus;
using FSMStateTransitions = std::map<FSMEvent, FSMState>;
using FSMDefinition = std::map<FSMState, FSMStateTransitions>;
class ChargePointFSM {
public:
using StatusNotificationCallback = std::function<void(
const ChargePointStatus status, const ChargePointErrorCode error_code, const ocpp::DateTime& timestamp,
const std::optional<CiString<50>>& info, const std::optional<CiString<255>>& vendor_id,
const std::optional<CiString<50>>& vendor_error_code)>;
explicit ChargePointFSM(const StatusNotificationCallback& status_notification_callback, FSMState initial_state);
bool handle_event(FSMEvent event, const ocpp::DateTime timestamp, const std::optional<CiString<50>>& info);
bool handle_error(const ErrorInfo& error_info);
bool handle_error_cleared(const std::string uuid);
bool handle_all_errors_cleared();
void trigger_status_notification();
FSMState get_state();
std::optional<ErrorInfo> get_latest_error();
private:
StatusNotificationCallback status_notification_callback;
// track current state
FSMState state;
std::unordered_map<std::string, ErrorInfo> active_errors;
bool is_faulted();
};
class ChargePointStates {
public:
using ConnectorStatusCallback = std::function<void(
const int connector_id, const ChargePointErrorCode errorCode, const ChargePointStatus status,
const ocpp::DateTime& timestamp, const std::optional<CiString<50>>& info,
const std::optional<CiString<255>>& vendor_id, const std::optional<CiString<50>>& vendor_error_code)>;
ChargePointStates(const ConnectorStatusCallback& connector_status_callback);
void reset(std::map<int, ChargePointStatus> connector_status_map);
void submit_event(const int connector_id, FSMEvent event, const ocpp::DateTime& timestamp,
const std::optional<CiString<50>>& info = std::nullopt);
void submit_error(const int connector_id, const ErrorInfo& error_info);
void submit_error_cleared(const int connector_id, const std::string uuid);
void submit_all_errors_cleared(const std::int32_t connector_id);
void trigger_status_notification(const int connector_id);
void trigger_status_notifications();
ChargePointStatus get_state(int connector_id);
std::optional<ErrorInfo> get_latest_error(int connector_id);
private:
ConnectorStatusCallback connector_status_callback;
std::unique_ptr<ChargePointFSM> state_machine_connector_zero;
std::vector<ChargePointFSM> state_machines;
std::mutex state_machines_mutex;
};
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CHARGE_POINT_STATE_MACHINE_HPP

View File

@@ -0,0 +1,39 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_CONNECTOR_HPP
#define OCPP_V16_CONNECTOR_HPP
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/transaction.hpp>
#include <ocpp/v16/types.hpp>
namespace ocpp {
namespace v16 {
struct Connector {
std::int32_t id;
std::optional<Measurement> measurement;
double max_current_offered = 0;
double max_power_offered = 0;
std::shared_ptr<Transaction> transaction = nullptr;
std::map<int, ChargingProfile> stack_level_tx_default_profiles_map;
std::map<int, ChargingProfile> stack_level_tx_profiles_map;
std::optional<std::vector<ChargePointStatus>> trigger_metervalue_on_status;
std::optional<double> trigger_metervalue_on_power_kw;
std::optional<double> trigger_metervalue_on_energy_kwh;
std::unique_ptr<Everest::SystemTimer> trigger_metervalue_at_time_timer;
std::optional<ChargePointStatus> previous_status;
std::optional<double> last_triggered_metervalue_power_kw;
explicit Connector(const int id) : id(id) {
}
~Connector() = default;
Connector& operator=(const Connector&) = delete;
Connector(const Connector&) = delete;
};
} // namespace v16
} // namespace ocpp
#endif

View File

@@ -0,0 +1,173 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_DATABASE_HANDLER_HPP
#define OCPP_V16_DATABASE_HANDLER_HPP
#include "sqlite3.h"
#include <fstream>
#include <iostream>
#include <ocpp/common/database/database_handler_common.hpp>
#include <ocpp/common/schemas.hpp>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Struct that contains all attributes of a transaction entry in the database
struct TransactionEntry {
std::string session_id;
std::int32_t connector;
std::string id_tag_start;
std::string time_start;
std::int32_t meter_start;
std::int32_t transaction_id;
bool csms_ack;
std::int32_t meter_last;
std::string meter_last_time;
std::string last_update;
std::string start_transaction_message_id;
std::optional<std::string> stop_transaction_message_id;
std::optional<std::int32_t> reservation_id = std::nullopt;
std::optional<std::string> parent_id_tag = std::nullopt;
std::optional<std::int32_t> meter_stop = std::nullopt;
std::optional<std::string> time_end = std::nullopt;
std::optional<std::string> id_tag_end = std::nullopt;
std::optional<std::string> stop_reason = std::nullopt;
};
/// \brief This class handles the connection and operations of the SQLite database
class DatabaseHandler : public ocpp::common::DatabaseHandlerCommon {
private:
const std::int32_t number_of_connectors;
// Runs initialization script and initializes the CONNECTORS and AUTH_LIST_VERSION table.
void init_sql() override;
void init_connector_table();
public:
DatabaseHandler(std::unique_ptr<everest::db::sqlite::ConnectionInterface> database,
const fs::path& sql_migration_files_path, std::int32_t number_of_connectors);
// transactions
/// \brief Inserts a transaction with the given parameter to the TRANSACTIONS table.
void insert_transaction(const std::string& session_id, const std::int32_t transaction_id,
const std::int32_t connector, const std::string& id_tag_start,
const std::string& time_start, const std::int32_t meter_start, const bool csms_ack,
const std::optional<std::int32_t> reservation_id,
const std::string& start_transaction_message_id);
/// \brief Updates the given parameters for the transaction with the given \p session_id in the TRANSACTIONS table.
void update_transaction(const std::string& session_id, std::int32_t transaction_id,
std::optional<CiString<20>> parent_id_tag = std::nullopt);
/// \brief Updates the given parameters for the transaction with the given \p session_id in the TRANSACTIONS table.
void update_transaction(const std::string& session_id, std::int32_t meter_stop, const std::string& time_end,
std::optional<CiString<20>> id_tag_end, std::optional<v16::Reason> stop_reason,
const std::string& stop_transaction_message_id);
/// \brief Updates the CSMS_ACK column for the transaction with the given \p transaction_id in the TRANSACTIONS
/// table
void update_transaction_csms_ack(const std::int32_t transaction_id);
/// \brief Returns the TransactionEntry for the given \p transaction_id, or std::nullopt if not found.
std::optional<TransactionEntry> get_transaction(const std::int32_t transaction_id);
/// \brief Updates the START_TRANSACTION_MESSAGE_ID column for the transaction with the given \p session_id in the
/// TRANSACTIONS table
void update_start_transaction_message_id(const std::string& session_id,
const std::string& start_transaction_message_id);
/// \brief Updates the METER_LAST and METER_LAST_TIME column for the transaction with the given \p session_id in the
/// TRANSACTIONS table
void update_transaction_meter_value(const std::string& session_id, const std::int32_t value,
const std::string& last_meter_time);
/// \brief Returns a list of all transactions in the database. If \p filter_complete is true, only incomplete
/// transactions will be return. If \p filter_complete is false, all transactions will be returned
std::vector<TransactionEntry> get_transactions(bool filter_incomplete = false);
// authorization cache
/// \brief Inserts or updates an authorization cache entry to the AUTH_CACHE table.
void insert_or_update_authorization_cache_entry(const CiString<20>& id_tag, const v16::IdTagInfo& id_tag_info);
/// \brief Returns the IdTagInfo of the given \p id_tag if it exists in the AUTH_CACHE table, else std::nullopt.
std::optional<v16::IdTagInfo> get_authorization_cache_entry(const CiString<20>& id_tag);
/// \brief Deletes all entries of the AUTH_CACHE table.
void clear_authorization_cache();
// connector availability
/// \brief Inserts or updates the given \p availability_type of the given \p connector to the CONNECTORS table.
void insert_or_update_connector_availability(std::int32_t connector,
const v16::AvailabilityType& availability_type);
/// \brief Inserts or updates the given \p availability_type of the given \p connectors to the CONNECTORS table.
void insert_or_update_connector_availability(const std::vector<std::int32_t>& connectors,
const v16::AvailabilityType& availability_type);
/// \brief Returns the AvailabilityType of the given \p connector of the CONNECTORS table.
v16::AvailabilityType get_connector_availability(std::int32_t connector);
/// \brief Returns a map of all connectors and its AvailabilityTypes of the CONNECTORS table.
std::map<std::int32_t, v16::AvailabilityType> get_connector_availability();
// local auth list management
/// \brief Inserts or ignores the given \p version in the AUTH_LIST_VERSION table.
void insert_or_ignore_local_list_version(std::int32_t version);
/// \brief Inserts or updates the given \p version in the AUTH_LIST_VERSION table.
void insert_or_update_local_list_version(std::int32_t version);
/// \brief Returns the version in the AUTH_LIST_VERSION table.
std::int32_t get_local_list_version();
/// \brief Inserts or updates a local authorization list entry to the AUTH_LIST table.
void insert_or_update_local_authorization_list_entry(const CiString<20>& id_tag, const v16::IdTagInfo& id_tag_info);
/// \brief Inserts or updates a local authorization list entries \p local_authorization_list to the AUTH_LIST table.
void insert_or_update_local_authorization_list(std::vector<v16::LocalAuthorizationList> local_authorization_list);
/// \brief Deletes the authorization list entry with the given \p id_tag
void delete_local_authorization_list_entry(const std::string& id_tag);
/// \brief Returns the IdTagInfo of the given \p id_tag if it exists in the AUTH_LIST table, else std::nullopt.
std::optional<v16::IdTagInfo> get_local_authorization_list_entry(const CiString<20>& id_tag);
/// \brief Deletes all entries of the AUTH_LIST table.
void clear_local_authorization_list();
/// \brief Get the number of entries currently in the authorization list
std::int32_t get_local_authorization_list_number_of_entries();
/// \brief Inserts or updates the given \p profile to CHARGING_PROFILES table
virtual void insert_or_update_charging_profile(const int connector_id, const v16::ChargingProfile& profile);
/// \brief Deletes the profile with the given \p profile_id
virtual void delete_charging_profile(const int profile_id);
/// \brief Deletes all profiles from table CHARGING_PROFILES
void delete_charging_profiles();
/// \brief Returns a list of all charging profiles in the CHARGING_PROFILES table
std::vector<v16::ChargingProfile> get_charging_profiles();
/// \brief Returns the connector_id of the given \p profile_id
int get_connector_id(const int profile_id);
/// \brief Returns the ids of all charging profiles stored against the given \p connector_id
///
/// Used to discover profiles whose install-time connector was 0 (i.e. ChargePointMaxProfile
/// and TxDefaultProfile installed at the charge-point level) so that ClearChargingProfile
/// with connectorId=0 can remove them along with their in-memory fan-out copies.
virtual std::vector<int32_t> get_charging_profile_ids_by_connector_id(const int connector_id);
};
} // namespace v16
} // namespace ocpp
#endif // OCPP_COMMON_DATABASE_HANDLER_HPP

View File

@@ -0,0 +1,394 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2026 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_KNOWN_KEYS_HPP
#define OCPP_V16_KNOWN_KEYS_HPP
#include "ocpp/v16/types.hpp"
#include "ocpp/v2/ctrlr_component_variables.hpp"
#include "ocpp/v2/ocpp_enums.hpp"
#include "ocpp/v2/ocpp_types.hpp"
#include <cstdint>
#include <optional>
#include <string_view>
#include <tuple>
namespace ocpp::v16::keys {
// clang-format off
// ============================================================================
// Standard OCPP 1.6 keys
// ============================================================================
// SupportedMeasurands is collected from the following valuesList elements
// - AlignedDataMeasurands
// - AlignedDataTxEndedMeasurands
// - SampledDataTxEndedMeasurands
// - SampledDataTxStartedMeasurands
// - SampledDataTxUpdatedMeasurands
#define MAPPING_STANDARD(mapping) \
mapping(AllowOfflineTxForUnknownId, OfflineTxForUnknownIdEnabled, Actual) \
mapping(AuthorizationCacheEnabled, AuthCacheCtrlrEnabled, Actual) \
mapping(AuthorizeRemoteTxRequests, AuthorizeRemoteStart, Actual) \
mapping(ClockAlignedDataInterval, AlignedDataInterval, Actual) \
mapping(ConnectionTimeOut, EVConnectionTimeOut, Actual) \
mapping(HeartbeatInterval, HeartbeatInterval, Actual) \
mapping(LocalAuthorizeOffline, LocalAuthorizeOffline, Actual) \
mapping(LocalPreAuthorize, LocalPreAuthorize, Actual) \
mapping(MaxEnergyOnInvalidId, MaxEnergyOnInvalidId, Actual) \
mapping(MeterValuesAlignedData, AlignedDataMeasurands, Actual) \
mapping(MeterValuesSampledData, SampledDataTxUpdatedMeasurands, Actual) \
mapping(MeterValueSampleInterval, SampledDataTxUpdatedInterval, Actual) \
mapping(ResetRetries, ResetRetries, Actual) \
mapping(StopTransactionOnInvalidId, StopTxOnInvalidId, Actual) \
mapping(StopTxnAlignedData, AlignedDataTxEndedMeasurands, Actual) \
mapping(StopTxnSampledData, SampledDataTxEndedMeasurands, Actual) \
mapping(TransactionMessageAttempts, MessageAttempts, Actual) \
mapping(TransactionMessageRetryInterval, MessageAttemptInterval, Actual) \
mapping(WebSocketPingInterval, WebSocketPingInterval, Actual) \
mapping(LocalAuthListEnabled, LocalAuthListCtrlrEnabled, Actual) \
mapping(ChargeProfileMaxStackLevel, ChargingProfileMaxStackLevel, Actual) \
mapping(ChargingScheduleAllowedChargingRateUnit, ChargingScheduleChargingRateUnit, Actual) \
mapping(ChargingScheduleMaxPeriods, PeriodsPerSchedule, Actual) \
mapping(ConnectorSwitch3to1PhaseSupported, Phases3to1, Actual) \
mapping(SupportedFileTransferProtocols, FileTransferProtocols, Actual)
// ============================================================================
// Internal configuration keys
// ============================================================================
#define MAPPING_INTERNAL(mapping) \
mapping(ChargePointId, ChargePointId, Actual) \
mapping(ChargeBoxSerialNumber, ChargeBoxSerialNumber, Actual) \
mapping(ChargePointModel, ChargePointModel, Actual) \
mapping(ChargePointSerialNumber, ChargePointSerialNumber, Actual) \
mapping(ChargePointVendor, ChargePointVendor, Actual) \
mapping(FirmwareVersion, FirmwareVersion, Actual) \
mapping(ICCID, ICCID, Actual) \
mapping(IFace, IFace, Actual) \
mapping(IMSI, IMSI, Actual) \
mapping(MeterSerialNumber, MeterSerialNumber, Actual) \
mapping(MeterType, MeterType, Actual) \
mapping(SupportedCiphers12, SupportedCiphers12, Actual) \
mapping(SupportedCiphers13, SupportedCiphers13, Actual) \
mapping(UseTPM, UseTPM, Actual) \
mapping(UseTPMSeccLeafCertificate, UseTPMSeccLeafCertificate, Actual) \
mapping(RetryBackoffRandomRange, RetryBackOffRandomRange, Actual) \
mapping(RetryBackoffRepeatTimes, RetryBackOffRepeatTimes, Actual) \
mapping(AuthorizeConnectorZeroOnConnectorOne,AuthorizeConnectorZeroOnConnectorOne, Actual) \
mapping(LogMessages, LogMessages, Actual) \
mapping(LogMessagesRaw, LogMessagesRaw, Actual) \
mapping(LogMessagesFormat, LogMessagesFormat, Actual) \
mapping(LogRotation, LogRotation, Actual) \
mapping(LogRotationDateSuffix, LogRotationDateSuffix, Actual) \
mapping(LogRotationMaximumFileSize, LogRotationMaximumFileSize, Actual) \
mapping(LogRotationMaximumFileCount, LogRotationMaximumFileCount, Actual) \
mapping(SupportedChargingProfilePurposeTypes,SupportedChargingProfilePurposeTypes, Actual) \
mapping(IgnoredProfilePurposesOffline, IgnoredProfilePurposesOffline, Actual) \
mapping(MaxCompositeScheduleDuration, MaxCompositeScheduleDuration, Actual) \
mapping(CompositeScheduleDefaultLimitAmps, CompositeScheduleDefaultLimitAmps, Actual) \
mapping(CompositeScheduleDefaultLimitWatts, CompositeScheduleDefaultLimitWatts, Actual) \
mapping(CompositeScheduleDefaultNumberPhases, CompositeScheduleDefaultNumberPhases, Actual) \
mapping(SupplyVoltage, SupplyVoltage, Actual) \
mapping(WebsocketPingPayload, WebsocketPingPayload, Actual) \
mapping(WebsocketPongTimeout, WebsocketPongTimeout, Actual) \
mapping(UseSslDefaultVerifyPaths, UseSslDefaultVerifyPaths, Actual) \
mapping(VerifyCsmsCommonName, VerifyCsmsCommonName, Actual) \
mapping(VerifyCsmsAllowWildcards, VerifyCsmsAllowWildcards, Actual) \
mapping(OcspRequestInterval, OcspRequestInterval, Actual) \
mapping(SeccLeafSubjectCommonName, ISO15118CtrlrSeccId, Actual) \
mapping(SeccLeafSubjectCountry, ISO15118CtrlrCountryName, Actual) \
mapping(SeccLeafSubjectOrganization, ISO15118CtrlrOrganizationName, Actual) \
mapping(QueueAllMessages, QueueAllMessages, Actual) \
mapping(MessageTypesDiscardForQueueing, MessageTypesDiscardForQueueing, Actual) \
mapping(MessageQueueSizeThreshold, MessageQueueSizeThreshold, Actual) \
mapping(MaxMessageSize, MaxMessageSize, Actual) \
mapping(TLSKeylogFile, TLSKeylogFile, Actual) \
mapping(EnableTLSKeylog, EnableTLSKeylog, Actual) \
mapping(NumberOfConnectors, NumberOfConnectors, Actual) \
mapping(RetryBackoffWaitMinimum, RetryBackOffWaitMinimum, Actual)
// ============================================================================
// VariableCharacteristics.maxLimit mappings
// These OCPP 1.6 read-only length/limit keys map to VariableCharacteristics.maxLimit
// in OCPP 2.x
// ============================================================================
#define MAPPING_MAX_LIMIT(mapping) \
mapping(MeterValuesAlignedDataMaxLength, AlignedDataMeasurands) \
mapping(MeterValuesSampledDataMaxLength, SampledDataTxUpdatedMeasurands) \
mapping(StopTxnAlignedDataMaxLength, AlignedDataTxEndedMeasurands) \
mapping(StopTxnSampledDataMaxLength, SampledDataTxEndedMeasurands) \
mapping(LocalAuthListMaxLength, LocalAuthListCtrlrEntries) \
mapping(SendLocalListMaxLength, ItemsPerMessageSendLocalList) \
mapping(MaxChargingProfilesInstalled, EntriesChargingProfiles)
// ============================================================================
// Security Section
// ============================================================================
#define MAPPING_SECURITY(mapping) \
mapping(AdditionalRootCertificateCheck, AdditionalRootCertificateCheck, Actual) \
mapping(CertificateSignedMaxChainSize, MaxCertificateChainSize, Actual) \
mapping(CpoName, OrganizationName, Actual) \
mapping(CertSigningWaitMinimum, CertSigningWaitMinimum, Actual) \
mapping(CertSigningRepeatTimes, CertSigningRepeatTimes, Actual) \
mapping(CertificateStoreMaxLength, CertificateEntries, Actual)
// ============================================================================
// PnC Section
// ============================================================================
#define MAPPING_PNC(mapping) \
mapping(ISO15118PnCEnabled, PnCEnabled, Actual) \
mapping(CentralContractValidationAllowed, CentralContractValidationAllowed, Actual) \
mapping(ContractValidationOffline, ContractValidationOffline, Actual)
// ============================================================================
// CostAndPrice Section
// ============================================================================
#define MAPPING_COST(mapping) \
mapping(NumberOfDecimalsForCostValues, NumberOfDecimalsForCostValues, Actual) \
mapping(TimeOffset, TimeOffset, Actual) \
mapping(NextTimeOffsetTransitionDateTime, NextTimeOffsetTransitionDateTime, Actual) \
mapping(TimeOffsetNextTransition, TimeOffsetNextTransition, Actual)
// ============================================================================
// Mavericks Section - OCPP 1.6 keys without direct OCPP 2.x equivalents
// ============================================================================
#define MAPPING_MISC(mapping) \
mapping(BlinkRepeat, BlinkRepeat, Actual) \
mapping(ConnectorPhaseRotation, ConnectorPhaseRotation, Actual) \
mapping(ConnectorPhaseRotationMaxLength, ConnectorPhaseRotationMaxLength, Actual) \
mapping(GetConfigurationMaxKeys, GetConfigurationMaxKeys, Actual) \
mapping(LightIntensity, LightIntensity, Actual) \
mapping(MinimumStatusDuration, MinimumStatusDuration, Actual) \
mapping(StopTransactionOnEVSideDisconnect, StopTransactionOnEVSideDisconnect, Actual) \
mapping(SupportedFeatureProfiles, SupportedFeatureProfiles, Actual) \
mapping(SupportedFeatureProfilesMaxLength, SupportedFeatureProfilesMaxLength, Actual) \
mapping(UnlockConnectorOnEVSideDisconnect, UnlockConnectorOnEVSideDisconnect, Actual) \
mapping(ReserveConnectorZeroSupported, ReserveConnectorZeroSupported, Actual) \
mapping(HostName, HostName, Actual) \
mapping(AllowChargingProfileWithoutStartSchedule, AllowChargingProfileWithoutStartSchedule, Actual) \
mapping(WaitForStopTransactionsOnResetTimeout, WaitForStopTransactionsOnResetTimeout, Actual) \
mapping(StopTransactionIfUnlockNotSupported, StopTransactionIfUnlockNotSupported, Actual) \
mapping(MeterPublicKeys, MeterPublicKeys, Actual) \
mapping(DisableSecurityEventNotifications, DisableSecurityEventNotifications, Actual) \
mapping(ISO15118CertificateManagementEnabled, ISO15118CertificateManagementEnabled, Actual) \
mapping(CustomDisplayCostAndPrice, CustomDisplayCostAndPrice, Actual) \
mapping(DefaultPrice, DefaultPrice, Actual) \
mapping(DefaultPriceText, DefaultPriceText, Actual) \
mapping(CustomIdleFeeAfterStop, CustomIdleFeeAfterStop, Actual) \
mapping(SupportedLanguages, SupportedLanguages, Actual) \
mapping(CustomMultiLanguageMessages, CustomMultiLanguageMessages, Actual) \
mapping(Language, Language, Actual) \
mapping(WaitForSetUserPriceTimeout, WaitForSetUserPriceTimeout, Actual)
// ============================================================================
// Mavericks Section - OCPP 1.6 keys where OCPP 2.x mapping is problematic
// ============================================================================
#define MAPPING_MISC_ADDITIONAL(mapping) \
mapping(AuthorizationKey, AuthorizationKey16, Actual) \
mapping(CentralSystemURI, CentralSystemURI16, Actual) \
mapping(SecurityProfile, SecurityProfile16, Actual)
#define MAPPING_ALL(mapping) \
MAPPING_MISC_ADDITIONAL(mapping) \
MAPPING_MISC(mapping) \
MAPPING_STANDARD(mapping) \
MAPPING_INTERNAL(mapping) \
MAPPING_SECURITY(mapping) \
MAPPING_PNC(mapping) \
MAPPING_COST(mapping)
#define FOR_ALL_MAPPED_KEYS(key) \
key(Core, AllowOfflineTxForUnknownId) \
key(Core, AuthorizationCacheEnabled) \
key(Core, AuthorizeRemoteTxRequests) \
key(Core, BlinkRepeat) \
key(Core, ClockAlignedDataInterval) \
key(Core, ConnectionTimeOut) \
key(Core, ConnectorPhaseRotation) \
key(Core, ConnectorPhaseRotationMaxLength) \
key(Core, GetConfigurationMaxKeys) \
key(Core, HeartbeatInterval) \
key(Core, LightIntensity) \
key(Core, LocalAuthorizeOffline) \
key(Core, LocalPreAuthorize) \
key(Core, MaxEnergyOnInvalidId) \
key(Core, MeterValuesAlignedData) \
key(Core, MeterValuesAlignedDataMaxLength) \
key(Core, MeterValueSampleInterval) \
key(Core, MeterValuesSampledData) \
key(Core, MeterValuesSampledDataMaxLength) \
key(Core, MinimumStatusDuration) \
key(Core, NumberOfConnectors) \
key(Core, ResetRetries) \
key(Core, StopTransactionOnEVSideDisconnect) \
key(Core, StopTransactionOnInvalidId) \
key(Core, StopTxnAlignedData) \
key(Core, StopTxnAlignedDataMaxLength) \
key(Core, StopTxnSampledData) \
key(Core, StopTxnSampledDataMaxLength) \
key(Core, SupportedFeatureProfiles) \
key(Core, SupportedFeatureProfilesMaxLength) \
key(Core, TransactionMessageAttempts) \
key(Core, TransactionMessageRetryInterval) \
key(Core, UnlockConnectorOnEVSideDisconnect) \
key(Core, WebSocketPingInterval) \
key(CostAndPrice, CustomDisplayCostAndPrice) \
key(CostAndPrice, CustomIdleFeeAfterStop) \
key(CostAndPrice, CustomMultiLanguageMessages) \
key(CostAndPrice, DefaultPrice) \
key(CostAndPrice, DefaultPriceText) \
key(CostAndPrice, Language) \
key(CostAndPrice, NextTimeOffsetTransitionDateTime) \
key(CostAndPrice, NumberOfDecimalsForCostValues) \
key(CostAndPrice, SupportedLanguages) \
key(CostAndPrice, TimeOffset) \
key(CostAndPrice, TimeOffsetNextTransition) \
key(CostAndPrice, WaitForSetUserPriceTimeout) \
key(FirmwareManagement, SupportedFileTransferProtocols) \
key(Internal, AllowChargingProfileWithoutStartSchedule) \
key(Internal, AuthorizeConnectorZeroOnConnectorOne) \
key(Internal, CentralSystemURI) \
key(Internal, ChargeBoxSerialNumber) \
key(Internal, ChargePointId) \
key(Internal, ChargePointModel) \
key(Internal, ChargePointSerialNumber) \
key(Internal, ChargePointVendor) \
key(Internal, CompositeScheduleDefaultLimitAmps) \
key(Internal, CompositeScheduleDefaultLimitWatts) \
key(Internal, CompositeScheduleDefaultNumberPhases) \
key(Internal, EnableTLSKeylog) \
key(Internal, FirmwareVersion) \
key(Internal, HostName) \
key(Internal, ICCID) \
key(Internal, IFace) \
key(Internal, IgnoredProfilePurposesOffline) \
key(Internal, IMSI) \
key(Internal, LogMessages) \
key(Internal, LogMessagesFormat) \
key(Internal, LogMessagesRaw) \
key(Internal, LogRotation) \
key(Internal, LogRotationDateSuffix) \
key(Internal, LogRotationMaximumFileCount) \
key(Internal, LogRotationMaximumFileSize) \
key(Internal, MaxCompositeScheduleDuration) \
key(Internal, MaxMessageSize) \
key(Internal, MessageQueueSizeThreshold) \
key(Internal, MessageTypesDiscardForQueueing) \
key(Internal, MeterPublicKeys) \
key(Internal, MeterSerialNumber) \
key(Internal, MeterType) \
key(Internal, OcspRequestInterval) \
key(Internal, QueueAllMessages) \
key(Internal, RetryBackoffRandomRange) \
key(Internal, RetryBackoffRepeatTimes) \
key(Internal, RetryBackoffWaitMinimum) \
key(Internal, SeccLeafSubjectCommonName) \
key(Internal, SeccLeafSubjectCountry) \
key(Internal, SeccLeafSubjectOrganization) \
key(Internal, StopTransactionIfUnlockNotSupported) \
key(Internal, SupplyVoltage) \
key(Internal, SupportedChargingProfilePurposeTypes) \
key(Internal, SupportedCiphers12) \
key(Internal, SupportedCiphers13) \
key(Internal, TLSKeylogFile) \
key(Internal, UseSslDefaultVerifyPaths) \
key(Internal, UseTPM) \
key(Internal, UseTPMSeccLeafCertificate) \
key(Internal, VerifyCsmsAllowWildcards) \
key(Internal, VerifyCsmsCommonName) \
key(Internal, WaitForStopTransactionsOnResetTimeout) \
key(Internal, WebsocketPingPayload) \
key(Internal, WebsocketPongTimeout) \
key(LocalAuthListManagement, LocalAuthListEnabled) \
key(LocalAuthListManagement, LocalAuthListMaxLength) \
key(LocalAuthListManagement, SendLocalListMaxLength) \
key(PnC, CentralContractValidationAllowed) \
key(PnC, CertSigningRepeatTimes) \
key(PnC, CertSigningWaitMinimum) \
key(PnC, ContractValidationOffline) \
key(PnC, ISO15118CertificateManagementEnabled) \
key(PnC, ISO15118PnCEnabled) \
key(Reservation, ReserveConnectorZeroSupported) \
key(Security, AdditionalRootCertificateCheck) \
key(Security, AuthorizationKey) \
key(Security, CertificateSignedMaxChainSize) \
key(Security, CertificateStoreMaxLength) \
key(Security, CpoName) \
key(Security, DisableSecurityEventNotifications) \
key(Security, SecurityProfile) \
key(SmartCharging, ChargeProfileMaxStackLevel) \
key(SmartCharging, ChargingScheduleAllowedChargingRateUnit) \
key(SmartCharging, ChargingScheduleMaxPeriods) \
key(SmartCharging, ConnectorSwitch3to1PhaseSupported) \
key(SmartCharging, MaxChargingProfilesInstalled)
// these have special handling
#define FOR_ALL_UNMAPPED_KEYS(key) \
key(Internal, ConnectorEvseIds) \
key(Internal, SupportedMeasurands)
#define FOR_ALL_KEYS(key) \
FOR_ALL_MAPPED_KEYS(key) \
FOR_ALL_UNMAPPED_KEYS(key)
// clang-format on
#define VALUE(a, b) b,
enum class valid_keys : std::uint8_t {
FOR_ALL_KEYS(VALUE)
};
enum class sections : std::uint8_t {
Core,
CostAndPrice,
FirmwareManagement,
Internal,
LocalAuthListManagement,
PnC,
Reservation,
Security,
SmartCharging,
Custom,
};
#undef VALUE
#define MAX_LIMIT_ENTRY(a, b) {valid_keys::a, &ocpp::v2::ControllerComponentVariables::b},
using MaxLimitEntry = std::pair<valid_keys, const ocpp::v2::ComponentVariable*>;
inline const MaxLimitEntry max_limit_entries[] = {MAPPING_MAX_LIMIT(MAX_LIMIT_ENTRY)};
#undef MAX_LIMIT_ENTRY
std::optional<valid_keys> convert(const std::string_view& str);
std::string_view convert(valid_keys key);
sections to_section(valid_keys key);
std::string_view to_section_string_view(valid_keys key);
bool is_readonly(valid_keys key);
inline bool is_in_section(sections section, valid_keys key) {
return to_section(key) == section;
}
bool is_hidden(valid_keys key);
std::optional<ocpp::v16::SupportedFeatureProfiles> get_profile(valid_keys key);
using DeviceModel_CV = std::optional<std::tuple<ocpp::v2::Component, ocpp::v2::Variable, ocpp::v2::AttributeEnum>>;
DeviceModel_CV convert_v2(const std::string_view& str);
DeviceModel_CV convert_v2(valid_keys key);
std::optional<std::string> convert_v2(const ocpp::v2::Component& component, const ocpp::v2::Variable& variable,
ocpp::v2::AttributeEnum attribute);
/// Returns the (Component, Variable) pair for keys that map to VariableCharacteristics.maxLimit,
/// or std::nullopt if the key uses a regular VariableAttribute mapping.
using DeviceModel_MaxLimitCV = std::optional<std::pair<ocpp::v2::Component, ocpp::v2::Variable>>;
DeviceModel_MaxLimitCV convert_v2_max_limit(valid_keys key);
} // namespace ocpp::v16::keys
#endif // OCPP_V16_KNOWN_KEYS_HPP

View File

@@ -0,0 +1,30 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/common/message_dispatcher.hpp>
#include <ocpp/v16/charge_point_configuration_interface.hpp>
namespace ocpp {
namespace v16 {
class MessageDispatcher : public MessageDispatcherInterface<MessageType> {
public:
MessageDispatcher(ocpp::MessageQueue<MessageType>& message_queue, ChargePointConfigurationInterface& configuration,
std::atomic<RegistrationStatus>& registration_status) :
message_queue(message_queue), configuration(configuration), registration_status(registration_status){};
void dispatch_call(const json& call, bool triggered = false) override;
std::future<ocpp::EnhancedMessage<MessageType>> dispatch_call_async(const json& call, bool triggered) override;
void dispatch_call_result(const json& call_result) override;
void dispatch_call_error(const json& call_error) override;
private:
ocpp::MessageQueue<MessageType>& message_queue;
ChargePointConfigurationInterface& configuration;
std::atomic<RegistrationStatus>& registration_status;
};
} // namespace v16
} // namespace ocpp

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_AUTHORIZE_HPP
#define OCPP_V16_AUTHORIZE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP Authorize message
struct AuthorizeRequest : public ocpp::Message {
CiString<20> idTag;
/// \brief Provides the type of this Authorize message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given AuthorizeRequest \p k to a given json object \p j
void to_json(json& j, const AuthorizeRequest& k);
/// \brief Conversion from a given json object \p j to a given AuthorizeRequest \p k
void from_json(const json& j, AuthorizeRequest& k);
/// \brief Writes the string representation of the given AuthorizeRequest \p k to the given output stream \p os
/// \returns an output stream with the AuthorizeRequest written to
std::ostream& operator<<(std::ostream& os, const AuthorizeRequest& k);
/// \brief Contains a OCPP AuthorizeResponse message
struct AuthorizeResponse : public ocpp::Message {
IdTagInfo idTagInfo;
/// \brief Provides the type of this AuthorizeResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given AuthorizeResponse \p k to a given json object \p j
void to_json(json& j, const AuthorizeResponse& k);
/// \brief Conversion from a given json object \p j to a given AuthorizeResponse \p k
void from_json(const json& j, AuthorizeResponse& k);
/// \brief Writes the string representation of the given AuthorizeResponse \p k to the given output stream \p os
/// \returns an output stream with the AuthorizeResponse written to
std::ostream& operator<<(std::ostream& os, const AuthorizeResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_AUTHORIZE_HPP

View File

@@ -0,0 +1,69 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_BOOTNOTIFICATION_HPP
#define OCPP_V16_BOOTNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP BootNotification message
struct BootNotificationRequest : public ocpp::Message {
CiString<20> chargePointVendor;
CiString<20> chargePointModel;
std::optional<CiString<25>> chargePointSerialNumber;
std::optional<CiString<25>> chargeBoxSerialNumber;
std::optional<CiString<50>> firmwareVersion;
std::optional<CiString<20>> iccid;
std::optional<CiString<20>> imsi;
std::optional<CiString<25>> meterType;
std::optional<CiString<25>> meterSerialNumber;
/// \brief Provides the type of this BootNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given BootNotificationRequest \p k to a given json object \p j
void to_json(json& j, const BootNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given BootNotificationRequest \p k
void from_json(const json& j, BootNotificationRequest& k);
/// \brief Writes the string representation of the given BootNotificationRequest \p k to the given output stream \p os
/// \returns an output stream with the BootNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const BootNotificationRequest& k);
/// \brief Contains a OCPP BootNotificationResponse message
struct BootNotificationResponse : public ocpp::Message {
RegistrationStatus status;
ocpp::DateTime currentTime;
std::int32_t interval;
/// \brief Provides the type of this BootNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given BootNotificationResponse \p k to a given json object \p j
void to_json(json& j, const BootNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given BootNotificationResponse \p k
void from_json(const json& j, BootNotificationResponse& k);
/// \brief Writes the string representation of the given BootNotificationResponse \p k to the given output stream \p os
/// \returns an output stream with the BootNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const BootNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_BOOTNOTIFICATION_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_CANCELRESERVATION_HPP
#define OCPP_V16_CANCELRESERVATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP CancelReservation message
struct CancelReservationRequest : public ocpp::Message {
std::int32_t reservationId;
/// \brief Provides the type of this CancelReservation message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given CancelReservationRequest \p k to a given json object \p j
void to_json(json& j, const CancelReservationRequest& k);
/// \brief Conversion from a given json object \p j to a given CancelReservationRequest \p k
void from_json(const json& j, CancelReservationRequest& k);
/// \brief Writes the string representation of the given CancelReservationRequest \p k to the given output stream \p os
/// \returns an output stream with the CancelReservationRequest written to
std::ostream& operator<<(std::ostream& os, const CancelReservationRequest& k);
/// \brief Contains a OCPP CancelReservationResponse message
struct CancelReservationResponse : public ocpp::Message {
CancelReservationStatus status;
/// \brief Provides the type of this CancelReservationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given CancelReservationResponse \p k to a given json object \p j
void to_json(json& j, const CancelReservationResponse& k);
/// \brief Conversion from a given json object \p j to a given CancelReservationResponse \p k
void from_json(const json& j, CancelReservationResponse& k);
/// \brief Writes the string representation of the given CancelReservationResponse \p k to the given output stream \p os
/// \returns an output stream with the CancelReservationResponse written to
std::ostream& operator<<(std::ostream& os, const CancelReservationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CANCELRESERVATION_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_CERTIFICATESIGNED_HPP
#define OCPP_V16_CERTIFICATESIGNED_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP CertificateSigned message
struct CertificateSignedRequest : public ocpp::Message {
CiString<10000> certificateChain;
/// \brief Provides the type of this CertificateSigned message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given CertificateSignedRequest \p k to a given json object \p j
void to_json(json& j, const CertificateSignedRequest& k);
/// \brief Conversion from a given json object \p j to a given CertificateSignedRequest \p k
void from_json(const json& j, CertificateSignedRequest& k);
/// \brief Writes the string representation of the given CertificateSignedRequest \p k to the given output stream \p os
/// \returns an output stream with the CertificateSignedRequest written to
std::ostream& operator<<(std::ostream& os, const CertificateSignedRequest& k);
/// \brief Contains a OCPP CertificateSignedResponse message
struct CertificateSignedResponse : public ocpp::Message {
CertificateSignedStatusEnumType status;
/// \brief Provides the type of this CertificateSignedResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given CertificateSignedResponse \p k to a given json object \p j
void to_json(json& j, const CertificateSignedResponse& k);
/// \brief Conversion from a given json object \p j to a given CertificateSignedResponse \p k
void from_json(const json& j, CertificateSignedResponse& k);
/// \brief Writes the string representation of the given CertificateSignedResponse \p k to the given output stream \p os
/// \returns an output stream with the CertificateSignedResponse written to
std::ostream& operator<<(std::ostream& os, const CertificateSignedResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CERTIFICATESIGNED_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_CHANGEAVAILABILITY_HPP
#define OCPP_V16_CHANGEAVAILABILITY_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP ChangeAvailability message
struct ChangeAvailabilityRequest : public ocpp::Message {
std::int32_t connectorId;
AvailabilityType type;
/// \brief Provides the type of this ChangeAvailability message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ChangeAvailabilityRequest \p k to a given json object \p j
void to_json(json& j, const ChangeAvailabilityRequest& k);
/// \brief Conversion from a given json object \p j to a given ChangeAvailabilityRequest \p k
void from_json(const json& j, ChangeAvailabilityRequest& k);
/// \brief Writes the string representation of the given ChangeAvailabilityRequest \p k to the given output stream \p os
/// \returns an output stream with the ChangeAvailabilityRequest written to
std::ostream& operator<<(std::ostream& os, const ChangeAvailabilityRequest& k);
/// \brief Contains a OCPP ChangeAvailabilityResponse message
struct ChangeAvailabilityResponse : public ocpp::Message {
AvailabilityStatus status;
/// \brief Provides the type of this ChangeAvailabilityResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ChangeAvailabilityResponse \p k to a given json object \p j
void to_json(json& j, const ChangeAvailabilityResponse& k);
/// \brief Conversion from a given json object \p j to a given ChangeAvailabilityResponse \p k
void from_json(const json& j, ChangeAvailabilityResponse& k);
/// \brief Writes the string representation of the given ChangeAvailabilityResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the ChangeAvailabilityResponse written to
std::ostream& operator<<(std::ostream& os, const ChangeAvailabilityResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CHANGEAVAILABILITY_HPP

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_CHANGECONFIGURATION_HPP
#define OCPP_V16_CHANGECONFIGURATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP ChangeConfiguration message
struct ChangeConfigurationRequest : public ocpp::Message {
CiString<50> key;
CiString<500> value;
/// \brief Provides the type of this ChangeConfiguration message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ChangeConfigurationRequest \p k to a given json object \p j
void to_json(json& j, const ChangeConfigurationRequest& k);
/// \brief Conversion from a given json object \p j to a given ChangeConfigurationRequest \p k
void from_json(const json& j, ChangeConfigurationRequest& k);
/// \brief Writes the string representation of the given ChangeConfigurationRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the ChangeConfigurationRequest written to
std::ostream& operator<<(std::ostream& os, const ChangeConfigurationRequest& k);
/// \brief Contains a OCPP ChangeConfigurationResponse message
struct ChangeConfigurationResponse : public ocpp::Message {
ConfigurationStatus status;
/// \brief Provides the type of this ChangeConfigurationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ChangeConfigurationResponse \p k to a given json object \p j
void to_json(json& j, const ChangeConfigurationResponse& k);
/// \brief Conversion from a given json object \p j to a given ChangeConfigurationResponse \p k
void from_json(const json& j, ChangeConfigurationResponse& k);
/// \brief Writes the string representation of the given ChangeConfigurationResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the ChangeConfigurationResponse written to
std::ostream& operator<<(std::ostream& os, const ChangeConfigurationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CHANGECONFIGURATION_HPP

View File

@@ -0,0 +1,56 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_CLEARCACHE_HPP
#define OCPP_V16_CLEARCACHE_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP ClearCache message
struct ClearCacheRequest : public ocpp::Message {
/// \brief Provides the type of this ClearCache message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ClearCacheRequest \p k to a given json object \p j
void to_json(json& j, const ClearCacheRequest& k);
/// \brief Conversion from a given json object \p j to a given ClearCacheRequest \p k
void from_json(const json& j, ClearCacheRequest& k);
/// \brief Writes the string representation of the given ClearCacheRequest \p k to the given output stream \p os
/// \returns an output stream with the ClearCacheRequest written to
std::ostream& operator<<(std::ostream& os, const ClearCacheRequest& k);
/// \brief Contains a OCPP ClearCacheResponse message
struct ClearCacheResponse : public ocpp::Message {
ClearCacheStatus status;
/// \brief Provides the type of this ClearCacheResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ClearCacheResponse \p k to a given json object \p j
void to_json(json& j, const ClearCacheResponse& k);
/// \brief Conversion from a given json object \p j to a given ClearCacheResponse \p k
void from_json(const json& j, ClearCacheResponse& k);
/// \brief Writes the string representation of the given ClearCacheResponse \p k to the given output stream \p os
/// \returns an output stream with the ClearCacheResponse written to
std::ostream& operator<<(std::ostream& os, const ClearCacheResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CLEARCACHE_HPP

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_CLEARCHARGINGPROFILE_HPP
#define OCPP_V16_CLEARCHARGINGPROFILE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP ClearChargingProfile message
struct ClearChargingProfileRequest : public ocpp::Message {
std::optional<std::int32_t> id;
std::optional<std::int32_t> connectorId;
std::optional<ChargingProfilePurposeType> chargingProfilePurpose;
std::optional<std::int32_t> stackLevel;
/// \brief Provides the type of this ClearChargingProfile message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ClearChargingProfileRequest \p k to a given json object \p j
void to_json(json& j, const ClearChargingProfileRequest& k);
/// \brief Conversion from a given json object \p j to a given ClearChargingProfileRequest \p k
void from_json(const json& j, ClearChargingProfileRequest& k);
/// \brief Writes the string representation of the given ClearChargingProfileRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the ClearChargingProfileRequest written to
std::ostream& operator<<(std::ostream& os, const ClearChargingProfileRequest& k);
/// \brief Contains a OCPP ClearChargingProfileResponse message
struct ClearChargingProfileResponse : public ocpp::Message {
ClearChargingProfileStatus status;
/// \brief Provides the type of this ClearChargingProfileResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ClearChargingProfileResponse \p k to a given json object \p j
void to_json(json& j, const ClearChargingProfileResponse& k);
/// \brief Conversion from a given json object \p j to a given ClearChargingProfileResponse \p k
void from_json(const json& j, ClearChargingProfileResponse& k);
/// \brief Writes the string representation of the given ClearChargingProfileResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the ClearChargingProfileResponse written to
std::ostream& operator<<(std::ostream& os, const ClearChargingProfileResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_CLEARCHARGINGPROFILE_HPP

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_DATATRANSFER_HPP
#define OCPP_V16_DATATRANSFER_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP DataTransfer message
struct DataTransferRequest : public ocpp::Message {
CiString<255> vendorId;
std::optional<CiString<50>> messageId;
std::optional<std::string> data;
/// \brief Provides the type of this DataTransfer message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given DataTransferRequest \p k to a given json object \p j
void to_json(json& j, const DataTransferRequest& k);
/// \brief Conversion from a given json object \p j to a given DataTransferRequest \p k
void from_json(const json& j, DataTransferRequest& k);
/// \brief Writes the string representation of the given DataTransferRequest \p k to the given output stream \p os
/// \returns an output stream with the DataTransferRequest written to
std::ostream& operator<<(std::ostream& os, const DataTransferRequest& k);
/// \brief Contains a OCPP DataTransferResponse message
struct DataTransferResponse : public ocpp::Message {
DataTransferStatus status;
std::optional<std::string> data;
/// \brief Provides the type of this DataTransferResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given DataTransferResponse \p k to a given json object \p j
void to_json(json& j, const DataTransferResponse& k);
/// \brief Conversion from a given json object \p j to a given DataTransferResponse \p k
void from_json(const json& j, DataTransferResponse& k);
/// \brief Writes the string representation of the given DataTransferResponse \p k to the given output stream \p os
/// \returns an output stream with the DataTransferResponse written to
std::ostream& operator<<(std::ostream& os, const DataTransferResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_DATATRANSFER_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_DELETECERTIFICATE_HPP
#define OCPP_V16_DELETECERTIFICATE_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP DeleteCertificate message
struct DeleteCertificateRequest : public ocpp::Message {
CertificateHashDataType certificateHashData;
/// \brief Provides the type of this DeleteCertificate message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given DeleteCertificateRequest \p k to a given json object \p j
void to_json(json& j, const DeleteCertificateRequest& k);
/// \brief Conversion from a given json object \p j to a given DeleteCertificateRequest \p k
void from_json(const json& j, DeleteCertificateRequest& k);
/// \brief Writes the string representation of the given DeleteCertificateRequest \p k to the given output stream \p os
/// \returns an output stream with the DeleteCertificateRequest written to
std::ostream& operator<<(std::ostream& os, const DeleteCertificateRequest& k);
/// \brief Contains a OCPP DeleteCertificateResponse message
struct DeleteCertificateResponse : public ocpp::Message {
DeleteCertificateStatusEnumType status;
/// \brief Provides the type of this DeleteCertificateResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given DeleteCertificateResponse \p k to a given json object \p j
void to_json(json& j, const DeleteCertificateResponse& k);
/// \brief Conversion from a given json object \p j to a given DeleteCertificateResponse \p k
void from_json(const json& j, DeleteCertificateResponse& k);
/// \brief Writes the string representation of the given DeleteCertificateResponse \p k to the given output stream \p os
/// \returns an output stream with the DeleteCertificateResponse written to
std::ostream& operator<<(std::ostream& os, const DeleteCertificateResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_DELETECERTIFICATE_HPP

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_DIAGNOSTICSSTATUSNOTIFICATION_HPP
#define OCPP_V16_DIAGNOSTICSSTATUSNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP DiagnosticsStatusNotification message
struct DiagnosticsStatusNotificationRequest : public ocpp::Message {
DiagnosticsStatus status;
/// \brief Provides the type of this DiagnosticsStatusNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given DiagnosticsStatusNotificationRequest \p k to a given json object \p j
void to_json(json& j, const DiagnosticsStatusNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given DiagnosticsStatusNotificationRequest \p k
void from_json(const json& j, DiagnosticsStatusNotificationRequest& k);
/// \brief Writes the string representation of the given DiagnosticsStatusNotificationRequest \p k to the given output
/// stream \p os
/// \returns an output stream with the DiagnosticsStatusNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const DiagnosticsStatusNotificationRequest& k);
/// \brief Contains a OCPP DiagnosticsStatusNotificationResponse message
struct DiagnosticsStatusNotificationResponse : public ocpp::Message {
/// \brief Provides the type of this DiagnosticsStatusNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given DiagnosticsStatusNotificationResponse \p k to a given json object \p j
void to_json(json& j, const DiagnosticsStatusNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given DiagnosticsStatusNotificationResponse \p k
void from_json(const json& j, DiagnosticsStatusNotificationResponse& k);
/// \brief Writes the string representation of the given DiagnosticsStatusNotificationResponse \p k to the given output
/// stream \p os
/// \returns an output stream with the DiagnosticsStatusNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const DiagnosticsStatusNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_DIAGNOSTICSSTATUSNOTIFICATION_HPP

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_EXTENDEDTRIGGERMESSAGE_HPP
#define OCPP_V16_EXTENDEDTRIGGERMESSAGE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP ExtendedTriggerMessage message
struct ExtendedTriggerMessageRequest : public ocpp::Message {
MessageTriggerEnumType requestedMessage;
std::optional<std::int32_t> connectorId;
/// \brief Provides the type of this ExtendedTriggerMessage message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ExtendedTriggerMessageRequest \p k to a given json object \p j
void to_json(json& j, const ExtendedTriggerMessageRequest& k);
/// \brief Conversion from a given json object \p j to a given ExtendedTriggerMessageRequest \p k
void from_json(const json& j, ExtendedTriggerMessageRequest& k);
/// \brief Writes the string representation of the given ExtendedTriggerMessageRequest \p k to the given output stream
/// \p os
/// \returns an output stream with the ExtendedTriggerMessageRequest written to
std::ostream& operator<<(std::ostream& os, const ExtendedTriggerMessageRequest& k);
/// \brief Contains a OCPP ExtendedTriggerMessageResponse message
struct ExtendedTriggerMessageResponse : public ocpp::Message {
TriggerMessageStatusEnumType status;
/// \brief Provides the type of this ExtendedTriggerMessageResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ExtendedTriggerMessageResponse \p k to a given json object \p j
void to_json(json& j, const ExtendedTriggerMessageResponse& k);
/// \brief Conversion from a given json object \p j to a given ExtendedTriggerMessageResponse \p k
void from_json(const json& j, ExtendedTriggerMessageResponse& k);
/// \brief Writes the string representation of the given ExtendedTriggerMessageResponse \p k to the given output stream
/// \p os
/// \returns an output stream with the ExtendedTriggerMessageResponse written to
std::ostream& operator<<(std::ostream& os, const ExtendedTriggerMessageResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_EXTENDEDTRIGGERMESSAGE_HPP

View File

@@ -0,0 +1,58 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_FIRMWARESTATUSNOTIFICATION_HPP
#define OCPP_V16_FIRMWARESTATUSNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP FirmwareStatusNotification message
struct FirmwareStatusNotificationRequest : public ocpp::Message {
FirmwareStatus status;
/// \brief Provides the type of this FirmwareStatusNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given FirmwareStatusNotificationRequest \p k to a given json object \p j
void to_json(json& j, const FirmwareStatusNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given FirmwareStatusNotificationRequest \p k
void from_json(const json& j, FirmwareStatusNotificationRequest& k);
/// \brief Writes the string representation of the given FirmwareStatusNotificationRequest \p k to the given output
/// stream \p os
/// \returns an output stream with the FirmwareStatusNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const FirmwareStatusNotificationRequest& k);
/// \brief Contains a OCPP FirmwareStatusNotificationResponse message
struct FirmwareStatusNotificationResponse : public ocpp::Message {
/// \brief Provides the type of this FirmwareStatusNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given FirmwareStatusNotificationResponse \p k to a given json object \p j
void to_json(json& j, const FirmwareStatusNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given FirmwareStatusNotificationResponse \p k
void from_json(const json& j, FirmwareStatusNotificationResponse& k);
/// \brief Writes the string representation of the given FirmwareStatusNotificationResponse \p k to the given output
/// stream \p os
/// \returns an output stream with the FirmwareStatusNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const FirmwareStatusNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_FIRMWARESTATUSNOTIFICATION_HPP

View File

@@ -0,0 +1,65 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_GETCOMPOSITESCHEDULE_HPP
#define OCPP_V16_GETCOMPOSITESCHEDULE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP GetCompositeSchedule message
struct GetCompositeScheduleRequest : public ocpp::Message {
std::int32_t connectorId;
std::int32_t duration;
std::optional<ChargingRateUnit> chargingRateUnit;
/// \brief Provides the type of this GetCompositeSchedule message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetCompositeScheduleRequest \p k to a given json object \p j
void to_json(json& j, const GetCompositeScheduleRequest& k);
/// \brief Conversion from a given json object \p j to a given GetCompositeScheduleRequest \p k
void from_json(const json& j, GetCompositeScheduleRequest& k);
/// \brief Writes the string representation of the given GetCompositeScheduleRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the GetCompositeScheduleRequest written to
std::ostream& operator<<(std::ostream& os, const GetCompositeScheduleRequest& k);
/// \brief Contains a OCPP GetCompositeScheduleResponse message
struct GetCompositeScheduleResponse : public ocpp::Message {
GetCompositeScheduleStatus status;
std::optional<std::int32_t> connectorId;
std::optional<ocpp::DateTime> scheduleStart;
std::optional<ChargingSchedule> chargingSchedule;
/// \brief Provides the type of this GetCompositeScheduleResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetCompositeScheduleResponse \p k to a given json object \p j
void to_json(json& j, const GetCompositeScheduleResponse& k);
/// \brief Conversion from a given json object \p j to a given GetCompositeScheduleResponse \p k
void from_json(const json& j, GetCompositeScheduleResponse& k);
/// \brief Writes the string representation of the given GetCompositeScheduleResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the GetCompositeScheduleResponse written to
std::ostream& operator<<(std::ostream& os, const GetCompositeScheduleResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_GETCOMPOSITESCHEDULE_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_GETCONFIGURATION_HPP
#define OCPP_V16_GETCONFIGURATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP GetConfiguration message
struct GetConfigurationRequest : public ocpp::Message {
std::optional<std::vector<CiString<50>>> key;
/// \brief Provides the type of this GetConfiguration message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetConfigurationRequest \p k to a given json object \p j
void to_json(json& j, const GetConfigurationRequest& k);
/// \brief Conversion from a given json object \p j to a given GetConfigurationRequest \p k
void from_json(const json& j, GetConfigurationRequest& k);
/// \brief Writes the string representation of the given GetConfigurationRequest \p k to the given output stream \p os
/// \returns an output stream with the GetConfigurationRequest written to
std::ostream& operator<<(std::ostream& os, const GetConfigurationRequest& k);
/// \brief Contains a OCPP GetConfigurationResponse message
struct GetConfigurationResponse : public ocpp::Message {
std::optional<std::vector<KeyValue>> configurationKey;
std::optional<std::vector<CiString<50>>> unknownKey;
/// \brief Provides the type of this GetConfigurationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetConfigurationResponse \p k to a given json object \p j
void to_json(json& j, const GetConfigurationResponse& k);
/// \brief Conversion from a given json object \p j to a given GetConfigurationResponse \p k
void from_json(const json& j, GetConfigurationResponse& k);
/// \brief Writes the string representation of the given GetConfigurationResponse \p k to the given output stream \p os
/// \returns an output stream with the GetConfigurationResponse written to
std::ostream& operator<<(std::ostream& os, const GetConfigurationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_GETCONFIGURATION_HPP

View File

@@ -0,0 +1,62 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_GETDIAGNOSTICS_HPP
#define OCPP_V16_GETDIAGNOSTICS_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP GetDiagnostics message
struct GetDiagnosticsRequest : public ocpp::Message {
std::string location;
std::optional<std::int32_t> retries;
std::optional<std::int32_t> retryInterval;
std::optional<ocpp::DateTime> startTime;
std::optional<ocpp::DateTime> stopTime;
/// \brief Provides the type of this GetDiagnostics message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetDiagnosticsRequest \p k to a given json object \p j
void to_json(json& j, const GetDiagnosticsRequest& k);
/// \brief Conversion from a given json object \p j to a given GetDiagnosticsRequest \p k
void from_json(const json& j, GetDiagnosticsRequest& k);
/// \brief Writes the string representation of the given GetDiagnosticsRequest \p k to the given output stream \p os
/// \returns an output stream with the GetDiagnosticsRequest written to
std::ostream& operator<<(std::ostream& os, const GetDiagnosticsRequest& k);
/// \brief Contains a OCPP GetDiagnosticsResponse message
struct GetDiagnosticsResponse : public ocpp::Message {
std::optional<CiString<255>> fileName;
/// \brief Provides the type of this GetDiagnosticsResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetDiagnosticsResponse \p k to a given json object \p j
void to_json(json& j, const GetDiagnosticsResponse& k);
/// \brief Conversion from a given json object \p j to a given GetDiagnosticsResponse \p k
void from_json(const json& j, GetDiagnosticsResponse& k);
/// \brief Writes the string representation of the given GetDiagnosticsResponse \p k to the given output stream \p os
/// \returns an output stream with the GetDiagnosticsResponse written to
std::ostream& operator<<(std::ostream& os, const GetDiagnosticsResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_GETDIAGNOSTICS_HPP

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_GETINSTALLEDCERTIFICATEIDS_HPP
#define OCPP_V16_GETINSTALLEDCERTIFICATEIDS_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP GetInstalledCertificateIds message
struct GetInstalledCertificateIdsRequest : public ocpp::Message {
CertificateUseEnumType certificateType;
/// \brief Provides the type of this GetInstalledCertificateIds message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetInstalledCertificateIdsRequest \p k to a given json object \p j
void to_json(json& j, const GetInstalledCertificateIdsRequest& k);
/// \brief Conversion from a given json object \p j to a given GetInstalledCertificateIdsRequest \p k
void from_json(const json& j, GetInstalledCertificateIdsRequest& k);
/// \brief Writes the string representation of the given GetInstalledCertificateIdsRequest \p k to the given output
/// stream \p os
/// \returns an output stream with the GetInstalledCertificateIdsRequest written to
std::ostream& operator<<(std::ostream& os, const GetInstalledCertificateIdsRequest& k);
/// \brief Contains a OCPP GetInstalledCertificateIdsResponse message
struct GetInstalledCertificateIdsResponse : public ocpp::Message {
GetInstalledCertificateStatusEnumType status;
std::optional<std::vector<CertificateHashDataType>> certificateHashData;
/// \brief Provides the type of this GetInstalledCertificateIdsResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetInstalledCertificateIdsResponse \p k to a given json object \p j
void to_json(json& j, const GetInstalledCertificateIdsResponse& k);
/// \brief Conversion from a given json object \p j to a given GetInstalledCertificateIdsResponse \p k
void from_json(const json& j, GetInstalledCertificateIdsResponse& k);
/// \brief Writes the string representation of the given GetInstalledCertificateIdsResponse \p k to the given output
/// stream \p os
/// \returns an output stream with the GetInstalledCertificateIdsResponse written to
std::ostream& operator<<(std::ostream& os, const GetInstalledCertificateIdsResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_GETINSTALLEDCERTIFICATEIDS_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_GETLOCALLISTVERSION_HPP
#define OCPP_V16_GETLOCALLISTVERSION_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP GetLocalListVersion message
struct GetLocalListVersionRequest : public ocpp::Message {
/// \brief Provides the type of this GetLocalListVersion message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetLocalListVersionRequest \p k to a given json object \p j
void to_json(json& j, const GetLocalListVersionRequest& k);
/// \brief Conversion from a given json object \p j to a given GetLocalListVersionRequest \p k
void from_json(const json& j, GetLocalListVersionRequest& k);
/// \brief Writes the string representation of the given GetLocalListVersionRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the GetLocalListVersionRequest written to
std::ostream& operator<<(std::ostream& os, const GetLocalListVersionRequest& k);
/// \brief Contains a OCPP GetLocalListVersionResponse message
struct GetLocalListVersionResponse : public ocpp::Message {
std::int32_t listVersion;
/// \brief Provides the type of this GetLocalListVersionResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetLocalListVersionResponse \p k to a given json object \p j
void to_json(json& j, const GetLocalListVersionResponse& k);
/// \brief Conversion from a given json object \p j to a given GetLocalListVersionResponse \p k
void from_json(const json& j, GetLocalListVersionResponse& k);
/// \brief Writes the string representation of the given GetLocalListVersionResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the GetLocalListVersionResponse written to
std::ostream& operator<<(std::ostream& os, const GetLocalListVersionResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_GETLOCALLISTVERSION_HPP

View File

@@ -0,0 +1,64 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_GETLOG_HPP
#define OCPP_V16_GETLOG_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP GetLog message
struct GetLogRequest : public ocpp::Message {
LogParametersType log;
LogEnumType logType;
std::int32_t requestId;
std::optional<std::int32_t> retries;
std::optional<std::int32_t> retryInterval;
/// \brief Provides the type of this GetLog message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetLogRequest \p k to a given json object \p j
void to_json(json& j, const GetLogRequest& k);
/// \brief Conversion from a given json object \p j to a given GetLogRequest \p k
void from_json(const json& j, GetLogRequest& k);
/// \brief Writes the string representation of the given GetLogRequest \p k to the given output stream \p os
/// \returns an output stream with the GetLogRequest written to
std::ostream& operator<<(std::ostream& os, const GetLogRequest& k);
/// \brief Contains a OCPP GetLogResponse message
struct GetLogResponse : public ocpp::Message {
LogStatusEnumType status;
std::optional<CiString<255>> filename;
/// \brief Provides the type of this GetLogResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given GetLogResponse \p k to a given json object \p j
void to_json(json& j, const GetLogResponse& k);
/// \brief Conversion from a given json object \p j to a given GetLogResponse \p k
void from_json(const json& j, GetLogResponse& k);
/// \brief Writes the string representation of the given GetLogResponse \p k to the given output stream \p os
/// \returns an output stream with the GetLogResponse written to
std::ostream& operator<<(std::ostream& os, const GetLogResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_GETLOG_HPP

View File

@@ -0,0 +1,55 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_HEARTBEAT_HPP
#define OCPP_V16_HEARTBEAT_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP Heartbeat message
struct HeartbeatRequest : public ocpp::Message {
/// \brief Provides the type of this Heartbeat message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given HeartbeatRequest \p k to a given json object \p j
void to_json(json& j, const HeartbeatRequest& k);
/// \brief Conversion from a given json object \p j to a given HeartbeatRequest \p k
void from_json(const json& j, HeartbeatRequest& k);
/// \brief Writes the string representation of the given HeartbeatRequest \p k to the given output stream \p os
/// \returns an output stream with the HeartbeatRequest written to
std::ostream& operator<<(std::ostream& os, const HeartbeatRequest& k);
/// \brief Contains a OCPP HeartbeatResponse message
struct HeartbeatResponse : public ocpp::Message {
ocpp::DateTime currentTime;
/// \brief Provides the type of this HeartbeatResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given HeartbeatResponse \p k to a given json object \p j
void to_json(json& j, const HeartbeatResponse& k);
/// \brief Conversion from a given json object \p j to a given HeartbeatResponse \p k
void from_json(const json& j, HeartbeatResponse& k);
/// \brief Writes the string representation of the given HeartbeatResponse \p k to the given output stream \p os
/// \returns an output stream with the HeartbeatResponse written to
std::ostream& operator<<(std::ostream& os, const HeartbeatResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_HEARTBEAT_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_INSTALLCERTIFICATE_HPP
#define OCPP_V16_INSTALLCERTIFICATE_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP InstallCertificate message
struct InstallCertificateRequest : public ocpp::Message {
CertificateUseEnumType certificateType;
CiString<5500> certificate;
/// \brief Provides the type of this InstallCertificate message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given InstallCertificateRequest \p k to a given json object \p j
void to_json(json& j, const InstallCertificateRequest& k);
/// \brief Conversion from a given json object \p j to a given InstallCertificateRequest \p k
void from_json(const json& j, InstallCertificateRequest& k);
/// \brief Writes the string representation of the given InstallCertificateRequest \p k to the given output stream \p os
/// \returns an output stream with the InstallCertificateRequest written to
std::ostream& operator<<(std::ostream& os, const InstallCertificateRequest& k);
/// \brief Contains a OCPP InstallCertificateResponse message
struct InstallCertificateResponse : public ocpp::Message {
InstallCertificateStatusEnumType status;
/// \brief Provides the type of this InstallCertificateResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given InstallCertificateResponse \p k to a given json object \p j
void to_json(json& j, const InstallCertificateResponse& k);
/// \brief Conversion from a given json object \p j to a given InstallCertificateResponse \p k
void from_json(const json& j, InstallCertificateResponse& k);
/// \brief Writes the string representation of the given InstallCertificateResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the InstallCertificateResponse written to
std::ostream& operator<<(std::ostream& os, const InstallCertificateResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_INSTALLCERTIFICATE_HPP

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_LOGSTATUSNOTIFICATION_HPP
#define OCPP_V16_LOGSTATUSNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP LogStatusNotification message
struct LogStatusNotificationRequest : public ocpp::Message {
UploadLogStatusEnumType status;
std::optional<std::int32_t> requestId;
/// \brief Provides the type of this LogStatusNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given LogStatusNotificationRequest \p k to a given json object \p j
void to_json(json& j, const LogStatusNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given LogStatusNotificationRequest \p k
void from_json(const json& j, LogStatusNotificationRequest& k);
/// \brief Writes the string representation of the given LogStatusNotificationRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the LogStatusNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const LogStatusNotificationRequest& k);
/// \brief Contains a OCPP LogStatusNotificationResponse message
struct LogStatusNotificationResponse : public ocpp::Message {
/// \brief Provides the type of this LogStatusNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given LogStatusNotificationResponse \p k to a given json object \p j
void to_json(json& j, const LogStatusNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given LogStatusNotificationResponse \p k
void from_json(const json& j, LogStatusNotificationResponse& k);
/// \brief Writes the string representation of the given LogStatusNotificationResponse \p k to the given output stream
/// \p os
/// \returns an output stream with the LogStatusNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const LogStatusNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_LOGSTATUSNOTIFICATION_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_METERVALUES_HPP
#define OCPP_V16_METERVALUES_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP MeterValues message
struct MeterValuesRequest : public ocpp::Message {
std::int32_t connectorId;
std::vector<MeterValue> meterValue;
std::optional<std::int32_t> transactionId;
/// \brief Provides the type of this MeterValues message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given MeterValuesRequest \p k to a given json object \p j
void to_json(json& j, const MeterValuesRequest& k);
/// \brief Conversion from a given json object \p j to a given MeterValuesRequest \p k
void from_json(const json& j, MeterValuesRequest& k);
/// \brief Writes the string representation of the given MeterValuesRequest \p k to the given output stream \p os
/// \returns an output stream with the MeterValuesRequest written to
std::ostream& operator<<(std::ostream& os, const MeterValuesRequest& k);
/// \brief Contains a OCPP MeterValuesResponse message
struct MeterValuesResponse : public ocpp::Message {
/// \brief Provides the type of this MeterValuesResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given MeterValuesResponse \p k to a given json object \p j
void to_json(json& j, const MeterValuesResponse& k);
/// \brief Conversion from a given json object \p j to a given MeterValuesResponse \p k
void from_json(const json& j, MeterValuesResponse& k);
/// \brief Writes the string representation of the given MeterValuesResponse \p k to the given output stream \p os
/// \returns an output stream with the MeterValuesResponse written to
std::ostream& operator<<(std::ostream& os, const MeterValuesResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_METERVALUES_HPP

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_REMOTESTARTTRANSACTION_HPP
#define OCPP_V16_REMOTESTARTTRANSACTION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP RemoteStartTransaction message
struct RemoteStartTransactionRequest : public ocpp::Message {
CiString<20> idTag;
std::optional<std::int32_t> connectorId;
std::optional<ChargingProfile> chargingProfile;
/// \brief Provides the type of this RemoteStartTransaction message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given RemoteStartTransactionRequest \p k to a given json object \p j
void to_json(json& j, const RemoteStartTransactionRequest& k);
/// \brief Conversion from a given json object \p j to a given RemoteStartTransactionRequest \p k
void from_json(const json& j, RemoteStartTransactionRequest& k);
/// \brief Writes the string representation of the given RemoteStartTransactionRequest \p k to the given output stream
/// \p os
/// \returns an output stream with the RemoteStartTransactionRequest written to
std::ostream& operator<<(std::ostream& os, const RemoteStartTransactionRequest& k);
/// \brief Contains a OCPP RemoteStartTransactionResponse message
struct RemoteStartTransactionResponse : public ocpp::Message {
RemoteStartStopStatus status;
/// \brief Provides the type of this RemoteStartTransactionResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given RemoteStartTransactionResponse \p k to a given json object \p j
void to_json(json& j, const RemoteStartTransactionResponse& k);
/// \brief Conversion from a given json object \p j to a given RemoteStartTransactionResponse \p k
void from_json(const json& j, RemoteStartTransactionResponse& k);
/// \brief Writes the string representation of the given RemoteStartTransactionResponse \p k to the given output stream
/// \p os
/// \returns an output stream with the RemoteStartTransactionResponse written to
std::ostream& operator<<(std::ostream& os, const RemoteStartTransactionResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_REMOTESTARTTRANSACTION_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_REMOTESTOPTRANSACTION_HPP
#define OCPP_V16_REMOTESTOPTRANSACTION_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP RemoteStopTransaction message
struct RemoteStopTransactionRequest : public ocpp::Message {
std::int32_t transactionId;
/// \brief Provides the type of this RemoteStopTransaction message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given RemoteStopTransactionRequest \p k to a given json object \p j
void to_json(json& j, const RemoteStopTransactionRequest& k);
/// \brief Conversion from a given json object \p j to a given RemoteStopTransactionRequest \p k
void from_json(const json& j, RemoteStopTransactionRequest& k);
/// \brief Writes the string representation of the given RemoteStopTransactionRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the RemoteStopTransactionRequest written to
std::ostream& operator<<(std::ostream& os, const RemoteStopTransactionRequest& k);
/// \brief Contains a OCPP RemoteStopTransactionResponse message
struct RemoteStopTransactionResponse : public ocpp::Message {
RemoteStartStopStatus status;
/// \brief Provides the type of this RemoteStopTransactionResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given RemoteStopTransactionResponse \p k to a given json object \p j
void to_json(json& j, const RemoteStopTransactionResponse& k);
/// \brief Conversion from a given json object \p j to a given RemoteStopTransactionResponse \p k
void from_json(const json& j, RemoteStopTransactionResponse& k);
/// \brief Writes the string representation of the given RemoteStopTransactionResponse \p k to the given output stream
/// \p os
/// \returns an output stream with the RemoteStopTransactionResponse written to
std::ostream& operator<<(std::ostream& os, const RemoteStopTransactionResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_REMOTESTOPTRANSACTION_HPP

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_RESERVENOW_HPP
#define OCPP_V16_RESERVENOW_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP ReserveNow message
struct ReserveNowRequest : public ocpp::Message {
std::int32_t connectorId;
ocpp::DateTime expiryDate;
CiString<20> idTag;
std::int32_t reservationId;
std::optional<CiString<20>> parentIdTag;
/// \brief Provides the type of this ReserveNow message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ReserveNowRequest \p k to a given json object \p j
void to_json(json& j, const ReserveNowRequest& k);
/// \brief Conversion from a given json object \p j to a given ReserveNowRequest \p k
void from_json(const json& j, ReserveNowRequest& k);
/// \brief Writes the string representation of the given ReserveNowRequest \p k to the given output stream \p os
/// \returns an output stream with the ReserveNowRequest written to
std::ostream& operator<<(std::ostream& os, const ReserveNowRequest& k);
/// \brief Contains a OCPP ReserveNowResponse message
struct ReserveNowResponse : public ocpp::Message {
ReservationStatus status;
/// \brief Provides the type of this ReserveNowResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ReserveNowResponse \p k to a given json object \p j
void to_json(json& j, const ReserveNowResponse& k);
/// \brief Conversion from a given json object \p j to a given ReserveNowResponse \p k
void from_json(const json& j, ReserveNowResponse& k);
/// \brief Writes the string representation of the given ReserveNowResponse \p k to the given output stream \p os
/// \returns an output stream with the ReserveNowResponse written to
std::ostream& operator<<(std::ostream& os, const ReserveNowResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_RESERVENOW_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_RESET_HPP
#define OCPP_V16_RESET_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP Reset message
struct ResetRequest : public ocpp::Message {
ResetType type;
/// \brief Provides the type of this Reset message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ResetRequest \p k to a given json object \p j
void to_json(json& j, const ResetRequest& k);
/// \brief Conversion from a given json object \p j to a given ResetRequest \p k
void from_json(const json& j, ResetRequest& k);
/// \brief Writes the string representation of the given ResetRequest \p k to the given output stream \p os
/// \returns an output stream with the ResetRequest written to
std::ostream& operator<<(std::ostream& os, const ResetRequest& k);
/// \brief Contains a OCPP ResetResponse message
struct ResetResponse : public ocpp::Message {
ResetStatus status;
/// \brief Provides the type of this ResetResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given ResetResponse \p k to a given json object \p j
void to_json(json& j, const ResetResponse& k);
/// \brief Conversion from a given json object \p j to a given ResetResponse \p k
void from_json(const json& j, ResetResponse& k);
/// \brief Writes the string representation of the given ResetResponse \p k to the given output stream \p os
/// \returns an output stream with the ResetResponse written to
std::ostream& operator<<(std::ostream& os, const ResetResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_RESET_HPP

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_SECURITYEVENTNOTIFICATION_HPP
#define OCPP_V16_SECURITYEVENTNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP SecurityEventNotification message
struct SecurityEventNotificationRequest : public ocpp::Message {
CiString<50> type;
ocpp::DateTime timestamp;
std::optional<CiString<255>> techInfo;
/// \brief Provides the type of this SecurityEventNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SecurityEventNotificationRequest \p k to a given json object \p j
void to_json(json& j, const SecurityEventNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given SecurityEventNotificationRequest \p k
void from_json(const json& j, SecurityEventNotificationRequest& k);
/// \brief Writes the string representation of the given SecurityEventNotificationRequest \p k to the given output
/// stream \p os
/// \returns an output stream with the SecurityEventNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const SecurityEventNotificationRequest& k);
/// \brief Contains a OCPP SecurityEventNotificationResponse message
struct SecurityEventNotificationResponse : public ocpp::Message {
/// \brief Provides the type of this SecurityEventNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SecurityEventNotificationResponse \p k to a given json object \p j
void to_json(json& j, const SecurityEventNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given SecurityEventNotificationResponse \p k
void from_json(const json& j, SecurityEventNotificationResponse& k);
/// \brief Writes the string representation of the given SecurityEventNotificationResponse \p k to the given output
/// stream \p os
/// \returns an output stream with the SecurityEventNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const SecurityEventNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SECURITYEVENTNOTIFICATION_HPP

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_SENDLOCALLIST_HPP
#define OCPP_V16_SENDLOCALLIST_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP SendLocalList message
struct SendLocalListRequest : public ocpp::Message {
std::int32_t listVersion;
UpdateType updateType;
std::optional<std::vector<LocalAuthorizationList>> localAuthorizationList;
/// \brief Provides the type of this SendLocalList message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SendLocalListRequest \p k to a given json object \p j
void to_json(json& j, const SendLocalListRequest& k);
/// \brief Conversion from a given json object \p j to a given SendLocalListRequest \p k
void from_json(const json& j, SendLocalListRequest& k);
/// \brief Writes the string representation of the given SendLocalListRequest \p k to the given output stream \p os
/// \returns an output stream with the SendLocalListRequest written to
std::ostream& operator<<(std::ostream& os, const SendLocalListRequest& k);
/// \brief Contains a OCPP SendLocalListResponse message
struct SendLocalListResponse : public ocpp::Message {
UpdateStatus status;
/// \brief Provides the type of this SendLocalListResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SendLocalListResponse \p k to a given json object \p j
void to_json(json& j, const SendLocalListResponse& k);
/// \brief Conversion from a given json object \p j to a given SendLocalListResponse \p k
void from_json(const json& j, SendLocalListResponse& k);
/// \brief Writes the string representation of the given SendLocalListResponse \p k to the given output stream \p os
/// \returns an output stream with the SendLocalListResponse written to
std::ostream& operator<<(std::ostream& os, const SendLocalListResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SENDLOCALLIST_HPP

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_SETCHARGINGPROFILE_HPP
#define OCPP_V16_SETCHARGINGPROFILE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP SetChargingProfile message
struct SetChargingProfileRequest : public ocpp::Message {
std::int32_t connectorId;
ChargingProfile csChargingProfiles;
/// \brief Provides the type of this SetChargingProfile message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SetChargingProfileRequest \p k to a given json object \p j
void to_json(json& j, const SetChargingProfileRequest& k);
/// \brief Conversion from a given json object \p j to a given SetChargingProfileRequest \p k
void from_json(const json& j, SetChargingProfileRequest& k);
/// \brief Writes the string representation of the given SetChargingProfileRequest \p k to the given output stream \p os
/// \returns an output stream with the SetChargingProfileRequest written to
std::ostream& operator<<(std::ostream& os, const SetChargingProfileRequest& k);
/// \brief Contains a OCPP SetChargingProfileResponse message
struct SetChargingProfileResponse : public ocpp::Message {
ChargingProfileStatus status;
/// \brief Provides the type of this SetChargingProfileResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SetChargingProfileResponse \p k to a given json object \p j
void to_json(json& j, const SetChargingProfileResponse& k);
/// \brief Conversion from a given json object \p j to a given SetChargingProfileResponse \p k
void from_json(const json& j, SetChargingProfileResponse& k);
/// \brief Writes the string representation of the given SetChargingProfileResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the SetChargingProfileResponse written to
std::ostream& operator<<(std::ostream& os, const SetChargingProfileResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SETCHARGINGPROFILE_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_SIGNCERTIFICATE_HPP
#define OCPP_V16_SIGNCERTIFICATE_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP SignCertificate message
struct SignCertificateRequest : public ocpp::Message {
CiString<5500> csr;
/// \brief Provides the type of this SignCertificate message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SignCertificateRequest \p k to a given json object \p j
void to_json(json& j, const SignCertificateRequest& k);
/// \brief Conversion from a given json object \p j to a given SignCertificateRequest \p k
void from_json(const json& j, SignCertificateRequest& k);
/// \brief Writes the string representation of the given SignCertificateRequest \p k to the given output stream \p os
/// \returns an output stream with the SignCertificateRequest written to
std::ostream& operator<<(std::ostream& os, const SignCertificateRequest& k);
/// \brief Contains a OCPP SignCertificateResponse message
struct SignCertificateResponse : public ocpp::Message {
GenericStatusEnumType status;
/// \brief Provides the type of this SignCertificateResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SignCertificateResponse \p k to a given json object \p j
void to_json(json& j, const SignCertificateResponse& k);
/// \brief Conversion from a given json object \p j to a given SignCertificateResponse \p k
void from_json(const json& j, SignCertificateResponse& k);
/// \brief Writes the string representation of the given SignCertificateResponse \p k to the given output stream \p os
/// \returns an output stream with the SignCertificateResponse written to
std::ostream& operator<<(std::ostream& os, const SignCertificateResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SIGNCERTIFICATE_HPP

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_SIGNEDFIRMWARESTATUSNOTIFICATION_HPP
#define OCPP_V16_SIGNEDFIRMWARESTATUSNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP SignedFirmwareStatusNotification message
struct SignedFirmwareStatusNotificationRequest : public ocpp::Message {
FirmwareStatusEnumType status;
std::optional<std::int32_t> requestId;
/// \brief Provides the type of this SignedFirmwareStatusNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SignedFirmwareStatusNotificationRequest \p k to a given json object \p j
void to_json(json& j, const SignedFirmwareStatusNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given SignedFirmwareStatusNotificationRequest \p k
void from_json(const json& j, SignedFirmwareStatusNotificationRequest& k);
/// \brief Writes the string representation of the given SignedFirmwareStatusNotificationRequest \p k to the given
/// output stream \p os
/// \returns an output stream with the SignedFirmwareStatusNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const SignedFirmwareStatusNotificationRequest& k);
/// \brief Contains a OCPP SignedFirmwareStatusNotificationResponse message
struct SignedFirmwareStatusNotificationResponse : public ocpp::Message {
/// \brief Provides the type of this SignedFirmwareStatusNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SignedFirmwareStatusNotificationResponse \p k to a given json object \p j
void to_json(json& j, const SignedFirmwareStatusNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given SignedFirmwareStatusNotificationResponse \p k
void from_json(const json& j, SignedFirmwareStatusNotificationResponse& k);
/// \brief Writes the string representation of the given SignedFirmwareStatusNotificationResponse \p k to the given
/// output stream \p os
/// \returns an output stream with the SignedFirmwareStatusNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const SignedFirmwareStatusNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SIGNEDFIRMWARESTATUSNOTIFICATION_HPP

View File

@@ -0,0 +1,63 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_SIGNEDUPDATEFIRMWARE_HPP
#define OCPP_V16_SIGNEDUPDATEFIRMWARE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP SignedUpdateFirmware message
struct SignedUpdateFirmwareRequest : public ocpp::Message {
std::int32_t requestId;
FirmwareType firmware;
std::optional<std::int32_t> retries;
std::optional<std::int32_t> retryInterval;
/// \brief Provides the type of this SignedUpdateFirmware message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SignedUpdateFirmwareRequest \p k to a given json object \p j
void to_json(json& j, const SignedUpdateFirmwareRequest& k);
/// \brief Conversion from a given json object \p j to a given SignedUpdateFirmwareRequest \p k
void from_json(const json& j, SignedUpdateFirmwareRequest& k);
/// \brief Writes the string representation of the given SignedUpdateFirmwareRequest \p k to the given output stream \p
/// os
/// \returns an output stream with the SignedUpdateFirmwareRequest written to
std::ostream& operator<<(std::ostream& os, const SignedUpdateFirmwareRequest& k);
/// \brief Contains a OCPP SignedUpdateFirmwareResponse message
struct SignedUpdateFirmwareResponse : public ocpp::Message {
UpdateFirmwareStatusEnumType status;
/// \brief Provides the type of this SignedUpdateFirmwareResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given SignedUpdateFirmwareResponse \p k to a given json object \p j
void to_json(json& j, const SignedUpdateFirmwareResponse& k);
/// \brief Conversion from a given json object \p j to a given SignedUpdateFirmwareResponse \p k
void from_json(const json& j, SignedUpdateFirmwareResponse& k);
/// \brief Writes the string representation of the given SignedUpdateFirmwareResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the SignedUpdateFirmwareResponse written to
std::ostream& operator<<(std::ostream& os, const SignedUpdateFirmwareResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SIGNEDUPDATEFIRMWARE_HPP

View File

@@ -0,0 +1,64 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_STARTTRANSACTION_HPP
#define OCPP_V16_STARTTRANSACTION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP StartTransaction message
struct StartTransactionRequest : public ocpp::Message {
std::int32_t connectorId;
CiString<20> idTag;
std::int32_t meterStart;
ocpp::DateTime timestamp;
std::optional<std::int32_t> reservationId;
/// \brief Provides the type of this StartTransaction message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given StartTransactionRequest \p k to a given json object \p j
void to_json(json& j, const StartTransactionRequest& k);
/// \brief Conversion from a given json object \p j to a given StartTransactionRequest \p k
void from_json(const json& j, StartTransactionRequest& k);
/// \brief Writes the string representation of the given StartTransactionRequest \p k to the given output stream \p os
/// \returns an output stream with the StartTransactionRequest written to
std::ostream& operator<<(std::ostream& os, const StartTransactionRequest& k);
/// \brief Contains a OCPP StartTransactionResponse message
struct StartTransactionResponse : public ocpp::Message {
IdTagInfo idTagInfo;
std::int32_t transactionId;
/// \brief Provides the type of this StartTransactionResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given StartTransactionResponse \p k to a given json object \p j
void to_json(json& j, const StartTransactionResponse& k);
/// \brief Conversion from a given json object \p j to a given StartTransactionResponse \p k
void from_json(const json& j, StartTransactionResponse& k);
/// \brief Writes the string representation of the given StartTransactionResponse \p k to the given output stream \p os
/// \returns an output stream with the StartTransactionResponse written to
std::ostream& operator<<(std::ostream& os, const StartTransactionResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_STARTTRANSACTION_HPP

View File

@@ -0,0 +1,65 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_STATUSNOTIFICATION_HPP
#define OCPP_V16_STATUSNOTIFICATION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP StatusNotification message
struct StatusNotificationRequest : public ocpp::Message {
std::int32_t connectorId;
ChargePointErrorCode errorCode;
ChargePointStatus status;
std::optional<CiString<50>> info;
std::optional<ocpp::DateTime> timestamp;
std::optional<CiString<255>> vendorId;
std::optional<CiString<50>> vendorErrorCode;
/// \brief Provides the type of this StatusNotification message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given StatusNotificationRequest \p k to a given json object \p j
void to_json(json& j, const StatusNotificationRequest& k);
/// \brief Conversion from a given json object \p j to a given StatusNotificationRequest \p k
void from_json(const json& j, StatusNotificationRequest& k);
/// \brief Writes the string representation of the given StatusNotificationRequest \p k to the given output stream \p os
/// \returns an output stream with the StatusNotificationRequest written to
std::ostream& operator<<(std::ostream& os, const StatusNotificationRequest& k);
/// \brief Contains a OCPP StatusNotificationResponse message
struct StatusNotificationResponse : public ocpp::Message {
/// \brief Provides the type of this StatusNotificationResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given StatusNotificationResponse \p k to a given json object \p j
void to_json(json& j, const StatusNotificationResponse& k);
/// \brief Conversion from a given json object \p j to a given StatusNotificationResponse \p k
void from_json(const json& j, StatusNotificationResponse& k);
/// \brief Writes the string representation of the given StatusNotificationResponse \p k to the given output stream \p
/// os
/// \returns an output stream with the StatusNotificationResponse written to
std::ostream& operator<<(std::ostream& os, const StatusNotificationResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_STATUSNOTIFICATION_HPP

View File

@@ -0,0 +1,64 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_STOPTRANSACTION_HPP
#define OCPP_V16_STOPTRANSACTION_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP StopTransaction message
struct StopTransactionRequest : public ocpp::Message {
std::int32_t meterStop;
ocpp::DateTime timestamp;
std::int32_t transactionId;
std::optional<CiString<20>> idTag;
std::optional<Reason> reason;
std::optional<std::vector<TransactionData>> transactionData;
/// \brief Provides the type of this StopTransaction message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given StopTransactionRequest \p k to a given json object \p j
void to_json(json& j, const StopTransactionRequest& k);
/// \brief Conversion from a given json object \p j to a given StopTransactionRequest \p k
void from_json(const json& j, StopTransactionRequest& k);
/// \brief Writes the string representation of the given StopTransactionRequest \p k to the given output stream \p os
/// \returns an output stream with the StopTransactionRequest written to
std::ostream& operator<<(std::ostream& os, const StopTransactionRequest& k);
/// \brief Contains a OCPP StopTransactionResponse message
struct StopTransactionResponse : public ocpp::Message {
std::optional<IdTagInfo> idTagInfo;
/// \brief Provides the type of this StopTransactionResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given StopTransactionResponse \p k to a given json object \p j
void to_json(json& j, const StopTransactionResponse& k);
/// \brief Conversion from a given json object \p j to a given StopTransactionResponse \p k
void from_json(const json& j, StopTransactionResponse& k);
/// \brief Writes the string representation of the given StopTransactionResponse \p k to the given output stream \p os
/// \returns an output stream with the StopTransactionResponse written to
std::ostream& operator<<(std::ostream& os, const StopTransactionResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_STOPTRANSACTION_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_TRIGGERMESSAGE_HPP
#define OCPP_V16_TRIGGERMESSAGE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP TriggerMessage message
struct TriggerMessageRequest : public ocpp::Message {
MessageTrigger requestedMessage;
std::optional<std::int32_t> connectorId;
/// \brief Provides the type of this TriggerMessage message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given TriggerMessageRequest \p k to a given json object \p j
void to_json(json& j, const TriggerMessageRequest& k);
/// \brief Conversion from a given json object \p j to a given TriggerMessageRequest \p k
void from_json(const json& j, TriggerMessageRequest& k);
/// \brief Writes the string representation of the given TriggerMessageRequest \p k to the given output stream \p os
/// \returns an output stream with the TriggerMessageRequest written to
std::ostream& operator<<(std::ostream& os, const TriggerMessageRequest& k);
/// \brief Contains a OCPP TriggerMessageResponse message
struct TriggerMessageResponse : public ocpp::Message {
TriggerMessageStatus status;
/// \brief Provides the type of this TriggerMessageResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given TriggerMessageResponse \p k to a given json object \p j
void to_json(json& j, const TriggerMessageResponse& k);
/// \brief Conversion from a given json object \p j to a given TriggerMessageResponse \p k
void from_json(const json& j, TriggerMessageResponse& k);
/// \brief Writes the string representation of the given TriggerMessageResponse \p k to the given output stream \p os
/// \returns an output stream with the TriggerMessageResponse written to
std::ostream& operator<<(std::ostream& os, const TriggerMessageResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_TRIGGERMESSAGE_HPP

View File

@@ -0,0 +1,57 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_UNLOCKCONNECTOR_HPP
#define OCPP_V16_UNLOCKCONNECTOR_HPP
#include <nlohmann/json_fwd.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP UnlockConnector message
struct UnlockConnectorRequest : public ocpp::Message {
std::int32_t connectorId;
/// \brief Provides the type of this UnlockConnector message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given UnlockConnectorRequest \p k to a given json object \p j
void to_json(json& j, const UnlockConnectorRequest& k);
/// \brief Conversion from a given json object \p j to a given UnlockConnectorRequest \p k
void from_json(const json& j, UnlockConnectorRequest& k);
/// \brief Writes the string representation of the given UnlockConnectorRequest \p k to the given output stream \p os
/// \returns an output stream with the UnlockConnectorRequest written to
std::ostream& operator<<(std::ostream& os, const UnlockConnectorRequest& k);
/// \brief Contains a OCPP UnlockConnectorResponse message
struct UnlockConnectorResponse : public ocpp::Message {
UnlockStatus status;
/// \brief Provides the type of this UnlockConnectorResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given UnlockConnectorResponse \p k to a given json object \p j
void to_json(json& j, const UnlockConnectorResponse& k);
/// \brief Conversion from a given json object \p j to a given UnlockConnectorResponse \p k
void from_json(const json& j, UnlockConnectorResponse& k);
/// \brief Writes the string representation of the given UnlockConnectorResponse \p k to the given output stream \p os
/// \returns an output stream with the UnlockConnectorResponse written to
std::ostream& operator<<(std::ostream& os, const UnlockConnectorResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_UNLOCKCONNECTOR_HPP

View File

@@ -0,0 +1,59 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_UPDATEFIRMWARE_HPP
#define OCPP_V16_UPDATEFIRMWARE_HPP
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/v16/ocpp_types.hpp>
namespace ocpp {
namespace v16 {
/// \brief Contains a OCPP UpdateFirmware message
struct UpdateFirmwareRequest : public ocpp::Message {
std::string location;
ocpp::DateTime retrieveDate;
std::optional<std::int32_t> retries;
std::optional<std::int32_t> retryInterval;
/// \brief Provides the type of this UpdateFirmware message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given UpdateFirmwareRequest \p k to a given json object \p j
void to_json(json& j, const UpdateFirmwareRequest& k);
/// \brief Conversion from a given json object \p j to a given UpdateFirmwareRequest \p k
void from_json(const json& j, UpdateFirmwareRequest& k);
/// \brief Writes the string representation of the given UpdateFirmwareRequest \p k to the given output stream \p os
/// \returns an output stream with the UpdateFirmwareRequest written to
std::ostream& operator<<(std::ostream& os, const UpdateFirmwareRequest& k);
/// \brief Contains a OCPP UpdateFirmwareResponse message
struct UpdateFirmwareResponse : public ocpp::Message {
/// \brief Provides the type of this UpdateFirmwareResponse message as a human readable string
/// \returns the message type as a human readable string
std::string get_type() const override;
};
/// \brief Conversion from a given UpdateFirmwareResponse \p k to a given json object \p j
void to_json(json& j, const UpdateFirmwareResponse& k);
/// \brief Conversion from a given json object \p j to a given UpdateFirmwareResponse \p k
void from_json(const json& j, UpdateFirmwareResponse& k);
/// \brief Writes the string representation of the given UpdateFirmwareResponse \p k to the given output stream \p os
/// \returns an output stream with the UpdateFirmwareResponse written to
std::ostream& operator<<(std::ostream& os, const UpdateFirmwareResponse& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_UPDATEFIRMWARE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,214 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// This code is generated using the generator in 'src/code_generator/common`, please do not edit manually
#ifndef OCPP_V16_OCPP_TYPES_HPP
#define OCPP_V16_OCPP_TYPES_HPP
#include <string>
#include <nlohmann/json_fwd.hpp>
#include <optional>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
namespace ocpp {
namespace v16 {
struct IdTagInfo {
AuthorizationStatus status;
std::optional<ocpp::DateTime> expiryDate;
std::optional<CiString<20>> parentIdTag;
};
/// \brief Conversion from a given IdTagInfo \p k to a given json object \p j
void to_json(json& j, const IdTagInfo& k);
/// \brief Conversion from a given json object \p j to a given IdTagInfo \p k
void from_json(const json& j, IdTagInfo& k);
/// \brief Writes the string representation of the given IdTagInfo \p k to the given output stream \p os
/// \returns an output stream with the IdTagInfo written to
std::ostream& operator<<(std::ostream& os, const IdTagInfo& k);
struct CertificateHashDataType {
HashAlgorithmEnumType hashAlgorithm;
CiString<128> issuerNameHash;
CiString<128> issuerKeyHash;
CiString<40> serialNumber;
};
/// \brief Conversion from a given CertificateHashDataType \p k to a given json object \p j
void to_json(json& j, const CertificateHashDataType& k);
/// \brief Conversion from a given json object \p j to a given CertificateHashDataType \p k
void from_json(const json& j, CertificateHashDataType& k);
/// \brief Writes the string representation of the given CertificateHashDataType \p k to the given output stream \p os
/// \returns an output stream with the CertificateHashDataType written to
std::ostream& operator<<(std::ostream& os, const CertificateHashDataType& k);
struct ChargingSchedulePeriod {
std::int32_t startPeriod;
float limit;
std::optional<std::int32_t> numberPhases;
};
/// \brief Conversion from a given ChargingSchedulePeriod \p k to a given json object \p j
void to_json(json& j, const ChargingSchedulePeriod& k);
/// \brief Conversion from a given json object \p j to a given ChargingSchedulePeriod \p k
void from_json(const json& j, ChargingSchedulePeriod& k);
/// \brief Writes the string representation of the given ChargingSchedulePeriod \p k to the given output stream \p os
/// \returns an output stream with the ChargingSchedulePeriod written to
std::ostream& operator<<(std::ostream& os, const ChargingSchedulePeriod& k);
struct ChargingSchedule {
ChargingRateUnit chargingRateUnit;
std::vector<ChargingSchedulePeriod> chargingSchedulePeriod;
std::optional<std::int32_t> duration;
std::optional<ocpp::DateTime> startSchedule;
std::optional<float> minChargingRate;
};
/// \brief Conversion from a given ChargingSchedule \p k to a given json object \p j
void to_json(json& j, const ChargingSchedule& k);
/// \brief Conversion from a given json object \p j to a given ChargingSchedule \p k
void from_json(const json& j, ChargingSchedule& k);
/// \brief Writes the string representation of the given ChargingSchedule \p k to the given output stream \p os
/// \returns an output stream with the ChargingSchedule written to
std::ostream& operator<<(std::ostream& os, const ChargingSchedule& k);
struct KeyValue {
CiString<50> key;
bool readonly;
std::optional<CiString<500>> value;
};
/// \brief Conversion from a given KeyValue \p k to a given json object \p j
void to_json(json& j, const KeyValue& k);
/// \brief Conversion from a given json object \p j to a given KeyValue \p k
void from_json(const json& j, KeyValue& k);
/// \brief Writes the string representation of the given KeyValue \p k to the given output stream \p os
/// \returns an output stream with the KeyValue written to
std::ostream& operator<<(std::ostream& os, const KeyValue& k);
struct LogParametersType {
CiString<512> remoteLocation;
std::optional<ocpp::DateTime> oldestTimestamp;
std::optional<ocpp::DateTime> latestTimestamp;
};
/// \brief Conversion from a given LogParametersType \p k to a given json object \p j
void to_json(json& j, const LogParametersType& k);
/// \brief Conversion from a given json object \p j to a given LogParametersType \p k
void from_json(const json& j, LogParametersType& k);
/// \brief Writes the string representation of the given LogParametersType \p k to the given output stream \p os
/// \returns an output stream with the LogParametersType written to
std::ostream& operator<<(std::ostream& os, const LogParametersType& k);
struct SampledValue {
std::string value;
std::optional<ReadingContext> context;
std::optional<ValueFormat> format;
std::optional<Measurand> measurand;
std::optional<Phase> phase;
std::optional<Location> location;
std::optional<UnitOfMeasure> unit;
};
/// \brief Conversion from a given SampledValue \p k to a given json object \p j
void to_json(json& j, const SampledValue& k);
/// \brief Conversion from a given json object \p j to a given SampledValue \p k
void from_json(const json& j, SampledValue& k);
/// \brief Writes the string representation of the given SampledValue \p k to the given output stream \p os
/// \returns an output stream with the SampledValue written to
std::ostream& operator<<(std::ostream& os, const SampledValue& k);
struct MeterValue {
ocpp::DateTime timestamp;
std::vector<SampledValue> sampledValue;
};
/// \brief Conversion from a given MeterValue \p k to a given json object \p j
void to_json(json& j, const MeterValue& k);
/// \brief Conversion from a given json object \p j to a given MeterValue \p k
void from_json(const json& j, MeterValue& k);
/// \brief Writes the string representation of the given MeterValue \p k to the given output stream \p os
/// \returns an output stream with the MeterValue written to
std::ostream& operator<<(std::ostream& os, const MeterValue& k);
struct ChargingProfile {
std::int32_t chargingProfileId;
std::int32_t stackLevel;
ChargingProfilePurposeType chargingProfilePurpose;
ChargingProfileKindType chargingProfileKind;
ChargingSchedule chargingSchedule;
std::optional<std::int32_t> transactionId;
std::optional<RecurrencyKindType> recurrencyKind;
std::optional<ocpp::DateTime> validFrom;
std::optional<ocpp::DateTime> validTo;
};
/// \brief Conversion from a given ChargingProfile \p k to a given json object \p j
void to_json(json& j, const ChargingProfile& k);
/// \brief Conversion from a given json object \p j to a given ChargingProfile \p k
void from_json(const json& j, ChargingProfile& k);
/// \brief Writes the string representation of the given ChargingProfile \p k to the given output stream \p os
/// \returns an output stream with the ChargingProfile written to
std::ostream& operator<<(std::ostream& os, const ChargingProfile& k);
struct LocalAuthorizationList {
CiString<20> idTag;
std::optional<IdTagInfo> idTagInfo;
};
/// \brief Conversion from a given LocalAuthorizationList \p k to a given json object \p j
void to_json(json& j, const LocalAuthorizationList& k);
/// \brief Conversion from a given json object \p j to a given LocalAuthorizationList \p k
void from_json(const json& j, LocalAuthorizationList& k);
/// \brief Writes the string representation of the given LocalAuthorizationList \p k to the given output stream \p os
/// \returns an output stream with the LocalAuthorizationList written to
std::ostream& operator<<(std::ostream& os, const LocalAuthorizationList& k);
struct FirmwareType {
CiString<512> location;
ocpp::DateTime retrieveDateTime;
CiString<5500> signingCertificate;
CiString<800> signature;
std::optional<ocpp::DateTime> installDateTime;
};
/// \brief Conversion from a given FirmwareType \p k to a given json object \p j
void to_json(json& j, const FirmwareType& k);
/// \brief Conversion from a given json object \p j to a given FirmwareType \p k
void from_json(const json& j, FirmwareType& k);
/// \brief Writes the string representation of the given FirmwareType \p k to the given output stream \p os
/// \returns an output stream with the FirmwareType written to
std::ostream& operator<<(std::ostream& os, const FirmwareType& k);
struct TransactionData {
ocpp::DateTime timestamp;
std::vector<SampledValue> sampledValue;
};
/// \brief Conversion from a given TransactionData \p k to a given json object \p j
void to_json(json& j, const TransactionData& k);
/// \brief Conversion from a given json object \p j to a given TransactionData \p k
void from_json(const json& j, TransactionData& k);
/// \brief Writes the string representation of the given TransactionData \p k to the given output stream \p os
/// \returns an output stream with the TransactionData written to
std::ostream& operator<<(std::ostream& os, const TransactionData& k);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_OCPP_TYPES_HPP

View File

@@ -0,0 +1,108 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef PROFILE_H
#define PROFILE_H
#include <cstdint>
#include <optional>
#include <vector>
#include <ocpp/common/types.hpp>
namespace ocpp::v16 {
class ChargingProfile;
class EnhancedChargingSchedulePeriod;
class ChargingSchedulePeriod;
constexpr float no_limit_specified = -1.0;
using ocpp::DateTime;
struct IntermediatePeriod {
std::int32_t startPeriod;
float current_limit;
float power_limit;
std::int32_t stack_level_current;
std::int32_t stack_level_power;
std::optional<std::int32_t> numberPhases;
std::optional<std::int32_t> phaseToUse;
};
using IntermediateProfile = std::vector<IntermediatePeriod>;
struct period_entry_t {
void init(const DateTime& in_start, int in_duration, const ChargingSchedulePeriod& in_period,
const ChargingProfile& in_profile);
bool validate(const ChargingProfile& profile, const DateTime& now);
DateTime start;
DateTime end;
float limit;
std::optional<std::int32_t> number_phases;
std::int32_t stack_level;
ChargingRateUnit charging_rate_unit;
std::optional<float> min_charging_rate;
};
/// \brief Calculate the number of seconds elapsed between \param to and \param from
std::int32_t elapsed_seconds(const ocpp::DateTime& to, const ocpp::DateTime& from);
/// \brief Rounds down the \param dt to the nearest second
ocpp::DateTime floor_seconds(const ocpp::DateTime& dt);
std::vector<DateTime> calculate_start(const DateTime& now, const DateTime& end,
const std::optional<DateTime>& session_start, const ChargingProfile& profile);
std::vector<period_entry_t> calculate_profile_entry(const DateTime& now, const DateTime& end,
const std::optional<DateTime>& session_start,
const ChargingProfile& profile, std::size_t period_index);
std::vector<period_entry_t> calculate_profile(const DateTime& now, const DateTime& end,
const std::optional<DateTime>& session_start,
const ChargingProfile& profile);
/// \brief generate an ordered list of valid schedule periods for the profiles
/// \param now the current date and time
/// \param end ignore entries beyond this date and time (i.e. that start after end)
/// \param session_start optional when the charging session started
/// \param profiles A vector of charging profiles
/// \param purpose The purpose to generate the list for. Only profiles with this purpose are included.
/// \return a list of profile periods with calculated date & time start and end times
/// \note it is valid for there to be gaps (for recurring profiles)
std::vector<period_entry_t> calculate_all_profiles(const DateTime& now, const DateTime& end,
const std::optional<DateTime>& session_start,
const std::vector<ChargingProfile>& profiles,
ChargingProfilePurposeType purpose);
/// \brief generates an IntermediateProfile by sorting and processing a list of period_entry_t intervals within a given
/// time range, resolving overlaps based on stack priority and filling any time gaps with default values.
/// \param periods the list of periods to build into the profile
/// \param now the start of the composite schedule
/// \param end the end (i.e. duration) of the composite schedule \return a list of profile periods with calculated date
/// & time start and end times
IntermediateProfile generate_profile_from_periods(std::vector<period_entry_t>& periods, const DateTime& now,
const DateTime& end);
/// \brief Generates a new profile by combining a \param tx_profile and a \param tx_default_profile.
/// The tx_profile will be preferred over the tx_default_profile whenever it has a value
/// \return A combined profile
IntermediateProfile merge_tx_profile_with_tx_default_profile(const IntermediateProfile& tx_profile,
const IntermediateProfile& tx_default_profile);
/// \brief Generates a new profile by taking the lowest limit of all the provided \param profiles
IntermediateProfile merge_profiles_by_lowest_limit(const std::vector<IntermediateProfile>& profiles);
/// \brief Generates a new profile by summing the limits of all the provided \param profiles, filling in defaults
/// wherever a profile has no limit
IntermediateProfile merge_profiles_by_summing_limits(const std::vector<IntermediateProfile>& profiles,
float current_default, float power_default);
/// \brief Convert an intermediate profile into a final charging schedule.
/// This will fill in defaults and convert merge the current and power limits into the final \p charging_rate_unit based
/// limit
std::vector<EnhancedChargingSchedulePeriod>
convert_intermediate_into_schedule(const IntermediateProfile& profile, ChargingRateUnit charging_rate_unit,
float default_limit, std::int32_t default_number_phases, float supply_voltage);
} // namespace ocpp::v16
#endif // PROFILE_H

View File

@@ -0,0 +1,130 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_SMART_CHARGING_HPP
#define OCPP_V16_SMART_CHARGING_HPP
#include <cstddef>
#include <limits>
#include <ocpp/v16/charge_point_configuration_interface.hpp>
#include <ocpp/v16/connector.hpp>
#include <ocpp/v16/database_handler.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/transaction.hpp>
namespace ocpp {
namespace v16 {
const int DEFAULT_AND_MAX_NUMBER_PHASES = 3;
const int HOURS_PER_DAY = 24;
const int SECONDS_PER_HOUR = 3600;
const int SECONDS_PER_DAY = 86400;
const int DAYS_PER_WEEK = 7;
/// \brief Helper struct to calculate Composite Schedule
struct LimitStackLevelPair {
int limit;
int stack_level;
};
/// \brief Helper struct to calculate Composite Schedule
struct PeriodDateTimePair {
std::optional<ChargingSchedulePeriod> period;
ocpp::DateTime end_time;
};
/// \brief This class handles and maintains incoming ChargingProfiles and contains the logic
/// to calculate the composite schedules
class SmartChargingHandler {
private:
std::map<std::int32_t, std::shared_ptr<Connector>> connectors;
std::shared_ptr<ocpp::v16::DatabaseHandler> database_handler;
ChargePointConfigurationInterface& configuration;
std::map<int, ChargingProfile> stack_level_charge_point_max_profiles_map;
std::mutex charge_point_max_profiles_map_mutex;
std::mutex tx_default_profiles_map_mutex;
std::mutex tx_profiles_map_mutex;
std::unique_ptr<Everest::SteadyTimer> clear_profiles_timer;
bool clear_profiles(std::map<std::int32_t, ChargingProfile>& stack_level_profiles_map,
std::optional<int> profile_id_opt, std::optional<int> connector_id_opt, const int connector_id,
std::optional<int> stack_level_opt,
std::optional<ChargingProfilePurposeType> charging_profile_purpose_opt, bool check_id_only);
protected:
int get_number_installed_profiles();
void clear_expired_profiles(const date::utc_clock::time_point& now);
public:
SmartChargingHandler(std::map<std::int32_t, std::shared_ptr<Connector>>& connectors,
std::shared_ptr<DatabaseHandler> database_handler,
ChargePointConfigurationInterface& configuration);
///
/// \brief validates the given \p profile according to the specification
///
bool validate_profile(ChargingProfile& profile, const int connector_id, bool ignore_no_transaction,
const int profile_max_stack_level, const int max_charging_profiles_installed,
const int charging_schedule_max_periods,
const std::vector<ChargingRateUnit>& charging_schedule_allowed_charging_rate_units);
///
/// \brief Adds the given \p profile to the collection of stack_level_charge_point_max_profiles_map
///
void add_charge_point_max_profile(const ChargingProfile& profile);
///
/// \brief Adds the given \p profile to the collection of stack_level_tx_default_profiles_map of the respective
/// connector or to all connectors if \p connector_id is 0
///
void add_tx_default_profile(const ChargingProfile& profile, const int connector_id);
///
/// \brief Adds the given \p profile to the collection of stack_level_tx_profiles_map of the respective
/// connector
///
void add_tx_profile(const ChargingProfile& profile, const int connector_id);
///
/// \brief Clears all charging profiles using optional filters
///
bool clear_all_profiles_with_filter(std::optional<int> profile_id, std::optional<int> connector_id,
std::optional<int> stack_level,
std::optional<ChargingProfilePurposeType> charging_profile_purpose,
bool check_id_only);
///
/// \brief Clears all present profiles from all collections
///
void clear_all_profiles();
///
/// \brief Gets all valid profiles within the given absoulte \p start_time and absolute \p end_time for the given
/// \p connector_id . Only profiles that are not contained in \p purposes_to_ignore are included in the response.
///
std::vector<ChargingProfile>
get_valid_profiles(const ocpp::DateTime& start_time, const ocpp::DateTime& end_time, const int connector_id,
const std::set<ChargingProfilePurposeType>& purposes_to_ignore = {});
///
/// \brief Calculates the enhanced composite schedule for the given \p valid_profiles and the given \p connector_id
///
EnhancedChargingSchedule calculate_enhanced_composite_schedule(const ocpp::DateTime& start_time,
const ocpp::DateTime& end_time,
const std::int32_t evse_id,
ChargingRateUnit charging_rate_unit, bool is_offline,
bool simulate_transaction_active);
ChargingSchedule calculate_composite_schedule(const ocpp::DateTime& start_time, const ocpp::DateTime& end_time,
const std::int32_t evse_id, ChargingRateUnit charging_rate_unit,
bool is_offline, bool simulate_transaction_active);
};
bool validate_schedule(const ChargingSchedule& schedule, const int charging_schedule_max_periods,
const std::vector<ChargingRateUnit>& charging_schedule_allowed_charging_rate_units);
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_SMART_CHARGING_HPP

View File

@@ -0,0 +1,218 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_TRANSACTION_HPP
#define OCPP_V16_TRANSACTION_HPP
#include <memory>
#include <random>
#include <everest/timer.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/types.hpp>
namespace ocpp {
namespace v16 {
/// \brief A structure that contains a energy value in Wh that can be used for start/stop energy values and a
/// corresponding timestamp
struct StampedEnergyWh {
ocpp::DateTime timestamp; ///< A timestamp associated with the energy value
double energy_Wh; ///< The energy value in Wh
StampedEnergyWh(ocpp::DateTime timestamp, double energy_Wh) : timestamp(timestamp), energy_Wh(energy_Wh) {
}
};
/// \brief Contains all transaction related data, such as the ID and power meter values
class Transaction {
private:
std::optional<std::int32_t> transaction_id;
std::int32_t internal_transaction_id;
std::int32_t connector;
std::string session_id;
CiString<20> id_token;
std::shared_ptr<StampedEnergyWh> start_energy_wh;
std::optional<std::int32_t> reservation_id;
bool active;
bool finished;
bool has_signed_meter_values;
std::unique_ptr<Everest::SteadyTimer> meter_values_sample_timer;
std::string start_transaction_message_id;
std::string stop_transaction_message_id;
std::shared_ptr<StampedEnergyWh> stop_energy_wh;
std::mutex meter_values_mutex;
std::vector<MeterValue> meter_values;
public:
/// \brief Creates a new Transaction object, taking ownership of the provided \p meter_values_sample_timer
/// on the provided \p connector
Transaction(const std::int32_t transaction_id, const std::int32_t& connector, const std::string& session_id,
const CiString<20>& id_token, const double meter_start, std::optional<std::int32_t> reservation_id,
const ocpp::DateTime& timestamp, std::unique_ptr<Everest::SteadyTimer> meter_values_sample_timer);
/// \brief Provides the energy in Wh at the start of the transaction
/// \returns the energy in Wh combined with a timestamp
std::shared_ptr<StampedEnergyWh> get_start_energy_wh();
/// \brief Adds the energy in Wh \p stop_energy_wh to the transaction. This also
/// stops the collection of further meter values.
void add_stop_energy_wh(std::shared_ptr<StampedEnergyWh> stop_energy_wh);
/// \brief Provides the energy in Wh at the end of the transaction
/// \returns the energy in Wh combined with a timestamp
std::shared_ptr<StampedEnergyWh> get_stop_energy_wh();
/// \brief Provides the reservation id of the transaction if present
/// \returns the reservation id
std::optional<std::int32_t> get_reservation_id();
/// \brief Provides the connector of this transaction
/// \returns the connector
std::int32_t get_connector() const;
/// \brief Provides the authorized id tag of this Transaction
/// \returns the authorized id tag
CiString<20> get_id_tag();
/// \brief Adds the provided \p meter_value to a chronological list of powermeter values
void add_meter_value(MeterValue meter_value);
/// \brief Provides all recorded powermeter values
/// \returns a vector of powermeter values
std::vector<MeterValue> get_meter_values();
/// \brief Changes the sample \p interval of the powermeter values sampling timer
/// \returns true if successful
bool change_meter_values_sample_interval(std::int32_t interval);
/// \brief Adds the provided \p meter_value to a chronological list of clock aligned powermeter values
void add_clock_aligned_meter_value(MeterValue meter_value);
/// \brief Provides the id of this transaction
/// \returns the transaction id
std::optional<std::int32_t> get_transaction_id();
/// \brief Returns the internal transaction id
std::int32_t get_internal_transaction_id() const;
/// \brief Provides the id of this session
/// \returns the session_id
std::string get_session_id();
/// \brief Sets the start transaction message id using the provides \p message_id
void set_start_transaction_message_id(const std::string& message_id);
/// \brief Provides the start transaction message id
std::string get_start_transaction_message_id();
/// \brief Sets the stop transaction message id using the provides \p message_id
void set_stop_transaction_message_id(const std::string& message_id);
/// \brief Provides the stop transaction message id
std::string get_stop_transaction_message_id();
/// \brief Sets the transaction id
void set_transaction_id(std::int32_t transaction_id);
/// \brief Provides all recorded sampled and clock aligned powermeter values
/// \returns a vector of sampled and clock aligned powermeter values packaged into a TransactionData object
std::vector<TransactionData> get_transaction_data();
/// \brief Marks the transaction as stopped/inactive
void stop();
/// \brief Indicates if the transaction is active. Active means that the transaction for this session is not null
/// and no StopTransaction.req has been pushed to the message queue yet
bool is_active() const;
/// \brief Indicates if a StopTransaction.req for this transaction has already been pushed to the message queue
bool is_finished() const;
/// \brief Sets the finished flag for this transaction. This is done when a StopTransaction.req has been pushed to
/// the message queue
void set_finished();
/// \brief Sets the has_signed_meter_value flag for this transaction, this function is called
/// from \p on_transaction_started and \p on_transaction_stopped
void set_has_signed_meter_values();
/// \brief Indicates if this transaction has signed meter values or not, this function is called
/// from \p on_transaction_started and \p on_transaction_stopped
/// \returns a boolean value indicating if this transaction has signed meter values or not
bool get_has_signed_meter_values();
};
/// \brief Contains transactions for all available connectors and manages access to these transactions
class TransactionHandler {
private:
std::mutex active_transactions_mutex;
// size is equal to the number of connectors
std::int32_t number_of_connectors;
std::vector<std::shared_ptr<Transaction>> active_transactions;
// size does not depend on the number of connectors
std::vector<std::shared_ptr<Transaction>> stopped_transactions;
std::mt19937 gen;
std::uniform_int_distribution<std::int32_t> distr;
public:
/// \brief Creates and manages transactions for the provided \p number_of_connectors
explicit TransactionHandler(std::int32_t number_of_connectors);
/// \brief Returns a negative random transaction_id
std::int32_t get_negative_random_transaction_id();
/// \brief Adds the given \p transaction the vector of transactions
void add_transaction(std::shared_ptr<Transaction> transaction);
/// \brief Adds the transaction at the \p connector to the vector of stopped transactions
void add_stopped_transaction(std::int32_t connector);
/// \brief Removes a transaction from the provided \p connector
/// \returns true if successful
bool remove_active_transaction(std::int32_t connector);
/// \brief Erases a transaction with the provided \p stop_transaction_message_id
void erase_stopped_transaction(std::string stop_transaction_message_id);
/// \brief Returns the transaction associated with the transaction at the provided \p connector
/// \returns The associated transaction if available or nullptr if not
std::shared_ptr<Transaction> get_transaction(std::int32_t connector);
/// \brief Returns the transaction associated with the transaction with the provided
/// \p start_transaction_message_id
/// \returns The associated transaction if available or nullptr if not
std::shared_ptr<Transaction> get_transaction(const std::string& start_transaction_message_id);
///
/// \brief Returns the transaction associated with the given id tag.
/// \param id_tag The id tag.
/// \return The associated transaction if available.
///
std::shared_ptr<Transaction> get_transaction_from_id_tag(const std::string& id_tag);
/// \brief Provides the connector on which a transaction with the given \p transaction_id is running
/// \returns The connector or -1 if the transaction_id is unknown
std::int32_t get_connector_from_transaction_id(std::int32_t transaction_id);
/// \brief Adds a clock aligned \p meter_value to the transaction on the provided \p connector
void add_meter_value(std::int32_t connector, const MeterValue& meter_value);
/// \brief Modifies the sample interval of the meter values sample timer on all connectors. The
/// provided \p interval is expected to be given in seconds.
void change_meter_values_sample_intervals(std::int32_t interval);
// \brief Provides the IdTag that was associated with the transaction with the provided
/// \p stop_transaction_message_id
/// \returns the IdTag if it is available, std::nullopt otherwise
std::optional<CiString<20>> get_authorized_id_tag(const std::string& stop_transaction_message_id);
/// \brief Indicates if there is an active transaction at the proveded \p connector
/// \returns true if a transaction exists
bool transaction_active(std::int32_t connector);
};
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_TRANSACTION_HPP

View File

@@ -0,0 +1,245 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V16_TYPES_HPP
#define OCPP_V16_TYPES_HPP
#include <iostream>
#include <sstream>
#include <string_view>
#include <nlohmann/json_fwd.hpp>
#include <everest/logging.hpp>
#include <ocpp/common/types.hpp>
#include <ocpp/v16/ocpp_enums.hpp>
#include <ocpp/v16/ocpp_types.hpp>
using json = nlohmann::json;
namespace ocpp {
namespace v16 {
/// \brief Contains all supported OCPP 1.6 message types
enum class MessageType {
Authorize,
AuthorizeResponse,
BootNotification,
BootNotificationResponse,
CancelReservation,
CancelReservationResponse,
CertificateSigned,
CertificateSignedResponse,
ChangeAvailability,
ChangeAvailabilityResponse,
ChangeConfiguration,
ChangeConfigurationResponse,
ClearCache,
ClearCacheResponse,
ClearChargingProfile,
ClearChargingProfileResponse,
DataTransfer,
DataTransferResponse,
DeleteCertificate,
DeleteCertificateResponse,
DiagnosticsStatusNotification,
DiagnosticsStatusNotificationResponse,
ExtendedTriggerMessage,
ExtendedTriggerMessageResponse,
FirmwareStatusNotification,
FirmwareStatusNotificationResponse,
GetCompositeSchedule,
GetCompositeScheduleResponse,
GetConfiguration,
GetConfigurationResponse,
GetDiagnostics,
GetDiagnosticsResponse,
GetInstalledCertificateIds,
GetInstalledCertificateIdsResponse,
GetLocalListVersion,
GetLocalListVersionResponse,
GetLog,
GetLogResponse,
Heartbeat,
HeartbeatResponse,
InstallCertificate,
InstallCertificateResponse,
LogStatusNotification,
LogStatusNotificationResponse,
MeterValues,
MeterValuesResponse,
RemoteStartTransaction,
RemoteStartTransactionResponse,
RemoteStopTransaction,
RemoteStopTransactionResponse,
ReserveNow,
ReserveNowResponse,
Reset,
ResetResponse,
SecurityEventNotification,
SecurityEventNotificationResponse,
SendLocalList,
SendLocalListResponse,
SetChargingProfile,
SetChargingProfileResponse,
SignCertificate,
SignCertificateResponse,
SignedFirmwareStatusNotification,
SignedFirmwareStatusNotificationResponse,
SignedUpdateFirmware,
SignedUpdateFirmwareResponse,
StartTransaction,
StartTransactionResponse,
StatusNotification,
StatusNotificationResponse,
StopTransaction,
StopTransactionResponse,
TriggerMessage,
TriggerMessageResponse,
UnlockConnector,
UnlockConnectorResponse,
UpdateFirmware,
UpdateFirmwareResponse,
InternalError, // not in spec, for internal use
};
namespace conversions {
/// \brief Converts the given MessageType \p m to std::string
/// \returns a string representation of the MessageType
std::string messagetype_to_string(MessageType m);
/// \brief Converts the given std::string \p s to MessageType
/// \returns a MessageType from a string representation
MessageType string_to_messagetype(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given \p message_type to the given output stream \p os
/// \returns an output stream with the MessageType written to
std::ostream& operator<<(std::ostream& os, const MessageType& message_type);
/// \brief Contains the supported OCPP 1.6 feature profiles
enum class SupportedFeatureProfiles {
Internal,
Core,
CostAndPrice,
FirmwareManagement,
LocalAuthListManagement,
Reservation,
SmartCharging,
RemoteTrigger,
Security,
PnC,
Custom
};
namespace conversions {
/// \brief Converts the given SupportedFeatureProfiles \p e to std::string
/// \returns a string representation of the SupportedFeatureProfiles
std::string supported_feature_profiles_to_string(SupportedFeatureProfiles e);
/// \brief Converts the given std::string \p s to SupportedFeatureProfiles
/// \returns a SupportedFeatureProfiles from a string representation
SupportedFeatureProfiles string_to_supported_feature_profiles(const std::string_view& s);
} // namespace conversions
/// \brief Writes the string representation of the given \p supported_feature_profiles to the given output stream \p os
/// \returns an output stream with the SupportedFeatureProfiles written to
std::ostream& operator<<(std::ostream& os, const SupportedFeatureProfiles& supported_feature_profiles);
/// \brief Contains the different connection states of the charge point
enum class ChargePointConnectionState {
Disconnected, // state when disconnected
Connected, // state when ws is connected
Booted, // state when ws is connected and BootNotifcation had been Accepted
Pending, // state when ws is connected and state when BootNotifcation is Pending
Rejected, // state when ws is connected and state when BootNotifcation had been Rejected
};
namespace conversions {
/// \brief Converts the given ChargePointConnectionState \p e to std::string
/// \returns a string representation of the ChargePointConnectionState
std::string charge_point_connection_state_to_string(ChargePointConnectionState e);
/// \brief Converts the given std::string \p s to ChargePointConnectionState
/// \returns a ChargePointConnectionState from a string representation
ChargePointConnectionState string_to_charge_point_connection_state(const std::string& s);
} // namespace conversions
/// \brief Writes the string representation of the given \p charge_point_connection_state
/// to the given output stream \p os \returns an output stream with the ChargePointConnectionState written to
std::ostream& operator<<(std::ostream& os, const ChargePointConnectionState& charge_point_connection_state);
/// \brief Combines a Measurand with an optional Phase
struct MeasurandWithPhase {
Measurand measurand; ///< A OCPP Measurand
std::optional<Phase> phase; ///< If applicable and available a Phase
/// \brief Comparison operator== between this MeasurandWithPhase and the given \p measurand_with_phase
/// \returns true when measurand and phase are equal
bool operator==(MeasurandWithPhase measurand_with_phase);
};
/// \brief Combines a Measurand with a list of Phases
struct MeasurandWithPhases {
Measurand measurand; ///< A OCPP Measurand
std::vector<Phase> phases; ///< A list of Phases
};
/// \brief Combines AvailabilityType with persist flag for scheduled Availability changes
struct AvailabilityChange {
AvailabilityType availability;
bool persist;
};
/// \brief BootReasonEnum contains the different boot reasons of the charge point (copied from OCPP2.0.1 definition)
enum class BootReasonEnum {
ApplicationReset,
FirmwareUpdate,
LocalReset,
PowerUp,
RemoteReset,
ScheduledReset,
Triggered,
Unknown,
Watchdog
};
/// \brief Enhances ChargingSchedulePeriod with stackLevel
struct EnhancedChargingSchedulePeriod {
std::int32_t startPeriod;
float limit;
std::optional<std::int32_t> numberPhases;
std::int32_t stackLevel;
bool periodTransformed = false; // indicates that a period was transformed from chargingRateUnit
};
/// \brief Conversion from a given EnhancedChargingSchedulePeriod \p k to a given json object \p j
void to_json(json& j, const EnhancedChargingSchedulePeriod& k);
/// \brief Conversion from a given json object \p j to a given EnhancedChargingSchedulePeriod \p k
void from_json(const json& j, EnhancedChargingSchedulePeriod& k);
/// \brief Enhances ChargingSchedule by containing std::vector<EnhancedChargingSchedulePeriods> instead of
/// std::vector<ChargingSchedulePeriod>
struct EnhancedChargingSchedule {
ChargingRateUnit chargingRateUnit;
std::vector<EnhancedChargingSchedulePeriod> chargingSchedulePeriod;
std::optional<std::int32_t> duration;
std::optional<ocpp::DateTime> startSchedule;
std::optional<float> minChargingRate;
};
/// \brief Conversion from a given EnhancedChargingSchedule \p k to a given json object \p j
void to_json(json& j, const EnhancedChargingSchedule& k);
/// \brief Conversion from a given json object \p j to a given EnhancedChargingSchedule \p k
void from_json(const json& j, EnhancedChargingSchedule& k);
/// \brief Extends the IdTagInfo with an optional TariffMessage for california pricing
struct EnhancedIdTagInfo {
IdTagInfo id_tag_info;
std::optional<TariffMessage> tariff_message;
};
} // namespace v16
} // namespace ocpp
#endif // OCPP_V16_TYPES_HPP

View File

@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#ifndef V16_UTILS_HPP
#define V16_UTILS_HPP
#include <ocpp/common/call_types.hpp>
#include <ocpp/v16/messages/StopTransaction.hpp>
#include <ocpp/v16/ocpp_types.hpp>
#include <ocpp/v16/types.hpp>
#include <cstddef>
#include <map>
#include <string>
#include <vector>
namespace ocpp::v16::utils {
size_t get_message_size(const ocpp::Call<StopTransactionRequest>& call);
/// \brief Drops every second entry from transactionData as long as the message size of the \p call is greater than the
/// \p max_message_size
void drop_transaction_data(size_t max_message_size, ocpp::Call<StopTransactionRequest>& call);
/// \brief Determines if a given \p security_event is critical as defined in the OCPP 1.6 security whitepaper
bool is_critical(const std::string& security_event);
/// \brief split a string into a vector of strings
/// \note will contain empty strings where a separator is repeated
std::vector<std::string> split_string(char separator, const std::string& csl);
/// \brief convert a vector into a comma separated list in a string
std::string to_csl(const std::vector<std::string>& vec);
/// \brief convert a comma separated list in a string to a vector of strings
/// \note will not contain empty strings when a comma is repeated
std::vector<std::string> from_csl(const std::string& csl);
/// \brief List that maintains insertion order and prevents duplicates
class OrderedUniqueStringList {
private:
using Store = std::map<std::string, std::size_t>;
std::size_t count{0};
Store list{};
void do_insert(std::string&& s);
public:
/// \brief Add to list assuming not a duplicate
/// \param s - the string to add
void insert(const std::string& s) {
do_insert(std::string{s});
}
/// \brief Add to list assuming not a duplicate
/// \param s - the string to add
void insert(std::string&& s) {
do_insert(std::move(s));
}
/// \brief Clear the list
void clear() {
count = 0;
list.clear();
}
/// \brief obtain an ordered vector of the unique strings
std::vector<std::string> get() const;
/// \brief is the list empty
/// \returns true when empty
bool empty() const {
return list.empty();
}
/// \brief how many strings are in the list
/// \returns the size of the list
auto size() const {
return list.size();
}
};
} // namespace ocpp::v16::utils
#endif

View File

@@ -0,0 +1,53 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include <everest/logging.hpp>
#include <everest/timer.hpp>
#include <ocpp/common/types.hpp>
#include <ocpp/v2/ocpp_enums.hpp>
#include <ocpp/v2/ocpp_types.hpp>
#include <ocpp/v2/types.hpp>
#include <ocpp/v2/utils.hpp>
#include <vector>
namespace ocpp {
namespace v2 {
class AverageMeterValues {
public:
AverageMeterValues() = default;
/// @brief Set the meter values into the local object for processing
/// @param meter_value MeterValue
void set_values(const MeterValue& meter_value);
/// @brief retrive the processed values
/// @return MeterValue type
MeterValue retrieve_processed_values();
/// @brief Manually clear the local object meter values
void clear_values();
private:
struct MeterValueCalc {
double sum;
int num_elements;
};
struct MeterValueMeasurands {
MeasurandEnum measurand;
std::optional<PhaseEnum> phase; // measurand may or may not have a phase field
std::optional<LocationEnum> location; // measurand may or may not have location field
// Define a comparison operator for the struct
bool operator<(const MeterValueMeasurands& other) const {
// Using tie here to compare the two lexicographically instead of writing it all out
return std::tie(measurand, location, phase) < std::tie(other.measurand, other.location, other.phase);
}
};
MeterValue averaged_meter_values;
std::mutex avg_meter_value_mutex;
std::map<MeterValueMeasurands, MeterValueCalc> aligned_meter_values;
void average_meter_value();
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,709 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <future>
#include <memory>
#include <set>
#include <ocpp/common/message_dispatcher.hpp>
#include <ocpp/common/charging_station_base.hpp>
#include <ocpp/v2/average_meter_values.hpp>
#include <ocpp/v2/charge_point_callbacks.hpp>
#include <ocpp/v2/ocpp_enums.hpp>
#include <ocpp/v2/ocpp_types.hpp>
#include <ocpp/v2/ocsp_updater.hpp>
#include <ocpp/v2/types.hpp>
#include <ocpp/v2/utils.hpp>
#include <ocpp/v2/messages/Authorize.hpp>
#include <ocpp/v2/messages/ChangeAvailability.hpp>
#include <ocpp/v2/messages/DataTransfer.hpp>
#include <ocpp/v2/messages/Get15118EVCertificate.hpp>
#include <ocpp/v2/messages/GetCompositeSchedule.hpp>
#include <ocpp/v2/messages/NotifyEVChargingNeeds.hpp>
#include "component_state_manager.hpp"
namespace ocpp {
namespace v21 {
class DERControlInterface;
} // namespace v21
namespace v2 {
class AuthorizationInterface;
class AvailabilityInterface;
class DataTransferInterface;
class DiagnosticsInterface;
class DisplayMessageInterface;
class FirmwareUpdateInterface;
class MeterValuesInterface;
class ProvisioningInterface;
class RemoteTransactionControlInterface;
class ReservationInterface;
class SecurityInterface;
class SmartChargingInterface;
class TariffAndCostInterface;
class TransactionInterface;
class BidirectionalInterface;
class DatabaseHandler;
class DeviceModelAbstract;
class DeviceModelStorageInterface;
class EvseManager;
struct FunctionalBlockContext;
class UnexpectedMessageTypeFromCSMS : public std::runtime_error {
using std::runtime_error::runtime_error;
};
/// \brief Interface class for OCPP2.0.1 Charging Station
class ChargePointInterface {
public:
virtual ~ChargePointInterface() = default;
/// \brief Starts the ChargePoint, initializes and connects to the Websocket endpoint
/// \param bootreason Optional bootreason (default: PowerUp).
/// \param start_connecting Optional, set to false to initialize but not start connecting. Otherwise will connect to
/// the first network profile. (default: true)
virtual void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool start_connecting = true) = 0;
/// \brief Stops the ChargePoint. Disconnects the websocket connection and stops MessageQueue and all timers
virtual void stop() = 0;
/// \brief Initializes the websocket and connects to a CSMS. Provide a network_profile_slot to connect to that
/// specific slot.
///
/// \param network_profile_slot Optional slot to use when connecting. std::nullopt means the slot will be determined
/// automatically.
virtual void connect_websocket(std::optional<std::int32_t> network_profile_slot = std::nullopt) = 0;
/// \brief Disconnects the the websocket connection to the CSMS if it is connected
virtual void disconnect_websocket() = 0;
/// \addtogroup ocpp201_handlers OCPP 2.0.1 handlers
/// Handlers that can be called from the implementing class
/// @{
/// @name Handlers
/// The handlers
/// @{
///
/// \brief Shall be called when a websocket connection has been established in case the connectivity_handler is
/// provided exernally.
/// \param configuration_slot The network profile slot used for the connection.
/// \param network_connection_profile The network connection profile used for the connection.
virtual void on_websocket_connected(const int configuration_slot,
const NetworkConnectionProfile& network_connection_profile,
const OcppProtocolVersion ocpp_version) = 0;
///
/// \brief Shall be called when a websocket connection has been disconnected in case the connectivity_handler is
/// provided externally.
/// \param configuration_slot The network profile slot used for the connection.
/// \param network_connection_profile The network connection profile used for the connection.
virtual void on_websocket_disconnected(const int configuration_slot,
const NetworkConnectionProfile& network_connection_profile) = 0;
/// \brief Shall be called when a websocket connection attempt has failed in case the connectivity_handler is
/// provided externally.
/// \param reason The reason why the connection failed.
virtual void on_websocket_connection_failed(ConnectionFailedReason reason) = 0;
///
/// \brief Can be called when a network is disconnected, for example when an ethernet cable is removed.
///
/// This is introduced because the websocket can take several minutes to timeout when a network interface becomes
/// unavailable, whereas the system can detect this sooner.
///
/// \param ocpp_interface The interface that is disconnected.
///
virtual void on_network_disconnected(OCPPInterfaceEnum ocpp_interface) = 0;
/// \brief Chargepoint notifies about new firmware update status firmware_update_status. This function should be
/// called during a Firmware Update to indicate the current firmware_update_status.
/// \param request_id The request_id. When it is -1, it will not be included in the request.
/// \param firmware_update_status The firmware_update_status
virtual void on_firmware_update_status_notification(std::int32_t request_id,
const FirmwareStatusEnum& firmware_update_status) = 0;
/// \brief Event handler that should be called when a session has started
/// \param evse_id
/// \param connector_id
virtual void on_session_started(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
/// \brief Event handler that should be called when the EV sends a certificate request (for update or installation)
/// \param request
virtual Get15118EVCertificateResponse
on_get_15118_ev_certificate_request(const Get15118EVCertificateRequest& request) = 0;
/// \brief Event handler that should be called when a transaction has started
/// \param evse_id
/// \param connector_id
/// \param session_id
/// \param timestamp
/// \param trigger_reason
/// \param meter_start
/// \param id_token
/// \param group_id_token Optional group id token
/// \param reservation_id
/// \param remote_start_id
/// \param charging_state The new charging state
virtual void on_transaction_started(const std::int32_t evse_id, const std::int32_t connector_id,
const std::string& session_id, const DateTime& timestamp,
const TriggerReasonEnum trigger_reason, const MeterValue& meter_start,
const std::optional<IdToken>& id_token,
const std::optional<IdToken>& group_id_token,
const std::optional<std::int32_t>& reservation_id,
const std::optional<std::int32_t>& remote_start_id,
const ChargingStateEnum charging_state) = 0;
/// \brief Event handler that should be called when a transaction has finished
/// \param evse_id
/// \param timestamp
/// \param meter_stop
/// \param reason
/// \param id_token
/// \param signed_meter_value
/// \param charging_state
virtual void on_transaction_finished(const std::int32_t evse_id, const DateTime& timestamp,
const MeterValue& meter_stop, const ReasonEnum reason,
const TriggerReasonEnum trigger_reason, const std::optional<IdToken>& id_token,
const std::optional<std::string>& signed_meter_value,
const ChargingStateEnum charging_state) = 0;
/// \brief Event handler that should be called when a session has finished
/// \param evse_id
/// \param connector_id
virtual void on_session_finished(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
/// \brief Event handler that should be called when the given \p id_token is authorized
virtual void on_authorized(const std::int32_t evse_id, const std::int32_t connector_id,
const IdToken& id_token) = 0;
/// \brief Event handler that should be called when a new meter value is present
/// \param evse_id
/// \param meter_value
virtual void on_meter_value(const std::int32_t evse_id, const MeterValue& meter_value) = 0;
/// \brief Event handler that should be called when the connector on the given \p evse_id and \p connector_id
/// becomes unavailable
virtual void on_unavailable(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
/// \brief Event handler that should be called when the connector returns from unavailable on the given \p evse_id
/// and \p connector_id .
virtual void on_enabled(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
/// \brief Event handler that should be called when the connector on the given evse_id and connector_id is faulted.
/// \param evse_id Faulted EVSE id
/// \param connector_id Faulted connector id
virtual void on_faulted(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
/// \brief Event handler that should be called when the fault on the connector on the given evse_id is cleared.
/// \param evse_id EVSE id where fault was cleared
/// \param connector_id Connector id where fault was cleared
virtual void on_fault_cleared(const std::int32_t evse_id, const std::int32_t connector_id) = 0;
/// \brief Event handler that should be called when the connector on the given evse_id and connector_id is reserved.
/// \param evse_id Reserved EVSE id
/// \param connector_id Reserved connector id
virtual void on_reserved(const std::int32_t evse_id, const std::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 std::int32_t evse_id, const std::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.
/// \param trigger_reason The trigger reason of the event. Defaults to ChargingStateChanged
/// \return True on success. False if evse id does not exist.
virtual bool
on_charging_state_changed(const std::uint32_t evse_id, const ChargingStateEnum charging_state,
const TriggerReasonEnum trigger_reason = TriggerReasonEnum::ChargingStateChanged) = 0;
/// \brief Event handler that will update the charging station availability
/// \param request The request
/// \return returns a ChangeAvailabilityResponse
virtual ChangeAvailabilityResponse on_change_availability(const ChangeAvailabilityRequest& request) = 0;
/// \brief Gets the transaction id for a certain \p evse_id if there is an active transaction
/// \param evse_id The evse to get the transaction for
/// \return The transaction id if a transaction is active, otherwise nullopt
virtual std::optional<std::string> get_evse_transaction_id(std::int32_t evse_id) = 0;
/// \brief Event handler that can be called to trigger a NotifyEvent.req with the given \p events
/// \param events
virtual void on_event(const std::vector<EventData>& events) = 0;
///
/// \brief Event handler that can be called to notify about the log status.
///
/// This function should be called curing a Diagnostics / Log upload to indicate the current log status.
///
/// \param status Log status.
/// \param requestId Request id that was provided in GetLogRequest.
///
virtual void on_log_status_notification(UploadLogStatusEnum status, std::int32_t requestId) = 0;
// \brief Notifies chargepoint that a SecurityEvent has occured. This will send a SecurityEventNotification.req to
// the
/// CSMS
/// \param type type of the security event
/// \param tech_info additional info of the security event
/// \param critical if set this overwrites the default criticality recommended in the OCPP 2.0.1 appendix. A
/// critical security event is transmitted as a message to the CSMS, a non-critical one is just written to the
/// security log
/// \param timestamp when this security event occured, if absent the current datetime is assumed
virtual void on_security_event(const CiString<50>& event_type, const std::optional<CiString<255>>& tech_info,
const std::optional<bool>& critical = std::nullopt,
const std::optional<DateTime>& timestamp = std::nullopt) = 0;
/// \brief Event handler that will update the variable internally when it has been changed on the fly.
/// \param set_variable_data contains data of the variable to set
///
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 std::int32_t reservation_id, const ReservationUpdateStatusEnum status) = 0;
/// \brief Event handler that should be called when the charging station receives a ChargeParameterDiscoveryReq from
/// the CSMS \param request specifies the parameters sent from the EV to the charging station
virtual void on_ev_charging_needs(const NotifyEVChargingNeedsRequest& request) = 0;
/// @} // End handlers group
/// @}
/// \brief Validates provided \p id_token \p certificate and \p ocsp_request_data using CSMS, AuthCache or AuthList
/// \param id_token
/// \param certificate
/// \param ocsp_request_data
/// \return AuthorizeResponse containing the result of the validation
virtual AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) = 0;
/// \brief Data transfer mechanism initiated by charger
/// \param vendorId
/// \param messageId
/// \param data
/// \return DataTransferResponse containing the result from CSMS
virtual std::optional<DataTransferResponse> data_transfer_req(const CiString<255>& vendorId,
const std::optional<CiString<50>>& messageId,
const std::optional<json>& data) = 0;
/// \brief Data transfer mechanism initiated by charger
/// \param request
/// \return DataTransferResponse containing the result from CSMS. In case no response is received from the CSMS
/// because the message timed out or the charging station is offline, std::nullopt is returned
virtual std::optional<DataTransferResponse> data_transfer_req(const DataTransferRequest& request) = 0;
/// \brief Delay draining the message queue after reconnecting, so the CSMS can perform post-reconnect checks first
/// \param delay The delay period (seconds)
virtual void set_message_queue_resume_delay(std::chrono::seconds delay) = 0;
/// \brief Gets variables specified within \p get_variable_data_vector from the device model and returns the result.
/// This function is used internally in order to handle GetVariables.req messages and it can be used to get
/// variables externally.
/// \param get_variable_data_vector contains data of the variables to get
/// \return Vector containing a result for each requested variable
virtual std::vector<GetVariableResult>
get_variables(const std::vector<GetVariableData>& get_variable_data_vector) = 0;
/// \brief Sets variables specified within \p set_variable_data_vector in the device model and returns the result.
/// \param set_variable_data_vector contains data of the variables to set
/// \return Map containing the SetVariableData as a key and the SetVariableResult as a value for each requested
/// change
virtual std::map<SetVariableData, SetVariableResult>
set_variables(const std::vector<SetVariableData>& set_variable_data_vector, const std::string& source) = 0;
/// \brief Registers a listener for variable changes
/// \param listener The listener function to register
virtual void register_variable_listener(
std::function<void(const std::unordered_map<std::int64_t, VariableMonitoringMeta>& monitors,
const Component& component, const Variable& variable,
const VariableCharacteristics& characteristics, const VariableAttribute& attribute,
const std::string& value_previous, const std::string& value_current)>&& listener) = 0;
/// \brief Gets a composite schedule based on the given \p request
/// \param request specifies different options for the request
/// \return EnhancedCompositeScheduleResponse containing the status of the operation and the composite schedule if
/// the operation was successful
virtual EnhancedCompositeScheduleResponse get_composite_schedule(const GetCompositeScheduleRequest& request) = 0;
/// \brief Gets a composite schedule based on the given parameters.
/// \note This will ignore TxDefaultProfiles and TxProfiles if no transaction is active on \p evse_id
/// \param evse_id Evse to get the schedule for
/// \param duration How long the schedule should be
/// \param unit ChargingRateUnit to thet the schedule for
/// \return the composite schedule if the operation was successful, otherwise nullopt
virtual std::optional<EnhancedCompositeSchedule>
get_composite_schedule(std::int32_t evse_id, std::chrono::seconds duration, ChargingRateUnitEnum unit) = 0;
/// \brief Gets composite schedules for all evse_ids (including 0) for the given \p duration and \p unit . If no
/// valid profiles are given for an evse for the specified period, the composite schedule will be empty for this
/// evse.
/// \param duration of the request from. Composite schedules will be retrieved from now to (now + duration)
/// \param unit of the period entries of the composite schedules
/// \return vector of composite schedules, one for each evse_id including 0.
virtual std::vector<EnhancedCompositeSchedule> get_all_composite_schedules(const std::int32_t duration,
const ChargingRateUnitEnum& unit) = 0;
/// \brief Gets the configured NetworkConnectionProfile based on the given \p configuration_slot . The
/// central system uri of the connection options will not contain ws:// or wss:// because this method removes it if
/// present. This returns the value from the cached network connection profiles. \param
/// network_configuration_priority \return
virtual std::optional<NetworkConnectionProfile>
get_network_connection_profile(const std::int32_t configuration_slot) const = 0;
/// \brief Get the priority of the given configuration slot.
/// \param configuration_slot The configuration slot to get the priority from.
/// \return The priority if the configuration slot exists.
///
virtual std::optional<int> get_priority_from_configuration_slot(const int configuration_slot) const = 0;
/// @brief Get a snapshot of the network connection slots sorted by priority.
/// Each item in the vector contains the configured configuration slots, where the slot with index 0 has the highest
/// priority. A copy is returned (rather than a const reference) so callers do not observe mid-mutation state once
/// the underlying ConnectivityManager monitor handle has been released.
/// @return The network connection slots
///
virtual std::vector<int> get_network_connection_slots() const = 0;
};
/// \brief Class implements OCPP2.0.1 Charging Station
class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBase {
private:
std::shared_ptr<DeviceModelAbstract> device_model;
std::unique_ptr<EvseManager> evse_manager;
std::shared_ptr<ConnectivityManagerInterface> connectivity_manager;
std::unique_ptr<MessageDispatcherInterface<MessageType>> message_dispatcher;
// Functional blocks
std::unique_ptr<FunctionalBlockContext> functional_block_context;
std::unique_ptr<DataTransferInterface> data_transfer;
std::unique_ptr<ReservationInterface> reservation;
std::unique_ptr<AvailabilityInterface> availability;
std::unique_ptr<AuthorizationInterface> authorization;
std::unique_ptr<DiagnosticsInterface> diagnostics;
std::unique_ptr<SecurityInterface> security;
std::unique_ptr<DisplayMessageInterface> display_message;
std::unique_ptr<FirmwareUpdateInterface> firmware_update;
std::unique_ptr<MeterValuesInterface> meter_values;
std::unique_ptr<SmartChargingInterface> smart_charging;
std::unique_ptr<TariffAndCostInterface> tariff_and_cost;
std::unique_ptr<TransactionInterface> transaction;
std::unique_ptr<ProvisioningInterface> provisioning;
std::unique_ptr<RemoteTransactionControlInterface> remote_transaction_control;
std::unique_ptr<BidirectionalInterface> bidirectional;
std::unique_ptr<v21::DERControlInterface> der_control;
// utility
std::shared_ptr<MessageQueue<v2::MessageType>> message_queue;
std::shared_ptr<DatabaseHandler> database_handler;
fs::path share_path;
// states
std::atomic<RegistrationStatusEnum> registration_status{RegistrationStatusEnum::Rejected};
std::atomic<OcppProtocolVersion> ocpp_version{
OcppProtocolVersion::Unknown}; // version that is currently in use, selected by CSMS in websocket handshake
std::atomic<UploadLogStatusEnum> upload_log_status{UploadLogStatusEnum::Idle};
std::atomic<std::int32_t> upload_log_status_id;
BootReasonEnum bootreason{BootReasonEnum::PowerUp};
bool skip_invalid_csms_certificate_notifications{false};
/// \brief Component responsible for maintaining and persisting the operational status of CS, EVSEs, and connectors.
std::shared_ptr<ComponentStateManagerInterface> component_state_manager;
// store the connector status
struct EvseConnectorPair {
std::int32_t evse_id;
std::int32_t connector_id;
// Define a comparison operator for the struct
bool operator<(const EvseConnectorPair& other) const {
// Compare based on name, then age
if (evse_id != other.evse_id) {
return evse_id < other.evse_id;
}
return connector_id < other.connector_id;
}
};
// callback struct
Callbacks callbacks;
/// \brief Handler for automatic or explicit OCSP cache updates
OcspUpdater ocsp_updater;
/// \brief optional delay to resumption of message queue after reconnecting to the CSMS
std::chrono::seconds message_queue_resume_delay = std::chrono::seconds(0);
// internal helper functions
void initialize(const std::map<std::int32_t, std::int32_t>& evse_connector_structure,
const std::string& message_log_path);
OcspUpdater make_ocsp_updater();
void update_dm_availability_state(const std::int32_t evse_id, const std::int32_t connector_id,
const ConnectorStatusEnum status);
void message_callback(const std::string& message);
/// \brief Get the value optional offline flag
/// \return true if the charge point is offline. std::nullopt if it is online;
bool is_offline();
/// @brief Configure the message logging callback with device model parameters
/// @param message_log_path path to file logging
void configure_message_logging_format(const std::string& message_log_path);
/* OCPP message requests */
/* OCPP message handlers */
// Generates async sending callbacks
template <class RequestType, class ResponseType>
std::function<ResponseType(RequestType)> send_callback(MessageType expected_response_message_type) {
return [this, expected_response_message_type](auto request) {
const auto enhanced_response =
this->message_dispatcher->dispatch_call_async(ocpp::Call<RequestType>(request)).get();
if (enhanced_response.messageType != expected_response_message_type) {
throw UnexpectedMessageTypeFromCSMS(
std::string("Got unexpected message type from CSMS, expected: ") +
conversions::messagetype_to_string(expected_response_message_type) +
", got: " + conversions::messagetype_to_string(enhanced_response.messageType));
}
const ocpp::CallResult<ResponseType> call_result = enhanced_response.message;
return call_result.msg;
};
}
protected:
void handle_message(const EnhancedMessage<v2::MessageType>& message);
void clear_invalid_charging_profiles();
public:
/// \addtogroup chargepoint_constructors
/// @{
/// @name Constructors for 2.0.1
/// @{
/// \brief Construct a new ChargePoint object
/// \param evse_connector_structure Map that defines the structure of EVSE and connectors of the chargepoint. The
/// key represents the id of the EVSE and the value represents the number of connectors for this EVSE. The ids of
/// the EVSEs have to increment starting with 1.
/// \param device_model device model instance
/// \param database_handler database handler instance
/// \param evse_security Pointer to evse_security that manages security related operations
/// \param connectivity_manager connectivity manager instance
/// \param message_log_path Path to where logfiles are written to
/// \param callbacks Callbacks that will be registered for ChargePoint
ChargePoint(const std::map<int32_t, int32_t>& evse_connector_structure,
const std::shared_ptr<DeviceModelAbstract> device_model,
const std::shared_ptr<DatabaseHandler> database_handler,
const std::shared_ptr<EvseSecurity> evse_security,
const std::shared_ptr<ConnectivityManagerInterface> connectivity_manager,
const std::string& message_log_path, const Callbacks& callbacks);
/// \brief Construct a new ChargePoint object
/// \param evse_connector_structure Map that defines the structure of EVSE and connectors of the chargepoint. The
/// key represents the id of the EVSE and the value represents the number of connectors for this EVSE. The ids of
/// the EVSEs have to increment starting with 1.
/// \param device_model device model instance
/// \param database_handler database handler instance
/// \param message_queue message queue instance
/// \param message_log_path Path to where logfiles are written to
/// \param evse_security Pointer to evse_security that manages security related operations
/// \param callbacks Callbacks that will be registered for ChargePoint
/// \param share_path Path where utility files for OCPP are read and written to
ChargePoint(const std::map<std::int32_t, std::int32_t>& evse_connector_structure,
std::shared_ptr<DeviceModelAbstract> device_model, std::shared_ptr<DatabaseHandler> database_handler,
std::shared_ptr<MessageQueue<v2::MessageType>> message_queue, const std::string& message_log_path,
const std::shared_ptr<EvseSecurity> evse_security, const Callbacks& callbacks,
const fs::path& share_path = {});
/// \brief Construct a new ChargePoint object
/// \param evse_connector_structure Map that defines the structure of EVSE and connectors of the chargepoint. The
/// key represents the id of the EVSE and the value represents the number of connectors for this EVSE. The ids of
/// the EVSEs have to increment starting with 1.
/// \param device_model_storage_interface device model interface instance
/// \param ocpp_main_path Path where utility files for OCPP are read and written to
/// \param core_database_path Path to directory where core database is located
/// \param message_log_path Path to where logfiles are written to
/// \param evse_security Pointer to evse_security that manages security related operations
/// \param callbacks Callbacks that will be registered for ChargePoint
ChargePoint(const std::map<std::int32_t, std::int32_t>& evse_connector_structure,
std::unique_ptr<DeviceModelStorageInterface> device_model_storage_interface,
const std::string& ocpp_main_path, const std::string& core_database_path,
const std::string& sql_init_path, const std::string& message_log_path,
const std::shared_ptr<EvseSecurity> evse_security, const Callbacks& callbacks);
/// \brief Construct a new ChargePoint object
/// \param evse_connector_structure Map that defines the structure of EVSE and connectors of the chargepoint. The
/// key represents the id of the EVSE and the value represents the number of connectors for this EVSE. The ids of
/// the EVSEs have to increment starting with 1.
/// \param device_model_storage_address address to device model storage (e.g. location of SQLite database)
/// \param device_model_migration_path Path to the device model database migration files
/// \param device_model_config_path Path to the device model config
/// \param ocpp_main_path Path where utility files for OCPP are read and written to
/// \param core_database_path Path to directory where core database is located
/// \param message_log_path Path to where logfiles are written to
/// \param evse_security Pointer to evse_security that manages security related operations; if nullptr
/// security_configuration must be set
/// \param callbacks Callbacks that will be registered for ChargePoint
ChargePoint(const std::map<std::int32_t, std::int32_t>& evse_connector_structure,
const std::string& device_model_storage_address, const std::string& device_model_migration_path,
const std::string& device_model_config_path, const std::string& ocpp_main_path,
const std::string& core_database_path, const std::string& sql_init_path,
const std::string& message_log_path, const std::shared_ptr<EvseSecurity> evse_security,
const Callbacks& callbacks);
/// @} // End chargepoint 2.0.1 member group
/// @} // End chargepoint 2.0.1 topic
~ChargePoint() override;
void start(BootReasonEnum bootreason = BootReasonEnum::PowerUp, bool start_connecting = true) override;
void stop() override;
void connect_websocket(std::optional<std::int32_t> network_profile_slot = std::nullopt) override;
void disconnect_websocket() override;
void on_websocket_connected(const int configuration_slot,
const NetworkConnectionProfile& network_connection_profile,
const OcppProtocolVersion ocpp_version) override;
void on_websocket_disconnected(const int configuration_slot,
const NetworkConnectionProfile& network_connection_profile) override;
void on_websocket_connection_failed(ConnectionFailedReason reason) override;
void on_network_disconnected(OCPPInterfaceEnum ocpp_interface) override;
void on_firmware_update_status_notification(std::int32_t request_id,
const FirmwareStatusEnum& firmware_update_status) override;
void on_session_started(const std::int32_t evse_id, const std::int32_t connector_id) override;
Get15118EVCertificateResponse
on_get_15118_ev_certificate_request(const Get15118EVCertificateRequest& request) override;
void on_transaction_started(const std::int32_t evse_id, const std::int32_t connector_id,
const std::string& session_id, const DateTime& timestamp,
const TriggerReasonEnum trigger_reason, const MeterValue& meter_start,
const std::optional<IdToken>& id_token, const std::optional<IdToken>& group_id_token,
const std::optional<std::int32_t>& reservation_id,
const std::optional<std::int32_t>& remote_start_id,
const ChargingStateEnum charging_state) override;
void on_transaction_finished(const std::int32_t evse_id, const DateTime& timestamp, const MeterValue& meter_stop,
const ReasonEnum reason, const TriggerReasonEnum trigger_reason,
const std::optional<IdToken>& id_token,
const std::optional<std::string>& signed_meter_value,
const ChargingStateEnum charging_state) override;
void on_session_finished(const std::int32_t evse_id, const std::int32_t connector_id) override;
void on_authorized(const std::int32_t evse_id, const std::int32_t connector_id, const IdToken& id_token) override;
void on_meter_value(const std::int32_t evse_id, const MeterValue& meter_value) override;
void on_unavailable(const std::int32_t evse_id, const std::int32_t connector_id) override;
void on_enabled(const std::int32_t evse_id, const std::int32_t connector_id) override;
void on_faulted(const std::int32_t evse_id, const std::int32_t connector_id) override;
void on_fault_cleared(const std::int32_t evse_id, const std::int32_t connector_id) override;
void on_reserved(const std::int32_t evse_id, const std::int32_t connector_id) override;
void on_reservation_cleared(const std::int32_t evse_id, const std::int32_t connector_id) override;
bool on_charging_state_changed(
const std::uint32_t evse_id, const ChargingStateEnum charging_state,
const TriggerReasonEnum trigger_reason = TriggerReasonEnum::ChargingStateChanged) override;
ChangeAvailabilityResponse on_change_availability(const ChangeAvailabilityRequest& request) override;
std::optional<std::string> get_evse_transaction_id(std::int32_t evse_id) override;
AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) override;
void on_event(const std::vector<EventData>& events) override;
void on_log_status_notification(UploadLogStatusEnum status, std::int32_t requestId) override;
void on_security_event(const CiString<50>& event_type, const std::optional<CiString<255>>& tech_info,
const std::optional<bool>& critical = std::nullopt,
const std::optional<DateTime>& timestamp = std::nullopt) override;
void on_variable_changed(const SetVariableData& set_variable_data) override;
void on_reservation_status(const std::int32_t reservation_id, const ReservationUpdateStatusEnum status) override;
void on_ev_charging_needs(const NotifyEVChargingNeedsRequest& request) override;
std::optional<DataTransferResponse> data_transfer_req(const CiString<255>& vendorId,
const std::optional<CiString<50>>& messageId,
const std::optional<json>& data) override;
std::optional<DataTransferResponse> data_transfer_req(const DataTransferRequest& request) override;
void set_message_queue_resume_delay(std::chrono::seconds delay) override {
this->message_queue_resume_delay = delay;
}
std::vector<GetVariableResult> get_variables(const std::vector<GetVariableData>& get_variable_data_vector) override;
std::map<SetVariableData, SetVariableResult>
set_variables(const std::vector<SetVariableData>& set_variable_data_vector, const std::string& source) override;
void register_variable_listener(
std::function<void(const std::unordered_map<std::int64_t, VariableMonitoringMeta>& monitors,
const Component& component, const Variable& variable,
const VariableCharacteristics& characteristics, const VariableAttribute& attribute,
const std::string& value_previous, const std::string& value_current)>&& listener) override;
EnhancedCompositeScheduleResponse get_composite_schedule(const GetCompositeScheduleRequest& request) override;
std::optional<EnhancedCompositeSchedule> get_composite_schedule(std::int32_t evse_id, std::chrono::seconds duration,
ChargingRateUnitEnum unit) override;
std::vector<EnhancedCompositeSchedule> get_all_composite_schedules(const std::int32_t duration,
const ChargingRateUnitEnum& unit) override;
std::optional<NetworkConnectionProfile>
get_network_connection_profile(const std::int32_t configuration_slot) const override;
std::optional<int> get_priority_from_configuration_slot(const int configuration_slot) const override;
std::vector<int> get_network_connection_slots() const override;
void send_not_implemented_error(const MessageId unique_message_id, const MessageTypeId message_type_id);
/// \brief Requests a value of a VariableAttribute specified by combination of \p component_id and \p variable_id
/// from the device model
/// \tparam T datatype of the value that is requested
/// \param component_id
/// \param variable_id
/// \param attribute_enum
/// \return Response to request that contains status of the request and the requested value as std::optional<T> .
/// The value is present if the status is GetVariableStatusEnum::Accepted
template <typename T>
RequestDeviceModelResponse<T> request_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum) {
return this->device_model->request_value<T>(component_id, variable_id, attribute_enum);
}
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,194 @@
#pragma once
#include <cstdint>
#include <memory>
#include <ocpp/common/connectivity_manager.hpp>
#include <ocpp/v2/device_model.hpp>
#include <ocpp/v2/messages/BootNotification.hpp>
#include <ocpp/v2/messages/ClearDisplayMessage.hpp>
#include <ocpp/v2/messages/DataTransfer.hpp>
#include <ocpp/v2/messages/GetDisplayMessages.hpp>
#include <ocpp/v2/messages/GetLog.hpp>
#include <ocpp/v2/messages/RequestStartTransaction.hpp>
#include <ocpp/v2/messages/ReserveNow.hpp>
#include <ocpp/v2/messages/SetDisplayMessage.hpp>
#include <ocpp/v2/messages/TransactionEvent.hpp>
#include <ocpp/v2/messages/UnlockConnector.hpp>
#include <ocpp/v2/messages/UpdateFirmware.hpp>
namespace ocpp::v2 {
struct Callbacks {
/// @addtogroup ocpp201_callbacks OCPP 2.0.1 callbacks
/// Callbacks will call be called when necessary and must be implemented by the calling class.
/// @{
/// @name Callbacks
/// Callbacks
/// @{
/// \brief Function to check if the callback struct is completely filled. All std::functions should hold a function,
/// all std::optional<std::functions> should either be empty or hold a function.
/// \param device_model The device model, to check if certain modules are enabled / available.
/// \param evse_connector_structure The evse_connector_structure is used to check variables for specific evse and/or
/// connector
///
/// \retval false if any of the normal callbacks are nullptr or any of the optional ones are filled with a nullptr
/// true otherwise
bool all_callbacks_valid(std::shared_ptr<DeviceModelAbstract> device_model,
const std::map<std::int32_t, std::int32_t>& evse_connector_structure) const;
///
/// \brief Callback if reset is allowed. If evse_id has a value, reset only applies to the given evse id. If it has
/// no value, applies to complete charging station.
///
std::function<bool(const std::optional<const std::int32_t> evse_id, const ResetEnum& reset_type)>
is_reset_allowed_callback;
std::function<void(const std::optional<const std::int32_t> evse_id, const ResetEnum& reset_type)> reset_callback;
std::function<RequestStartStopStatusEnum(const std::int32_t evse_id, const ReasonEnum& stop_reason)>
stop_transaction_callback;
std::function<void(const std::int32_t evse_id)> pause_charging_callback;
/// \brief Used to notify the user of libocpp that the Operative/Inoperative state of the charging station changed
/// If as a result the state of EVSEs or connectors changed as well, libocpp will additionally call the
/// evse_effective_operative_status_changed_callback once for each EVSE whose status changed, and
/// connector_effective_operative_status_changed_callback once for each connector whose status changed.
/// If left empty, the callback is ignored.
/// \param new_status The operational status the CS switched to
std::optional<std::function<void(const OperationalStatusEnum new_status)>>
cs_effective_operative_status_changed_callback;
/// \brief Used to notify the user of libocpp that the Operative/Inoperative state of an EVSE changed
/// If as a result the state of connectors changed as well, libocpp will additionally call the
/// connector_effective_operative_status_changed_callback once for each connector whose status changed.
/// If left empty, the callback is ignored.
/// \param evse_id The id of the EVSE
/// \param new_status The operational status the EVSE switched to
std::optional<std::function<void(const std::int32_t evse_id, const OperationalStatusEnum new_status)>>
evse_effective_operative_status_changed_callback;
/// \brief Used to notify the user of libocpp that the Operative/Inoperative state of a connector changed.
/// \param evse_id The id of the EVSE
/// \param connector_id The ID of the connector within the EVSE
/// \param new_status The operational status the connector switched to
std::function<void(const std::int32_t evse_id, const std::int32_t connector_id,
const OperationalStatusEnum new_status)>
connector_effective_operative_status_changed_callback;
std::function<GetLogResponse(const GetLogRequest& request)> get_log_request_callback;
std::function<UnlockConnectorResponse(const std::int32_t evse_id, const std::int32_t connecor_id)>
unlock_connector_callback;
// callback to be called when the request can be accepted. authorize_remote_start indicates if Authorize.req needs
// to follow or not
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 The reservation check status of this evse / id token.
///
std::function<ocpp::ReservationCheckStatus(const std::int32_t evse_id, const CiString<255> idToken,
const std::optional<CiString<255>> 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
std::optional<std::function<void(const SetVariableData& set_variable_data)>> variable_changed_callback;
// callback is called when receiving a SetNetworkProfile.req from the CSMS
std::optional<std::function<SetNetworkProfileStatusEnum(
const std::int32_t configuration_slot, const NetworkConnectionProfile& network_connection_profile)>>
validate_network_profile_callback;
std::optional<ConfigureNetworkConnectionProfileCallback> configure_network_connection_profile_callback;
std::optional<std::function<void(const ocpp::DateTime& currentTime)>> time_sync_callback;
/// \brief Callback function is called when a OCPP message is sent or received
std::optional<std::function<void(const std::string& message, MessageDirection direction)>> ocpp_messages_callback;
///
/// \brief callback function that can be used to react to a security event callback. This callback is
/// called only if the SecurityEvent occured internally within libocpp
/// Typically this callback is used to log security events in the security log
///
std::function<void(const CiString<50>& event_type, const std::optional<CiString<255>>& tech_info)>
security_event_callback;
/// \brief Callback for indicating when a charging profile is received and was accepted.
std::function<void()> set_charging_profiles_callback;
/// \brief Callback for when a bootnotification response is received
std::optional<std::function<void(const ocpp::v2::BootNotificationResponse& boot_notification_response)>>
boot_notification_callback;
/// \brief Callback function that can be used to get (human readable) customer information based on the given
/// arguments
std::optional<std::function<std::string(const std::optional<CertificateHashDataType> customer_certificate,
const std::optional<IdToken> id_token,
const std::optional<CiString<64>> customer_identifier)>>
get_customer_information_callback;
/// \brief Callback function that can be called to clear customer information based on the given arguments
std::optional<std::function<void(const std::optional<CertificateHashDataType> customer_certificate,
const std::optional<IdToken> id_token,
const std::optional<CiString<64>> customer_identifier)>>
clear_customer_information_callback;
/// \brief Callback function that can be called when all connectors are unavailable
std::optional<std::function<void()>> all_connectors_unavailable_callback;
/// \brief Callback function that can be used to handle arbitrary data transfers for all vendorId and
/// messageId
std::optional<std::function<DataTransferResponse(const DataTransferRequest& request)>> data_transfer_callback;
/// \brief Callback function that is called when a transaction_event was sent to the CSMS
std::optional<std::function<void(const TransactionEventRequest& transaction_event)>> transaction_event_callback;
/// \brief Callback function that is called when a transaction_event_response was received from the CSMS
std::optional<std::function<void(const TransactionEventRequest& transaction_event,
const TransactionEventResponse& transaction_event_response)>>
transaction_event_response_callback;
/// \brief Callback function is called when the websocket connection status changes
std::optional<std::function<void(const bool is_connected, const int configuration_slot,
const NetworkConnectionProfile& network_connection_profile,
const OcppProtocolVersion ocpp_version)>>
connection_state_changed_callback;
/// \brief Callback functions called for get / set / clear display messages
std::optional<std::function<std::vector<DisplayMessage>(const GetDisplayMessagesRequest& request)>>
get_display_message_callback;
std::optional<std::function<SetDisplayMessageResponse(const std::vector<DisplayMessage>& display_messages)>>
set_display_message_callback;
std::optional<std::function<ClearDisplayMessageResponse(const ClearDisplayMessageRequest& request)>>
clear_display_message_callback;
/// \brief Callback function is called when running cost is set.
std::optional<std::function<void(const RunningCost& running_cost, const std::uint32_t number_of_decimals,
std::optional<std::string> currency_code)>>
set_running_cost_callback;
/// \brief Callback function is called when a TransactionEventResponse message from the CSMS is received that
/// contains tariff and cost information.
std::optional<std::function<void(const TariffMessage& message)>> tariff_message_callback;
/// \brief Callback function is called on startup and whenever the applicable default price changes (e.g. after a
/// connectivity state change or a configuration update that affects the fallback price variables). The argument
/// contains the price text in one or more languages; the first entry uses the configured default language.
std::optional<std::function<void(const std::vector<DisplayMessageContent>& messages)>> default_price_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 std::int32_t reservationId)>> cancel_reservation_callback;
/// @} // End ocpp 201 callbacks group / topic
/// \brief Callback function is called when an update to the allowed energy transfer modes has been received,
/// OCPP 2.1
std::optional<std::function<bool(const std::vector<ocpp::v2::EnergyTransferModeEnum> allowed_energy_transfer_modes,
const CiString<36> transaction_id)>>
update_allowed_energy_transfer_modes_callback;
/// @} // End group
};
} // namespace ocpp::v2

View File

@@ -0,0 +1,71 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/v2/ocpp_types.hpp>
namespace ocpp {
namespace v2 {
inline bool operator==(const EVSE& lhs, const EVSE& rhs) {
return lhs.id == rhs.id and lhs.connectorId == rhs.connectorId;
};
inline bool operator<(const EVSE& lhs, const EVSE& rhs) {
if (lhs.id != rhs.id) {
return lhs.id < rhs.id;
}
return lhs.connectorId < rhs.connectorId;
}
inline bool operator==(const Component& lhs, const Component& rhs) {
return lhs.name.get() == rhs.name.get() and lhs.instance == rhs.instance and lhs.evse == rhs.evse;
};
inline bool operator<(const Component& lhs, const Component& rhs) {
if (lhs.name != rhs.name) {
return lhs.name < rhs.name;
}
if (lhs.instance != rhs.instance) {
return lhs.instance < rhs.instance;
}
return lhs.evse < rhs.evse;
};
inline bool operator==(const Variable& lhs, const Variable& rhs) {
return lhs.name.get() == rhs.name.get() and lhs.instance == rhs.instance;
};
inline bool operator<(const Variable& lhs, const Variable& rhs) {
if (lhs.name != rhs.name) {
return lhs.name < rhs.name;
}
return lhs.instance < rhs.instance;
};
inline bool operator==(const ComponentVariable& lhs, const ComponentVariable& rhs) {
return lhs.component == rhs.component and lhs.variable == rhs.variable;
}
inline bool operator<(const ComponentVariable& lhs, const ComponentVariable& rhs) {
if (lhs.component == rhs.component) {
return lhs.variable < rhs.variable;
}
return lhs.component < rhs.component;
}
inline bool operator==(const SetVariableData& lhs, const SetVariableData& rhs) {
return lhs.component == rhs.component and lhs.variable == rhs.variable and
lhs.attributeValue.get() == rhs.attributeValue.get() and lhs.attributeType == rhs.attributeType;
}
inline bool operator<(const SetVariableData& lhs, const SetVariableData& rhs) {
if (lhs.component == rhs.component) {
return lhs.variable < rhs.variable;
}
return lhs.component < rhs.component;
}
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,343 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include "database_handler.hpp"
#include <ocpp/v2/ocpp_enums.hpp>
namespace ocpp::v2 {
/// \brief Exception used when an evse that does not exist is accessed.
class EvseOutOfRangeException : public std::exception {
public:
explicit EvseOutOfRangeException(std::int32_t id) : msg{"Evse with id " + std::to_string(id) + " does not exist"} {
}
~EvseOutOfRangeException() noexcept override = default;
const char* what() const noexcept override {
return msg.c_str();
}
private:
std::string msg;
};
/// \brief Exception used when an connector_id that does not exist is accessed.
class ConnectorOutOfRangeException : public std::exception {
public:
explicit ConnectorOutOfRangeException(std::int32_t connector_id, std::int32_t evse_id) :
msg{"Connector with id " + std::to_string(connector_id) + " does not exist for evse with id " +
std::to_string(evse_id)} {
}
~ConnectorOutOfRangeException() noexcept override = default;
const char* what() const noexcept override {
return msg.c_str();
}
private:
std::string msg;
};
/// \brief Describes the individual state of a single connector
struct FullConnectorStatus {
/// \brief Operative/Inoperative status, usually set by the CSMS
OperationalStatusEnum individual_operational_status;
/// \brief True if the connector has an active (uncleared) error, assumed false on boot
bool faulted;
/// \brief True if the connector has an active reservation, assumed false on boot
bool reserved;
/// \brief True if the connector has a cable plugged in, assumed false on boot
bool occupied;
/// \brief True if the connector is explicitly set to unavailable
bool unavailable;
/// \brief Translates the individual state to an Available/Unavailable/Occupied/Reserved/Faulted state
/// This does NOT take into account the state of the EVSE or CS,
/// and is intended to be used internally by the ComponentStateManagerInterface.
ConnectorStatusEnum to_connector_status() const;
};
class ComponentStateManagerInterface {
public:
virtual ~ComponentStateManagerInterface();
/// \brief Set a callback to be called when the effective Operative/Inoperative state of the CS changes.
virtual void set_cs_effective_availability_changed_callback(
const std::function<void(const OperationalStatusEnum new_status)>& callback) = 0;
/// \brief Set a callback to be called when the effective Operative/Inoperative state of an EVSE changes.
virtual void set_evse_effective_availability_changed_callback(
const std::function<void(const std::int32_t evse_id, const OperationalStatusEnum new_status)>& callback) = 0;
/// \brief Set a callback to be called when the effective Operative/Inoperative state of a connector changes.
virtual void set_connector_effective_availability_changed_callback(
const std::function<void(const std::int32_t evse_id, const std::int32_t connector_id,
const OperationalStatusEnum new_status)>& callback) = 0;
/// \brief Get the individual status (Operative/Inoperative) of the CS, as set by the CSMS
virtual OperationalStatusEnum get_cs_individual_operational_status() = 0;
/// \brief Get the individual status (Operative/Inoperative) of an EVSE, as set by the CSMS
/// Note: This is not the same as the effective status.
/// The EVSE might be effectively Inoperative if the CS is Inoperative.
virtual OperationalStatusEnum get_evse_individual_operational_status(std::int32_t evse_id) = 0;
/// \brief Get the individual status (Operative/Inoperative) of a connector, as set by the CSMS
/// Note: This is not the same as the effective status.
/// The connector might be effectively Inoperative if its EVSE or the CS is Inoperative.
virtual OperationalStatusEnum get_connector_individual_operational_status(std::int32_t evse_id,
std::int32_t connector_id) = 0;
/// \brief Get the individual status (Operative/Inoperative) of the CS, as persisted in the database
/// This status is restored after reboot, and differs from the individual status if non-persistent
/// status changes were made.
virtual OperationalStatusEnum get_cs_persisted_operational_status() = 0;
/// \brief Get the individual status (Operative/Inoperative) of an EVSE, as persisted in the database
/// This status is restored after reboot, and differs from the individual status if non-persistent
/// status changes were made.
virtual OperationalStatusEnum get_evse_persisted_operational_status(std::int32_t evse_id) = 0;
/// \brief Get the individual status (Operative/Inoperative) of a connector, as persisted in the database
/// This status is restored after reboot, and differs from the individual status if non-persistent
/// status changes were made.
virtual OperationalStatusEnum get_connector_persisted_operational_status(std::int32_t evse_id,
std::int32_t connector_id) = 0;
/// \brief Set the individual status (Operative/Inoperative) of the CS
virtual void set_cs_individual_operational_status(OperationalStatusEnum new_status, bool persist) = 0;
/// \brief Set the individual status (Operative/Inoperative) of an EVSE
/// Note: This is not the same as the effective status.
/// The EVSE might be effectively Inoperative if the CS is Inoperative.
virtual void set_evse_individual_operational_status(std::int32_t evse_id, OperationalStatusEnum new_status,
bool persist) = 0;
/// \brief Set the individual status (Operative/Inoperative) of a connector
/// Note: This is not the same as the effective status.
/// The connector might be effectively Inoperative if its EVSE or the CS is Inoperative.
virtual void set_connector_individual_operational_status(std::int32_t evse_id, std::int32_t connector_id,
OperationalStatusEnum new_status, bool persist) = 0;
/// \brief Get the effective Operative/Inoperative status of an EVSE
/// This is computed from the EVSE's and the CS's individual statuses.
virtual OperationalStatusEnum get_evse_effective_operational_status(std::int32_t evse_id) = 0;
/// \brief Get the effective Operative/Inoperative status of a connector.
/// This is computed from the connector's, the EVSE's, and the CS's individual statuses.
virtual OperationalStatusEnum get_connector_effective_operational_status(std::int32_t evse_id,
std::int32_t connector_id) = 0;
/// \brief Get the effective Available/Unavailable/Occupied/Faulted/Reserved status of a connector.
/// If the EVSE or the CS is Inoperative, the connector will be effectively Unavailable.
virtual ConnectorStatusEnum get_connector_effective_status(std::int32_t evse_id, std::int32_t connector_id) = 0;
/// \brief Update the state of the connector when plugged in or out
virtual void set_connector_occupied(std::int32_t evse_id, std::int32_t connector_id, bool is_occupied) = 0;
/// \brief Update the state of the connector when reservations are made or expire
virtual void set_connector_reserved(std::int32_t evse_id, std::int32_t connector_id, bool is_reserved) = 0;
/// \brief Update the state of the connector when errors are raised and cleared
virtual void set_connector_faulted(std::int32_t evse_id, std::int32_t connector_id, bool is_faulted) = 0;
/// \brief Update the state of the connector when unavailable or enabled
virtual void set_connector_unavailable(std::int32_t evse_id, std::int32_t connector_id, bool is_unavailable) = 0;
/// \brief Call the {cs, evse, connector}_effective_availability_changed_callback callback once for every component.
/// This is usually only done once on boot to notify the rest of the system what the state manager expects the
/// operative state (Operative/Inoperative) of the CS, EVSEs, and connectors to be.
virtual void trigger_all_effective_availability_changed_callbacks() = 0;
/// \brief Call the send_connector_status_notification_callback once for every connector.
/// This is usually done on boot, and on reconnect after the station has been offline for a long time.
virtual void send_status_notification_all_connectors() = 0;
/// \brief Call the send_connector_status_notification_callback once for every connector whose state has changed
/// since it was last reported with a successful send_connector_status_notification_callback. This is usually done
/// when the station has been offline for short time and comes back online.
virtual void send_status_notification_changed_connectors() = 0;
/// \brief Call the send_connector_status_notification_callback for a single connector.
/// This is usually done when the CSMS explicitly sends a TriggerMessage to send a StatusNotification.
virtual void send_status_notification_single_connector(std::int32_t evse_id, std::int32_t connector_id) = 0;
};
/// \brief Stores and monitors operational/effective states of the CS, EVSEs, and connectors
class ComponentStateManager : public ComponentStateManagerInterface {
private:
std::shared_ptr<DatabaseHandler> database;
/// Current individual Operative/Inoperative state of the CS
OperationalStatusEnum cs_individual_status;
/// Current individual Operative/Inoperative state of EVSEs, plus individual state of connectors.
std::vector<std::pair<OperationalStatusEnum, std::vector<FullConnectorStatus>>>
evse_and_connector_individual_statuses;
/// Last Operative/Inoperative status of the CS that was reported to the user of libocpp via callbacks
OperationalStatusEnum last_cs_effective_operational_status;
/// Last Operative/Inoperative status of EVSEs and connectors that was reported to the user of libocpp via callbacks
std::vector<std::pair<OperationalStatusEnum, std::vector<OperationalStatusEnum>>>
last_evse_and_connector_effective_operational_statuses;
/// Last connector status for each connector that was reported with a successful
/// send_connector_status_notification_callback
// We need to track this separately because the send_connector_status_notification_callback can fail
std::vector<std::vector<ConnectorStatusEnum>> last_connector_reported_statuses;
/// \brief Callback triggered by the library when the effective status of the charging station changes
/// \param new_status The effective status after the change
std::optional<std::function<void(const OperationalStatusEnum new_status)>>
cs_effective_availability_changed_callback = std::nullopt;
/// \brief Callback triggered by the library when the effective status of an EVSE changes
/// \param evse_id The ID of the EVSE whose status changed
/// \param new_status The effective status after the change
std::optional<std::function<void(const std::int32_t evse_id, const OperationalStatusEnum new_status)>>
evse_effective_availability_changed_callback = std::nullopt;
/// \brief Callback triggered by the library when the effective status of a connector changes
/// \param evse_id The ID of the EVSE whose status changed
/// \param connector_id The ID of the connector within the EVSE whose status changed
/// \param new_status The effective status after the change
std::optional<std::function<void(const std::int32_t evse_id, const std::int32_t connector_id,
const OperationalStatusEnum new_status)>>
connector_effective_availability_changed_callback = std::nullopt;
/// \brief Callback used by the library to trigger a StatusUpdateRequest for a connector
/// \param evse_id The ID of the EVSE
/// \param connector_id The ID of the connector
/// \param new_status The connector status
/// \param initiated_by_trigger_message Indicates if the StatusNotification was initiated by a TriggerMessage.req
/// \return true if the status notification was successfully sent, false otherwise (usually it fails when offline)
std::function<bool(const std::int32_t evse_id, const std::int32_t connector_id,
const ConnectorStatusEnum new_status, bool initiated_by_trigger_message)>
send_connector_status_notification_callback;
/// \brief Internal convenience function - returns the number of EVSEs
std::int32_t num_evses();
/// \brief Internal convenience function - returns the number of connectors in an EVSE
std::int32_t num_connectors(std::int32_t evse_id);
/// \brief Throws a std::out_of_range if \param evse_id is out of bounds
void check_evse_id(std::int32_t evse_id);
/// \brief Throws a std::out_of_range if \param evse_id or \param connector_id is out of bounds
void check_evse_and_connector_id(std::int32_t evse_id, std::int32_t connector_id);
/// \brief Convenience function, returns a (writeable) reference to the individual status of an EVSE
OperationalStatusEnum& individual_evse_status(std::int32_t evse_id);
/// \brief Convenience function, returns a (writeable) reference to the individual status of a connector
FullConnectorStatus& individual_connector_status(std::int32_t evse_id, std::int32_t connector_id);
/// \brief Convenience function, returns a (writeable) reference to last Operative/Inoperative status of an EVSE
/// that was reported to the user of libocpp via callbacks.
OperationalStatusEnum& last_evse_effective_status(std::int32_t evse_id);
/// \brief Convenience function, returns a (writeable) reference to last Operative/Inoperative status of a connector
/// that was reported to the user of libocpp via callbacks.
OperationalStatusEnum& last_connector_effective_status(std::int32_t evse_id, std::int32_t connector_id);
/// \brief Convenience function, returns a (writeable) reference to last connector status that was successfully
/// reported via send_connector_status_notification_callback
ConnectorStatusEnum& last_connector_reported_status(std::int32_t evse_id, std::int32_t connector_id);
/// \brief Internal helper function, triggers {cs, evse, connector}_effective_availability_changed_callback calls
/// for the CS and all sub-components.
/// \param only_if_state_changed If set to true, callbacks are only triggered for components whose state
/// has changed since it was last reported via callbacks
void trigger_callbacks_cs(bool only_if_state_changed);
/// \brief Internal helper function, triggers {evse, connector}_effective_availability_changed_callback calls
/// for an EVSE and its connectors
/// \param only_if_state_changed If set to true, callbacks are only triggered for components whose state
/// has changed since it was last reported via callbacks
void trigger_callbacks_evse(std::int32_t evse_id, bool only_if_state_changed);
/// \brief Internal helper function, triggers connector_effective_availability_changed_callback calls
/// for a connector
/// \param only_if_state_changed If set to true, callbacks are only triggered for components whose state
/// has changed since it was last reported via callbacks
void trigger_callbacks_connector(std::int32_t evse_id, std::int32_t connector_id, bool only_if_state_changed);
/// \brief Internal helper function, calls send_connector_status_notification_callback for a single connector
/// \param only_if_changed If set to true, the callback will only be triggered if the connector state has changed
/// since it was last reported with a successful send_connector_status_notification_callback
/// \param intiated_by_trigger_message Indicates if the StatusNotification was initiated by a TriggerMessage.req
void send_status_notification_single_connector_internal(std::int32_t evse_id, std::int32_t connector_id,
bool only_if_changed,
bool intiated_by_trigger_message = false);
/// \brief Initializes *_individual_status(es) from the values stored in the DB.
/// Inserts Operative if values are missing.
void
read_all_states_from_database_or_set_defaults(const std::map<std::int32_t, std::int32_t>& evse_connector_structure);
/// \brief Initializes last_*_operational_status(es) and last_connector_reported_statuses
/// with the current effective statuses of all components
void initialize_reported_state_cache();
public:
/// \brief At construction time, the state of each component (CS, EVSEs, and connectors) is retrieved from the
/// database. No callbacks are triggered at this stage.
/// When the status of components is updated, corresponding callbacks are triggered to notify the user of libocpp.
/// Additionally, the ComponentStateManager sends StatusNotifications to the CSMS when connector statuses change.
/// Note: It is expected that ComponentStateManagerInterface::trigger_all_effective_availability_changed_callbacks
/// is called on boot, and ComponentStateManagerInterface::send_status_notification_all_connectors is called when
/// first connected to the CSMS.
/// \param evse_connector_structure Maps each EVSE ID to the number of connectors the EVSE has
/// \param db_handler A shared reference to the persistent database
/// \param send_connector_status_notification_callback The callback through which to send StatusNotifications to the
/// CSMS \param initiated_by_trigger_message Indicates if the StatusNotification was initiated by a
/// TriggerMessage.req
explicit ComponentStateManager(
const std::map<std::int32_t, std::int32_t>& evse_connector_structure,
std::shared_ptr<DatabaseHandler> db_handler,
std::function<bool(const std::int32_t evse_id, const std::int32_t connector_id,
const ConnectorStatusEnum new_status, const bool initiated_by_trigger_message)>
send_connector_status_notification_callback);
void set_cs_effective_availability_changed_callback(
const std::function<void(const OperationalStatusEnum new_status)>& callback) override;
void set_evse_effective_availability_changed_callback(
const std::function<void(const std::int32_t evse_id, const OperationalStatusEnum new_status)>& callback)
override;
void set_connector_effective_availability_changed_callback(
const std::function<void(const std::int32_t evse_id, const std::int32_t connector_id,
const OperationalStatusEnum new_status)>& callback) override;
OperationalStatusEnum get_cs_individual_operational_status() override;
OperationalStatusEnum get_evse_individual_operational_status(std::int32_t evse_id) override;
OperationalStatusEnum get_connector_individual_operational_status(std::int32_t evse_id,
std::int32_t connector_id) override;
OperationalStatusEnum get_cs_persisted_operational_status() override;
OperationalStatusEnum get_evse_persisted_operational_status(std::int32_t evse_id) override;
OperationalStatusEnum get_connector_persisted_operational_status(std::int32_t evse_id,
std::int32_t connector_id) override;
void set_cs_individual_operational_status(OperationalStatusEnum new_status, bool persist) override;
void set_evse_individual_operational_status(std::int32_t evse_id, OperationalStatusEnum new_status,
bool persist) override;
void set_connector_individual_operational_status(std::int32_t evse_id, std::int32_t connector_id,
OperationalStatusEnum new_status, bool persist) override;
OperationalStatusEnum get_evse_effective_operational_status(std::int32_t evse_id) override;
OperationalStatusEnum get_connector_effective_operational_status(std::int32_t evse_id,
std::int32_t connector_id) override;
ConnectorStatusEnum get_connector_effective_status(std::int32_t evse_id, std::int32_t connector_id) override;
void set_connector_occupied(std::int32_t evse_id, std::int32_t connector_id, bool is_occupied) override;
void set_connector_reserved(std::int32_t evse_id, std::int32_t connector_id, bool is_reserved) override;
void set_connector_faulted(std::int32_t evse_id, std::int32_t connector_id, bool is_faulted) override;
void set_connector_unavailable(std::int32_t evse_id, std::int32_t connector_id, bool is_unavailable) override;
void trigger_all_effective_availability_changed_callbacks() override;
void send_status_notification_all_connectors() override;
void send_status_notification_changed_connectors() override;
void send_status_notification_single_connector(std::int32_t evse_id, std::int32_t connector_id) override;
};
} // namespace ocpp::v2

View File

@@ -0,0 +1,78 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include <functional>
#include <mutex>
#include "component_state_manager.hpp"
#include "database_handler.hpp"
#include <ocpp/v2/ocpp_enums.hpp>
#include <optional>
namespace ocpp {
namespace v2 {
/// \brief Enum for ConnectorEvents
enum class ConnectorEvent {
PlugIn,
PlugOut,
Reserve,
ReservationCleared,
Error,
ErrorCleared,
Unavailable,
UnavailableCleared
};
namespace conversions {
/// \brief Converts the given ConnectorEvent \p e to human readable string
/// \returns a string representation of the ConnectorEvent
std::string connector_event_to_string(ConnectorEvent e);
} // namespace conversions
/// \brief Represents a Connector, thus electrical outlet on a Charging Station. Single physical Connector.
class Connector {
private:
/// \brief ID of the EVSE this connector belongs to (>0)
// cppcheck-suppress unusedStructMember
std::int32_t evse_id;
/// \brief ID of the connector itself (>0)
std::int32_t connector_id;
/// \brief Component responsible for maintaining and monitoring the operational status of CS, EVSEs, and connectors.
std::shared_ptr<ComponentStateManagerInterface> component_state_manager;
/// \brief status mutex to protect the status of the connector against concurrent updates
std::mutex status_mutex;
public:
/// \brief Construct a new Connector object
/// \param evse_id id of the EVSE the connector is ap art of
/// \param connector_id id of the connector
/// \param component_state_manager A shared reference to the component state manager
Connector(const std::int32_t evse_id, const std::int32_t connector_id,
std::shared_ptr<ComponentStateManagerInterface> component_state_manager);
/// \brief Gets the effective Operative/Inoperative status of this connector
OperationalStatusEnum get_effective_operational_status();
/// \brief Gets the effective Available/Unavailable/Faulted/Reserved/Occupied status of this connector
ConnectorStatusEnum get_effective_connector_status();
/// \brief Adjust the state of the connector according to the \p event that was submitted.
/// \param event
void submit_event(ConnectorEvent event);
/// \brief Switches the operative status of the connector and recomputes its effective status
/// \param new_status: The operative status to switch to
/// \param persist: True if the updated operative status setting should be persisted
void set_connector_operative_status(OperationalStatusEnum new_status, bool persist);
/// \brief Restores the operative status of the connector to the persisted status and recomputes its effective
/// status
void restore_connector_operative_status();
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,17 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <cstddef>
namespace ocpp {
namespace v2 {
/// \brief OCPP 2.0.1 defines this as 5600 but it can be set to a higher value, which we do here, if it's reported via
/// the device model, which we do as well
/// 17000 is the minimum value from OCPP 2.1
constexpr std::size_t ISO15118_GET_EV_CERTIFICATE_EXI_RESPONSE_SIZE = 17000;
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,464 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V2_CTRLR_COMPONENT_VARIABLES
#define OCPP_V2_CTRLR_COMPONENT_VARIABLES
#include <cstdint>
#include <optional>
#include <set>
#include <ocpp/v2/ocpp_types.hpp>
namespace ocpp {
namespace v2 {
class DeviceModelInterface;
///
/// \brief Required ComponentVariable.
///
struct RequiredComponentVariable : ComponentVariable {
/// \brief Constructor
RequiredComponentVariable() : required_for({OcppProtocolVersion::v201, OcppProtocolVersion::v21}){};
///
/// \brief RequiredComponentVariable
/// \param component Component
/// \param variable Variable
/// \param custom_data Custom data (default nullopt)
/// \param required_for Required for which version. Multiple versions can be given.
///
RequiredComponentVariable(const Component component, const std::optional<Variable> variable,
const std::optional<CustomData> custom_data = std::nullopt,
const std::set<OcppProtocolVersion>& required_for = {OcppProtocolVersion::v201,
OcppProtocolVersion::v21}) :
ComponentVariable(), required_for(required_for) {
this->component = component;
this->variable = variable;
this->customData = custom_data;
};
/// \brief For which ocpp protocol version(s) this component variable is required.
std::set<OcppProtocolVersion> required_for;
};
///
/// \brief Required variables per component.
///
/// First value is the 'available' variable from the specific component. Second value is a set of required variables.
/// This makes it possible to check only for the required variables if a component is available.
///
extern const std::vector<std::pair<ComponentVariable, std::vector<RequiredComponentVariable>>>
required_component_available_variables;
///
/// \brief Required variables that should always exist, regardless of any available or not available controller.
///
extern const std::vector<RequiredComponentVariable> required_variables;
///
/// \brief Required variables of an EVSE.
///
extern const std::vector<Variable> required_evse_variables;
///
/// \brief Required variables of a connector.
///
extern const std::vector<Variable> required_connector_variables;
///
/// \brief Required variables of a V2X component.
///
extern const std::vector<Variable> required_v2x_variables;
namespace ControllerComponents {
extern const Component InternalCtrlr;
extern const Component AlignedDataCtrlr;
extern const Component AuthCacheCtrlr;
extern const Component AuthCtrlr;
extern const Component ChargingStation;
extern const Component ClockCtrlr;
extern const Component ConnectedEV;
extern const Component CustomizationCtrlr;
extern const Component DeviceDataCtrlr;
extern const Component DisplayMessageCtrlr;
extern const Component ISO15118Ctrlr;
extern const Component LocalAuthListCtrlr;
extern const Component MonitoringCtrlr;
extern const Component OCPPCommCtrlr;
extern const Component ReservationCtrlr;
extern const Component SampledDataCtrlr;
extern const Component SecurityCtrlr;
extern const Component SmartChargingCtrlr;
extern const Component TariffCostCtrlr;
extern const Component TxCtrlr;
// following controllers contains OCPP1.6 configuration keys without a clear mapping to OCPP2.x.
extern const Component OCPP16LegacyCtrlr;
extern const Component CustomLegacyController;
} // namespace ControllerComponents
namespace StandardizedVariables {
extern const Variable Problem;
extern const Variable Tripped;
extern const Variable Overload;
extern const Variable Fallback;
}; // namespace StandardizedVariables
// Provides access to standardized variables of OCPP2.0.1 spec
namespace ControllerComponentVariables {
extern const ComponentVariable InternalCtrlrEnabled;
extern const RequiredComponentVariable ChargePointId;
extern const RequiredComponentVariable NetworkConnectionProfiles;
extern const RequiredComponentVariable ChargeBoxSerialNumber;
extern const RequiredComponentVariable ChargePointModel;
extern const ComponentVariable ChargePointSerialNumber;
extern const RequiredComponentVariable ChargePointVendor;
extern const RequiredComponentVariable FirmwareVersion;
extern const ComponentVariable ICCID;
extern const ComponentVariable IMSI;
extern const ComponentVariable MeterSerialNumber;
extern const ComponentVariable MeterType;
extern const RequiredComponentVariable SupportedCiphers12;
extern const RequiredComponentVariable SupportedCiphers13;
extern const ComponentVariable AuthorizeConnectorZeroOnConnectorOne;
extern const ComponentVariable LogMessages;
extern const ComponentVariable LogMessagesRaw;
extern const RequiredComponentVariable LogMessagesFormat;
extern const ComponentVariable LogRotation;
extern const ComponentVariable LogRotationDateSuffix;
extern const ComponentVariable LogRotationMaximumFileSize;
extern const ComponentVariable LogRotationMaximumFileCount;
extern const ComponentVariable SupportedChargingProfilePurposeTypes;
extern const ComponentVariable SupportedCriteria;
extern const ComponentVariable RoundClockAlignedTimestamps;
extern const ComponentVariable NetworkConfigTimeout;
extern const ComponentVariable MaxCompositeScheduleDuration;
extern const RequiredComponentVariable NumberOfConnectors;
extern const ComponentVariable UseSslDefaultVerifyPaths;
extern const ComponentVariable VerifyCsmsCommonName;
extern const ComponentVariable UseTPM;
extern const ComponentVariable UseTPMSeccLeafCertificate;
extern const ComponentVariable VerifyCsmsAllowWildcards;
extern const ComponentVariable IFace;
extern const ComponentVariable EnableTLSKeylog;
extern const ComponentVariable TLSKeylogFile;
extern const ComponentVariable OcspRequestInterval;
extern const ComponentVariable WebsocketPingPayload;
extern const ComponentVariable WebsocketPongTimeout;
extern const ComponentVariable MonitorsProcessingInterval;
extern const ComponentVariable MaxCustomerInformationDataLength;
extern const ComponentVariable V2GCertificateExpireCheckInitialDelaySeconds;
extern const ComponentVariable V2GCertificateExpireCheckIntervalSeconds;
extern const ComponentVariable ClientCertificateExpireCheckInitialDelaySeconds;
extern const ComponentVariable ClientCertificateExpireCheckIntervalSeconds;
extern const ComponentVariable MessageQueueSizeThreshold;
extern const ComponentVariable MaxMessageSize;
extern const ComponentVariable ResumeTransactionsOnBoot;
extern const ComponentVariable AllowSecurityLevelZeroConnections;
extern const RequiredComponentVariable SupportedOcppVersions;
extern const ComponentVariable AlignedDataCtrlrEnabled;
extern const ComponentVariable AlignedDataCtrlrAvailable;
extern const RequiredComponentVariable AlignedDataInterval;
extern const RequiredComponentVariable AlignedDataMeasurands;
extern const ComponentVariable AlignedDataSendDuringIdle;
extern const ComponentVariable AlignedDataSignReadings;
extern const RequiredComponentVariable AlignedDataTxEndedInterval;
extern const RequiredComponentVariable AlignedDataTxEndedMeasurands;
extern const ComponentVariable AuthCacheCtrlrAvailable;
extern const ComponentVariable AuthCacheCtrlrEnabled;
extern const ComponentVariable AuthCacheDisablePostAuthorize;
extern const ComponentVariable AuthCacheLifeTime;
extern const ComponentVariable AuthCachePolicy;
extern const ComponentVariable AuthCacheStorage;
extern const ComponentVariable AuthCtrlrEnabled;
extern const ComponentVariable AdditionalInfoItemsPerMessage;
extern const RequiredComponentVariable AuthorizeRemoteStart;
extern const RequiredComponentVariable LocalAuthorizeOffline;
extern const RequiredComponentVariable LocalPreAuthorize;
extern const ComponentVariable DisableRemoteAuthorization;
extern const ComponentVariable MasterPassGroupId;
extern const ComponentVariable OfflineTxForUnknownIdEnabled;
extern const ComponentVariable AllowNewSessionsPendingFirmwareUpdate;
extern const RequiredComponentVariable ChargingStationAvailabilityState;
extern const RequiredComponentVariable ChargingStationAvailable;
extern const RequiredComponentVariable ChargingStationSupplyPhases;
extern const RequiredComponentVariable ClockCtrlrDateTime;
extern const ComponentVariable NextTimeOffsetTransitionDateTime;
extern const ComponentVariable NtpServerUri;
extern const ComponentVariable NtpSource;
extern const ComponentVariable TimeAdjustmentReportingThreshold;
extern const ComponentVariable TimeOffset;
extern const ComponentVariable TimeOffsetNextTransition;
extern const RequiredComponentVariable TimeSource;
extern const ComponentVariable TimeZone;
extern const ComponentVariable CustomImplementationEnabled;
extern const ComponentVariable CustomImplementationCaliforniaPricingEnabled;
extern const ComponentVariable CustomImplementationMultiLanguageEnabled;
extern const RequiredComponentVariable BytesPerMessageGetReport;
extern const RequiredComponentVariable BytesPerMessageGetVariables;
extern const RequiredComponentVariable BytesPerMessageSetVariables;
extern const ComponentVariable ConfigurationValueSize;
extern const RequiredComponentVariable ItemsPerMessageGetReport;
extern const RequiredComponentVariable ItemsPerMessageGetVariables;
extern const RequiredComponentVariable ItemsPerMessageSetVariables;
extern const ComponentVariable ReportingValueSize;
extern const ComponentVariable DisplayMessageCtrlrAvailable;
extern const RequiredComponentVariable NumberOfDisplayMessages;
extern const RequiredComponentVariable DisplayMessageSupportedFormats;
extern const RequiredComponentVariable DisplayMessageSupportedPriorities;
extern const ComponentVariable DisplayMessageSupportedStates;
extern const ComponentVariable DisplayMessageQRCodeDisplayCapable;
extern const ComponentVariable DisplayMessageLanguage;
extern const ComponentVariable CentralContractValidationAllowed;
extern const RequiredComponentVariable ContractValidationOffline;
extern const ComponentVariable RequestMeteringReceipt;
extern const ComponentVariable ISO15118CtrlrSeccId;
extern const ComponentVariable ISO15118CtrlrCountryName;
extern const ComponentVariable ISO15118CtrlrOrganizationName;
extern const ComponentVariable PnCEnabled;
extern const ComponentVariable V2GCertificateInstallationEnabled;
extern const ComponentVariable ContractCertificateInstallationEnabled;
extern const ComponentVariable LocalAuthListCtrlrAvailable;
extern const RequiredComponentVariable BytesPerMessageSendLocalList;
extern const ComponentVariable LocalAuthListCtrlrEnabled;
extern const RequiredComponentVariable LocalAuthListCtrlrEntries;
extern const RequiredComponentVariable ItemsPerMessageSendLocalList;
extern const ComponentVariable LocalAuthListCtrlrStorage;
extern const ComponentVariable LocalAuthListDisablePostAuthorize;
extern const ComponentVariable MonitoringCtrlrAvailable;
extern const ComponentVariable BytesPerMessageClearVariableMonitoring;
extern const RequiredComponentVariable BytesPerMessageSetVariableMonitoring;
extern const ComponentVariable MonitoringCtrlrEnabled;
extern const ComponentVariable ActiveMonitoringBase;
extern const ComponentVariable ActiveMonitoringLevel;
extern const ComponentVariable ItemsPerMessageClearVariableMonitoring;
extern const RequiredComponentVariable ItemsPerMessageSetVariableMonitoring;
extern const ComponentVariable OfflineQueuingSeverity;
extern const ComponentVariable ActiveNetworkProfile;
extern const RequiredComponentVariable FileTransferProtocols;
extern const ComponentVariable HeartbeatInterval;
extern const RequiredComponentVariable MessageTimeout;
extern const RequiredComponentVariable MessageAttemptInterval;
extern const RequiredComponentVariable MessageAttempts;
extern const RequiredComponentVariable NetworkConfigurationPriority;
extern const RequiredComponentVariable NetworkProfileConnectionAttempts;
extern const RequiredComponentVariable OfflineThreshold;
extern const ComponentVariable QueueAllMessages;
extern const ComponentVariable MessageTypesDiscardForQueueing;
extern const RequiredComponentVariable ResetRetries;
extern const RequiredComponentVariable RetryBackOffRandomRange;
extern const RequiredComponentVariable RetryBackOffRepeatTimes;
extern const RequiredComponentVariable RetryBackOffWaitMinimum;
extern const RequiredComponentVariable UnlockOnEVSideDisconnect;
extern const RequiredComponentVariable WebSocketPingInterval;
extern const ComponentVariable ReservationCtrlrAvailable;
extern const ComponentVariable ReservationCtrlrEnabled;
extern const ComponentVariable ReservationCtrlrNonEvseSpecific;
extern const ComponentVariable SampledDataCtrlrAvailable;
extern const ComponentVariable SampledDataCtrlrEnabled;
extern const ComponentVariable SampledDataSignReadings;
extern const RequiredComponentVariable SampledDataTxEndedInterval;
extern const RequiredComponentVariable SampledDataTxEndedMeasurands;
extern const RequiredComponentVariable SampledDataTxStartedMeasurands;
extern const RequiredComponentVariable SampledDataTxUpdatedInterval;
extern const RequiredComponentVariable SampledDataTxUpdatedMeasurands;
extern const ComponentVariable AdditionalRootCertificateCheck;
extern const ComponentVariable BasicAuthPassword;
extern const RequiredComponentVariable CertificateEntries;
extern const ComponentVariable CertSigningRepeatTimes;
extern const ComponentVariable CertSigningWaitMinimum;
extern const RequiredComponentVariable SecurityCtrlrIdentity;
extern const ComponentVariable MaxCertificateChainSize;
extern const ComponentVariable UpdateCertificateSymlinks;
extern const RequiredComponentVariable OrganizationName;
extern const RequiredComponentVariable SecurityProfile;
extern const ComponentVariable AllowCSMSRootCertInstallWithUnsecureConnection;
extern const ComponentVariable AllowMFRootCertInstallWithUnsecureConnection;
extern const ComponentVariable ACPhaseSwitchingSupported;
extern const ComponentVariable SmartChargingCtrlrAvailable;
extern const ComponentVariable SmartChargingCtrlrEnabled;
extern const RequiredComponentVariable EntriesChargingProfiles;
extern const ComponentVariable ExternalControlSignalsEnabled;
extern const RequiredComponentVariable LimitChangeSignificance;
extern const ComponentVariable NotifyChargingLimitWithSchedules;
extern const RequiredComponentVariable PeriodsPerSchedule;
extern const RequiredComponentVariable CompositeScheduleDefaultLimitAmps;
extern const RequiredComponentVariable CompositeScheduleDefaultLimitWatts;
extern const RequiredComponentVariable CompositeScheduleDefaultNumberPhases;
extern const RequiredComponentVariable SupplyVoltage;
extern const ComponentVariable Phases3to1;
extern const RequiredComponentVariable ChargingProfileMaxStackLevel;
extern const RequiredComponentVariable ChargingScheduleChargingRateUnit;
extern const ComponentVariable IgnoredProfilePurposesOffline;
extern const ComponentVariable ChargingProfilePersistenceTxProfile;
extern const ComponentVariable ChargingProfilePersistenceChargingStationExternalConstraints;
extern const ComponentVariable ChargingProfilePersistenceLocalGeneration;
extern const ComponentVariable ChargingProfileUpdateRateLimit;
extern const ComponentVariable MaxExternalConstraintsId;
extern const ComponentVariable SupportedAdditionalPurposes;
extern const ComponentVariable SupportsDynamicProfiles;
extern const ComponentVariable SupportsUseLocalTime;
extern const ComponentVariable SupportsRandomizedDelay;
extern const ComponentVariable SupportsLimitAtSoC;
extern const ComponentVariable SupportsEvseSleep;
extern const ComponentVariable TariffCostCtrlrAvailableTariff;
extern const ComponentVariable TariffCostCtrlrAvailableCost;
extern const RequiredComponentVariable TariffCostCtrlrCurrency;
extern const ComponentVariable TariffCostCtrlrEnabledTariff;
extern const ComponentVariable TariffCostCtrlrEnabledCost;
extern const RequiredComponentVariable TariffFallbackMessage;
extern const ComponentVariable OfflineTariffFallbackMessage;
extern const RequiredComponentVariable TotalCostFallbackMessage;
extern const ComponentVariable NumberOfDecimalsForCostValues;
extern const RequiredComponentVariable EVConnectionTimeOut;
extern const ComponentVariable MaxEnergyOnInvalidId;
extern const RequiredComponentVariable StopTxOnEVSideDisconnect;
extern const RequiredComponentVariable StopTxOnInvalidId;
extern const ComponentVariable TxBeforeAcceptedEnabled;
extern const RequiredComponentVariable TxStartPoint;
extern const RequiredComponentVariable TxStopPoint;
extern const ComponentVariable ISO15118CtrlrAvailable;
// OCPP1.6 mavericks: The following ComponentVariable definitions are required because some OCPP1.6 configuration keys
// do not map to any existing component variable combination in OCPP2.x. The following definitions only control the
// OCPP1.6 implementation
extern const ComponentVariable BlinkRepeat;
extern const ComponentVariable ConnectorPhaseRotation;
extern const ComponentVariable ConnectorPhaseRotationMaxLength;
extern const RequiredComponentVariable GetConfigurationMaxKeys;
extern const ComponentVariable LightIntensity;
extern const ComponentVariable MinimumStatusDuration;
extern const ComponentVariable StopTransactionOnEVSideDisconnect;
extern const RequiredComponentVariable SupportedFeatureProfiles;
extern const ComponentVariable SupportedFeatureProfilesMaxLength;
extern const RequiredComponentVariable UnlockConnectorOnEVSideDisconnect;
extern const ComponentVariable ReserveConnectorZeroSupported;
extern const ComponentVariable HostName;
extern const ComponentVariable AllowChargingProfileWithoutStartSchedule;
extern const ComponentVariable WaitForStopTransactionsOnResetTimeout;
extern const ComponentVariable StopTransactionIfUnlockNotSupported;
extern const ComponentVariable MeterPublicKeys;
extern const ComponentVariable DisableSecurityEventNotifications;
extern const ComponentVariable ISO15118CertificateManagementEnabled;
extern const ComponentVariable CustomDisplayCostAndPrice; // Required only if CaliforniaPricing enabled
extern const ComponentVariable DefaultPrice;
extern const ComponentVariable DefaultPriceText;
extern const ComponentVariable CustomIdleFeeAfterStop;
extern const ComponentVariable SupportedLanguages;
extern const ComponentVariable CustomMultiLanguageMessages;
extern const ComponentVariable Language;
extern const ComponentVariable WaitForSetUserPriceTimeout;
extern const ComponentVariable AuthorizationKey16;
extern const RequiredComponentVariable CentralSystemURI16;
extern const RequiredComponentVariable SecurityProfile16;
} // namespace ControllerComponentVariables
namespace EvseComponentVariables {
extern const Variable Available;
extern const Variable AvailabilityState;
extern const Variable SupplyPhases;
extern const Variable AllowReset;
extern const Variable Power;
extern const Variable DCInputPhaseControl;
extern const Variable ISO15118EvseId;
ComponentVariable get_component_variable(const std::int32_t evse_id, const Variable& variable);
} // namespace EvseComponentVariables
namespace ConnectorComponentVariables {
extern const Variable Available;
extern const Variable AvailabilityState;
extern const Variable Type;
extern const Variable SupplyPhases;
ComponentVariable get_component_variable(const std::int32_t evse_id, const std::int32_t connector_id,
const Variable& variable);
} // namespace ConnectorComponentVariables
namespace V2xComponentVariables {
extern const Variable Available;
extern const Variable Enabled;
extern const Variable SupportedEnergyTransferModes;
extern const Variable SupportedOperationModes;
extern const Variable TxStartedMeasurands;
extern const Variable TxEndedMeasurands;
extern const Variable TxEndedInterval;
extern const Variable TxUpdatedMeasurands;
extern const Variable TxUpdatedInterval;
Variable get_v2x_tx_started_measurands(const OperationModeEnum& mode);
Variable get_v2x_tx_ended_measurands(const OperationModeEnum& mode);
Variable get_v2x_tx_ended_interval(const OperationModeEnum& mode);
Variable get_v2x_tx_updated_measurands(const OperationModeEnum& mode);
Variable get_v2x_tx_updated_interval(const OperationModeEnum& mode);
ComponentVariable get_component_variable(const std::int32_t evse_id, const Variable& variable);
} // namespace V2xComponentVariables
namespace ISO15118ComponentVariables {
extern const Variable Enabled;
extern const Variable ServiceRenegotiationSupport;
extern const Variable ProtocolSupported;
// These variables are defined again here as it is possible to have either a global variable or evse specific
extern const Variable SeccId;
extern const Variable CountryName;
extern const Variable OrganizationName;
ComponentVariable get_component_variable(const std::int32_t evse_id, const Variable& variable);
} // namespace ISO15118ComponentVariables
namespace ConnectedEvComponentVariables {
extern const Variable Available;
extern const Variable VehicleId;
extern const Variable ProtocolAgreed;
extern const Variable VehicleCertificateLeaf;
extern const Variable VehicleCertificateSubCa1;
extern const Variable VehicleCertificateSubCa2;
extern const Variable VehicleCertificateRoot;
Variable get_protocol_supported_by_ev(const std::int32_t priority);
ComponentVariable get_component_variable(const std::int32_t evse_id, const Variable& variable);
} // namespace ConnectedEvComponentVariables
namespace NetworkConfigurationComponentVariables {
extern const Variable OcppCsmsUrl;
extern const Variable SecurityProfile;
extern const Variable OcppInterface;
extern const Variable OcppTransport;
extern const Variable MessageTimeout;
extern const Variable Identity;
extern const Variable BasicAuthPassword;
extern const Variable ApnEnabled;
extern const Variable VpnEnabled;
extern const Variable Apn;
extern const Variable ApnUserName;
extern const Variable ApnPassword;
extern const Variable SimPin;
extern const Variable PreferredNetwork;
extern const Variable UseOnlyPreferredNetwork;
extern const Variable ApnAuthentication;
extern const Variable VpnServer;
extern const Variable VpnUser;
extern const Variable VpnPassword;
extern const Variable VpnKey;
extern const Variable VpnType;
extern const Variable VpnGroup;
extern const Variable OcppVersion;
extern const Variable CsmsRootCertificateHashAlgorithm;
extern const Variable CsmsRootCertificateIssuerKeyHash;
extern const Variable CsmsRootCertificateIssuerNameHash;
extern const Variable CsmsRootCertificateSerialNumber;
ComponentVariable get_component_variable(const std::int32_t slot, const Variable& variable);
std::optional<NetworkConnectionProfile> read_profile_from_device_model(DeviceModelInterface& dm, int32_t slot);
bool write_profile_to_device_model(DeviceModelInterface& dm, int32_t slot, const NetworkConnectionProfile& profile,
const std::string& source);
void migrate_from_blob_if_needed(DeviceModelInterface& dm);
void clear_slot_in_device_model(DeviceModelInterface& dm, int32_t slot);
} // namespace NetworkConfigurationComponentVariables
namespace DERComponentVariables {
extern const Variable Available;
extern const Variable ModesSupported;
ComponentVariable get_dc_component_variable(const std::int32_t evse_id, const Variable& variable);
ComponentVariable get_ac_component_variable(const std::int32_t evse_id, const Variable& variable);
} // namespace DERComponentVariables
} // namespace v2
} // namespace ocpp
#endif // OCPP_V2_CTRLR_COMPONENT_VARIABLES

View File

@@ -0,0 +1,400 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef OCPP_V2_DATABASE_HANDLER_HPP
#define OCPP_V2_DATABASE_HANDLER_HPP
#include "ocpp/v2/types.hpp"
#include "sqlite3.h"
#include <memory>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <everest/database/sqlite/connection.hpp>
#include <ocpp/common/database/database_handler_common.hpp>
#include <ocpp/v2/ocpp_types.hpp>
#include <ocpp/v2/transaction.hpp>
#include <everest/logging.hpp>
namespace ocpp {
namespace v2 {
/// \brief Helper class for retrieving authorization cache entries from the database
struct AuthorizationCacheEntry {
IdTokenInfo id_token_info;
DateTime last_used;
};
class DatabaseHandlerInterface {
public:
virtual ~DatabaseHandlerInterface() = default;
// Authorization cache management
/// \brief Inserts cache entry
/// \param id_token_hash
/// \param id_token_info
virtual void authorization_cache_insert_entry(const std::string& id_token_hash,
const IdTokenInfo& id_token_info) = 0;
/// \brief Updates the last_used field in the entry
///
/// \param id_token_hash
/// \retval true if entry was updated
virtual void authorization_cache_update_last_used(const std::string& id_token_hash) = 0;
/// \brief Gets cache entry for given \p id_token_hash if present
/// \param id_token_hash
/// \return
virtual std::optional<AuthorizationCacheEntry> authorization_cache_get_entry(const std::string& id_token_hash) = 0;
/// \brief Deletes the cache entry for the given \p id_token_hash
/// \param id_token_hash
virtual void authorization_cache_delete_entry(const std::string& id_token_hash) = 0;
/// \brief Removes up to \p nr_to_remove items from the cache starting from the least recently used
///
/// \param nr_to_remove Number of items to remove from the database
/// \retval True if succeeded
virtual void authorization_cache_delete_nr_of_oldest_entries(size_t nr_to_remove) = 0;
/// \brief Removes all entries from the cache that have passed their expiry date or auth cache lifetime
///
/// \param auth_cache_lifetime The maximum time tokens can stay in the cache without being used
/// \retval True if succeeded
virtual void
authorization_cache_delete_expired_entries(std::optional<std::chrono::seconds> auth_cache_lifetime) = 0;
/// \brief Deletes all entries of the AUTH_CACHE table. Returns true if the operation was successful, else false
virtual void authorization_cache_clear() = 0;
/// \brief Get the binary size of the authorization cache table
///
/// \retval The size of the authorization cache table in bytes
virtual size_t authorization_cache_get_binary_size() = 0;
// Availability
/// \brief Persist operational settings for the charging station
virtual void insert_cs_availability(OperationalStatusEnum operational_status, bool replace) = 0;
/// \brief Retrieve persisted operational settings for the charging station
virtual OperationalStatusEnum get_cs_availability() = 0;
/// \brief Persist operational settings for an EVSE
virtual void insert_evse_availability(std::int32_t evse_id, OperationalStatusEnum operational_status,
bool replace) = 0;
/// \brief Retrieve persisted operational settings for an EVSE
virtual OperationalStatusEnum get_evse_availability(std::int32_t evse_id) = 0;
/// \brief Persist operational settings for a connector
virtual void insert_connector_availability(std::int32_t evse_id, std::int32_t connector_id,
OperationalStatusEnum operational_status, bool replace) = 0;
/// \brief Retrieve persisted operational settings for a connector
virtual OperationalStatusEnum get_connector_availability(std::int32_t evse_id, std::int32_t connector_id) = 0;
// Local authorization list management
/// \brief Inserts or updates the given \p version in the AUTH_LIST_VERSION table.
virtual void insert_or_update_local_authorization_list_version(std::int32_t version) = 0;
/// \brief Returns the version in the AUTH_LIST_VERSION table.
virtual std::int32_t get_local_authorization_list_version() = 0;
/// \brief Inserts or updates a local authorization list entry to the AUTH_LIST table.
virtual void insert_or_update_local_authorization_list_entry(const IdToken& id_token,
const IdTokenInfo& id_token_info) = 0;
/// \brief Inserts or updates a local authorization list entries \p local_authorization_list to the AUTH_LIST table.
virtual void
insert_or_update_local_authorization_list(const std::vector<v2::AuthorizationData>& local_authorization_list) = 0;
/// \brief Deletes the authorization list entry with the given \p id_tag
virtual void delete_local_authorization_list_entry(const IdToken& id_token) = 0;
/// \brief Returns the IdTagInfo of the given \p id_tag if it exists in the AUTH_LIST table, else std::nullopt.
virtual std::optional<v2::IdTokenInfo> get_local_authorization_list_entry(const IdToken& id_token) = 0;
/// \brief Deletes all entries of the AUTH_LIST table.
virtual void clear_local_authorization_list() = 0;
/// \brief Get the number of entries currently in the authorization list
virtual std::int32_t get_local_authorization_list_number_of_entries() = 0;
// Transaction metervalues
/// \brief Inserts a \p meter_value to the database linked to transaction with id \p transaction_id
virtual void transaction_metervalues_insert(const std::string& transaction_id, const MeterValue& meter_value) = 0;
/// \brief Get all metervalues linked to transaction with id \p transaction_id
virtual std::vector<MeterValue> transaction_metervalues_get_all(const std::string& transaction_id) = 0;
/// \brief Remove all metervalue entries linked to transaction with id \p transaction_id
virtual void transaction_metervalues_clear(const std::string& transaction_id) = 0;
// transactions
/// \brief Inserts a transaction with the given parameters to the TRANSACTIONS table
/// \param transaction
/// \param evse_id
virtual void transaction_insert(const EnhancedTransaction& transaction, std::int32_t evse_id) = 0;
/// \brief Gets a transaction from the database if one can be found using \p evse_id
/// \param evse_id The evse id to get the transaction for
/// \return nullptr if not found, otherwise an enhanced transaction object.
virtual std::unique_ptr<EnhancedTransaction> transaction_get(const std::int32_t evse_id) = 0;
/// \brief Update the sequence number of the given transaction id in the database.
/// \param transaction_id
/// \param seq_no
virtual void transaction_update_seq_no(const std::string& transaction_id, std::int32_t seq_no) = 0;
/// \brief Update the charging state of the given transaction id in the database.
/// \param transaction_id
/// \param charging_state
virtual void transaction_update_charging_state(const std::string& transaction_id,
const ChargingStateEnum charging_state) = 0;
/// \brief Update the id_token_sent of the given transaction id in the database.
/// \param transaction_id
/// \param id_token_sent
virtual void transaction_update_id_token_sent(const std::string& transaction_id, bool id_token_sent) = 0;
/// \brief Clear all the transactions from the TRANSACTIONS table.
/// \param transaction_id transaction id of the transaction to clear from.
/// \return true if succeeded
virtual void transaction_delete(const std::string& transaction_id) = 0;
/// charging profiles
/// \brief Inserts or updates the given \p profile to CHARGING_PROFILES table
virtual void insert_or_update_charging_profile(
const int evse_id, const v2::ChargingProfile& profile,
const CiString<20> charging_limit_source = ChargingLimitSourceEnumStringType::CSO) = 0;
/// \brief Deletes the profile with the given \p profile_id
virtual bool delete_charging_profile(const int profile_id) = 0;
/// \brief Deletes the profiles with the given \p transaction_id
virtual void delete_charging_profile_by_transaction_id(const std::string& transaction_id) = 0;
/// \brief Deletes all profiles from table CHARGING_PROFILES
virtual bool clear_charging_profiles() = 0;
/// \brief Deletes all profiles from table CHARGING_PROFILES matching \p profile_id or \p criteria.
/// \return the ids of the rows actually deleted (empty when nothing matched).
virtual std::vector<std::int32_t>
clear_charging_profiles_matching_criteria(const std::optional<std::int32_t> profile_id,
const std::optional<ClearChargingProfile>& criteria) = 0;
/// \brief Get all profiles from table CHARGING_PROFILES matching \p profile_id or \p criteria
virtual std::vector<ReportedChargingProfile>
get_charging_profiles_matching_criteria(const std::optional<std::int32_t> evse_id,
const ChargingProfileCriterion& criteria) = 0;
/// \brief Retrieves the charging profiles stored on \p evse_id
virtual std::vector<v2::ChargingProfile> get_charging_profiles_for_evse(const int evse_id) = 0;
/// \brief Retrieves all ChargingProfiles
virtual std::vector<v2::ChargingProfile> get_all_charging_profiles() = 0;
/// \brief Retrieves all ChargingProfiles grouped by EVSE ID
virtual std::map<std::int32_t, std::vector<v2::ChargingProfile>> get_all_charging_profiles_group_by_evse() = 0;
virtual CiString<20> get_charging_limit_source_for_profile(const int profile_id) = 0;
// DER Control persistence (OCPP 2.1 R04)
/// \brief Inserts or updates a DER control in DER_CONTROLS table
virtual void insert_or_update_der_control(const std::string& control_id, bool is_default,
const std::string& control_type, bool is_superseded, int32_t priority,
const std::optional<std::string>& start_time,
const std::optional<float>& duration,
const std::string& control_json) = 0;
/// \brief Retrieves a single DER control by control_id
virtual std::optional<std::string> get_der_control(const std::string& control_id) = 0;
/// \brief Total number of rows currently in DER_CONTROLS. Used by the DER control
/// handler to cap the table so a CSMS cannot grow the DB unbounded by issuing
/// SetDERControl with ever-unique controlIds.
virtual std::size_t count_der_controls() = 0;
/// \brief Retrieves DER controls matching optional filter criteria
virtual std::vector<std::string>
get_der_controls_matching_criteria(const std::optional<bool>& is_default,
const std::optional<std::string>& control_type,
const std::optional<std::string>& control_id) = 0;
/// \brief Deletes a DER control by control_id. Returns true if a row was deleted.
virtual bool delete_der_control(const std::string& control_id) = 0;
/// \brief Deletes a DER control whose CONTROL_ID AND IS_DEFAULT both match.
/// Returns true if a row was deleted. Needed for R04.FR.42 so ClearDERControl
/// scoped by isDefault won't accidentally delete a row of the opposite kind.
virtual bool delete_der_control_by_id_and_default(const std::string& control_id, bool is_default) = 0;
/// \brief Deletes DER controls matching is_default and optional control_type. Returns number of rows deleted.
virtual int delete_der_controls_matching_criteria(bool is_default,
const std::optional<std::string>& control_type) = 0;
/// \brief Updates the is_superseded flag for a DER control
virtual void update_der_control_superseded(const std::string& control_id, bool is_superseded) = 0;
/// \brief Append \p displaced_id to the \p control_id row's CONTROL_JSON.displacedIds
/// array. Creates the array if it does not yet exist. Used at deferred-supersede
/// activation so the row records the controlId it ended up displacing; the expiry
/// handler reads this back to populate FR.22 NotifyDERStartStop.supersededIds.
virtual void append_der_control_displaced_id(const std::string& control_id, const std::string& displaced_id) = 0;
/// \brief R04.FR.07: record that \p new_control_id, once activated, will supersede
/// \p existing_control_id. The flip is performed later by a scheduled-check pass.
virtual void set_der_control_pending_supersede(const std::string& new_control_id,
const std::string& existing_control_id) = 0;
/// \brief R04.FR.07: clear the pending-supersede pointer for \p control_id after
/// the deferred supersede has been performed.
virtual void clear_der_control_pending_supersede(const std::string& control_id) = 0;
/// \brief A pending-supersede activation: when \p new_id 's start time has arrived,
/// \p existing_id should be flipped to isSuperseded=true and \p new_id started.
struct PendingSupersedeActivation {
std::string new_id;
std::string existing_id;
};
/// \brief R04.FR.07: return all rows whose PENDING_SUPERSEDE_ID is set and whose
/// START_TIME is at or before \p now. Caller is responsible for performing the
/// flip + notify + clear inside a transaction.
virtual std::vector<PendingSupersedeActivation>
get_der_control_pending_supersede_activations(const DateTime& now) = 0;
/// \brief R04.FR.20/21: return all scheduled, non-superseded rows with
/// START_TIME <= \p now that have not yet been flagged STARTED_NOTIFIED.
/// Caller emits NotifyDERStartStop(started=true) for each and then calls
/// \ref mark_der_control_started_notified on the same id.
virtual std::vector<std::string> get_der_controls_needing_start_notify(const DateTime& now) = 0;
/// \brief R04.FR.20/21: flag a row as having had its start notification emitted.
virtual void mark_der_control_started_notified(const std::string& control_id) = 0;
virtual std::unique_ptr<everest::db::sqlite::StatementInterface> new_statement(const std::string& sql) = 0;
/// \brief Begin a database transaction. Destructor rolls back unless commit() is called.
[[nodiscard]] virtual std::unique_ptr<everest::db::sqlite::TransactionInterface> begin_transaction() = 0;
};
class DatabaseHandler : public DatabaseHandlerInterface, public common::DatabaseHandlerCommon {
private:
void init_sql() override;
void inintialize_enum_tables();
void init_enum_table_inner(const std::string& table_name, const int begin, const int end,
std::function<std::string(int)> conversion);
template <typename T>
void init_enum_table(const std::string& table_name, T begin, T end, std::function<std::string(T)> conversion);
// Availability management (internal helpers)
// Setting evse_id to 0 addresses the whole CS, setting evse_id > 0 and connector_id=0 addresses a whole EVSE
void insert_availability(std::int32_t evse_id, std::int32_t connector_id, OperationalStatusEnum operational_status,
bool replace);
OperationalStatusEnum get_availability(std::int32_t evse_id, std::int32_t connector_id);
public:
DatabaseHandler(std::unique_ptr<everest::db::sqlite::ConnectionInterface> database,
const fs::path& sql_migration_files_path);
// Authorization cache management
void authorization_cache_insert_entry(const std::string& id_token_hash, const IdTokenInfo& id_token_info) override;
void authorization_cache_update_last_used(const std::string& id_token_hash) override;
std::optional<AuthorizationCacheEntry> authorization_cache_get_entry(const std::string& id_token_hash) override;
void authorization_cache_delete_entry(const std::string& id_token_hash) override;
void authorization_cache_delete_nr_of_oldest_entries(size_t nr_to_remove) override;
void authorization_cache_delete_expired_entries(std::optional<std::chrono::seconds> auth_cache_lifetime) override;
void authorization_cache_clear() override;
size_t authorization_cache_get_binary_size() override;
// Availability
void insert_cs_availability(OperationalStatusEnum operational_status, bool replace) override;
OperationalStatusEnum get_cs_availability() override;
void insert_evse_availability(std::int32_t evse_id, OperationalStatusEnum operational_status,
bool replace) override;
OperationalStatusEnum get_evse_availability(std::int32_t evse_id) override;
void insert_connector_availability(std::int32_t evse_id, std::int32_t connector_id,
OperationalStatusEnum operational_status, bool replace) override;
OperationalStatusEnum get_connector_availability(std::int32_t evse_id, std::int32_t connector_id) override;
// Local authorization list management
void insert_or_update_local_authorization_list_version(std::int32_t version) override;
std::int32_t get_local_authorization_list_version() override;
void insert_or_update_local_authorization_list_entry(const IdToken& id_token,
const IdTokenInfo& id_token_info) override;
void insert_or_update_local_authorization_list(
const std::vector<v2::AuthorizationData>& local_authorization_list) override;
void delete_local_authorization_list_entry(const IdToken& id_token) override;
std::optional<v2::IdTokenInfo> get_local_authorization_list_entry(const IdToken& id_token) override;
void clear_local_authorization_list() override;
std::int32_t get_local_authorization_list_number_of_entries() override;
// Transaction metervalues
void transaction_metervalues_insert(const std::string& transaction_id, const MeterValue& meter_value) override;
std::vector<MeterValue> transaction_metervalues_get_all(const std::string& transaction_id) override;
void transaction_metervalues_clear(const std::string& transaction_id) override;
// transactions
void transaction_insert(const EnhancedTransaction& transaction, std::int32_t evse_id) override;
std::unique_ptr<EnhancedTransaction> transaction_get(const std::int32_t evse_id) override;
void transaction_update_seq_no(const std::string& transaction_id, std::int32_t seq_no) override;
void transaction_update_charging_state(const std::string& transaction_id,
const ChargingStateEnum charging_state) override;
void transaction_update_id_token_sent(const std::string& transaction_id, bool id_token_sent) override;
void transaction_delete(const std::string& transaction_id) override;
/// charging profiles
void insert_or_update_charging_profile(
const int evse_id, const v2::ChargingProfile& profile,
const CiString<20> charging_limit_source = ChargingLimitSourceEnumStringType::CSO) override;
bool delete_charging_profile(const int profile_id) override;
void delete_charging_profile_by_transaction_id(const std::string& transaction_id) override;
bool clear_charging_profiles() override;
std::vector<std::int32_t>
clear_charging_profiles_matching_criteria(const std::optional<std::int32_t> profile_id,
const std::optional<ClearChargingProfile>& criteria) override;
std::vector<ReportedChargingProfile>
get_charging_profiles_matching_criteria(const std::optional<std::int32_t> evse_id,
const ChargingProfileCriterion& criteria) override;
std::vector<v2::ChargingProfile> get_charging_profiles_for_evse(const int evse_id) override;
std::vector<v2::ChargingProfile> get_all_charging_profiles() override;
std::map<std::int32_t, std::vector<v2::ChargingProfile>> get_all_charging_profiles_group_by_evse() override;
CiString<20> get_charging_limit_source_for_profile(const int profile_id) override;
// DER Control persistence
void insert_or_update_der_control(const std::string& control_id, bool is_default, const std::string& control_type,
bool is_superseded, int32_t priority,
const std::optional<std::string>& start_time,
const std::optional<float>& duration, const std::string& control_json) override;
std::optional<std::string> get_der_control(const std::string& control_id) override;
std::size_t count_der_controls() override;
std::vector<std::string> get_der_controls_matching_criteria(const std::optional<bool>& is_default,
const std::optional<std::string>& control_type,
const std::optional<std::string>& control_id) override;
bool delete_der_control(const std::string& control_id) override;
bool delete_der_control_by_id_and_default(const std::string& control_id, bool is_default) override;
int delete_der_controls_matching_criteria(bool is_default, const std::optional<std::string>& control_type) override;
void update_der_control_superseded(const std::string& control_id, bool is_superseded) override;
void append_der_control_displaced_id(const std::string& control_id, const std::string& displaced_id) override;
std::unique_ptr<everest::db::sqlite::StatementInterface> new_statement(const std::string& sql) override;
void set_der_control_pending_supersede(const std::string& new_control_id,
const std::string& existing_control_id) override;
void clear_der_control_pending_supersede(const std::string& control_id) override;
std::vector<PendingSupersedeActivation> get_der_control_pending_supersede_activations(const DateTime& now) override;
std::vector<std::string> get_der_controls_needing_start_notify(const DateTime& now) override;
void mark_der_control_started_notified(const std::string& control_id) override;
[[nodiscard]] std::unique_ptr<everest::db::sqlite::TransactionInterface> begin_transaction() override;
};
} // namespace v2
} // namespace ocpp
#endif

View File

@@ -0,0 +1,157 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef DEVICE_MODEL_HPP
#define DEVICE_MODEL_HPP
#include <type_traits>
#include <everest/logging.hpp>
#include <ocpp/v2/ctrlr_component_variables.hpp>
#include <ocpp/v2/device_model_abstract.hpp>
#include <ocpp/v2/device_model_storage_interface.hpp>
namespace ocpp {
namespace v2 {
using on_variable_changed = std::function<void(
const std::unordered_map<std::int64_t, VariableMonitoringMeta>& monitors, const Component& component,
const Variable& variable, const VariableCharacteristics& characteristics, const VariableAttribute& attribute,
const std::string& value_previous, const std::string& value_current)>;
using on_monitor_updated = std::function<void(const VariableMonitoringMeta& updated_monitor, const Component& component,
const Variable& variable, const VariableCharacteristics& characteristics,
const VariableAttribute& attribute, const std::string& current_value)>;
/// \brief This class manages access to the device model representation and to the device model interface and provides
/// functionality to support the use cases defined in the functional block Provisioning
class DeviceModel : public DeviceModelAbstract {
private:
DeviceModelMap device_model_map;
std::unique_ptr<DeviceModelStorageInterface> device_model;
/// \brief Listener for the internal change of a variable
std::vector<on_variable_changed> variable_listener;
/// \brief Listener for the internal update of a monitor
on_monitor_updated monitor_update_listener;
/// \brief Private helper method that does some checks with the device model representation in memory to evaluate if
/// a value for the given parameters can be requested. If it can be requested it will be retrieved from the device
/// model interface and the given \p value will be set to the value that was retrieved
/// \param component_id
/// \param variable_id
/// \param attribute_enum
/// \param value string reference to value: will be set to requested value if value is present
/// \param allow_write_only true to allow a writeOnly value to be read.
/// \return GetVariableStatusEnum that indicates the result of the request
GetVariableStatusEnum request_value_internal(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, std::string& value,
bool allow_write_only) const;
/// \brief Iterates over the given \p component_criteria and converts this to the variable names
/// (Active,Available,Enabled,Problem). If any of the variables can not be found as part of a component this
/// function returns false. If any of those variable's value is true, this function returns true (except for
/// criteria problem). If all variable's value are false, this function returns false
/// \param component_id
/// \param /// component_criteria
/// \return
bool component_criteria_match(const Component& component_id,
const std::vector<ComponentCriterionEnum>& component_criteria);
///
/// \brief Helper function to check if a variable has a value.
/// \param component_variable Component variable to check.
/// \param attribute Attribute to check.
///
/// \throws DeviceModelError if variable has no value or value is an empty string.
///
void check_variable_has_value(const ComponentVariable& component_variable,
const AttributeEnum attribute = AttributeEnum::Actual);
///
/// \brief Helper function to check if a required variable has a value.
/// \param required_variable Required component variable to check.
/// \param supported_versions The current supported ocpp versions.
/// \throws DeviceModelError if variable has no value or value is an empty string.
///
void check_required_variable(const RequiredComponentVariable& required_variable,
const std::vector<OcppProtocolVersion>& supported_versions);
///
/// \brief Loop over all required variables to check if they have a value.
///
/// This will check for all required variables from `ctrlr_component_variables.cpp` `required_variables`.
/// It will also check for specific required variables that belong to a specific controller. If a controller is not
/// available, the 'required' variables of that component are not required at this point.
///
/// \throws DeviceModelError if one of the variables does not have a value or value is an empty string.
///
void check_required_variables();
public:
/// \brief Constructor for the device model
/// \param device_model_storage_interface pointer to a device model interface class
explicit DeviceModel(std::unique_ptr<DeviceModelStorageInterface> device_model_storage_interface);
GetVariableStatusEnum get_variable(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, std::string& value,
bool allow_write_only = false) const override;
SetVariableStatusEnum set_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& value,
const std::string& source, bool allow_read_only = false) override;
bool create_network_configuration_slot_from_default_schema(std::int32_t new_slot) override;
SetVariableStatusEnum set_read_only_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& value,
const std::string& source) override;
SetVariableStatusEnum clear_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& source) override;
std::optional<MutabilityEnum> get_mutability(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum) override;
std::optional<VariableMetaData> get_variable_meta_data(const Component& component_id,
const Variable& variable_id) override;
std::vector<ReportData> get_base_report_data(const ReportBaseEnum& report_base) override;
std::vector<ReportData> get_custom_report_data(
const std::optional<std::vector<ComponentVariable>>& component_variables = std::nullopt,
const std::optional<std::vector<ComponentCriterionEnum>>& component_criteria = std::nullopt) override;
std::vector<SetMonitoringResult>
set_monitors(const std::vector<SetMonitoringData>& requests,
const VariableMonitorType type = VariableMonitorType::CustomMonitor) override;
bool update_monitor_reference(std::int32_t monitor_id, const std::string& reference_value) override;
std::vector<VariableMonitoringPeriodic> get_periodic_monitors() override;
std::vector<MonitoringData> get_monitors(const std::vector<MonitoringCriterionEnum>& criteria,
const std::vector<ComponentVariable>& component_variables) override;
std::vector<ClearMonitoringResult> clear_monitors(const std::vector<int>& request_ids,
bool allow_protected = false) override;
std::int32_t clear_custom_monitors() override;
void register_variable_listener(on_variable_changed&& listener) override {
variable_listener.push_back(std::move(listener));
}
void register_monitor_listener(on_monitor_updated&& listener) override {
monitor_update_listener = std::move(listener);
}
void check_integrity(const std::map<std::int32_t, std::int32_t>& evse_connector_structure) override;
};
} // namespace v2
} // namespace ocpp
#endif // DEVICE_MODEL_HPP

View File

@@ -0,0 +1,15 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/v2/device_model_base.hpp>
#include <ocpp/v2/device_model_interface.hpp>
namespace ocpp {
namespace v2 {
class DeviceModelAbstract : public DeviceModelBase, public DeviceModelInterface {};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,135 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <everest/logging.hpp>
#include <ocpp/v2/comparators.hpp>
#include <ocpp/v2/device_model_helpers.hpp>
#include <ocpp/v2/device_model_interface.hpp>
namespace ocpp {
namespace v2 {
/// \brief Response to requesting a value from the device model
/// \tparam T
template <typename T> struct RequestDeviceModelResponse {
GetVariableStatusEnum status;
std::optional<T> value;
};
/// \brief Base class for device model implementations, provides templated getters for variable attribute values
class DeviceModelBase {
public:
// ============================================================================
// Value getters
// ============================================================================
/// \brief Retrieves a variable attribute value
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \return The requested value
template <typename T>
T get_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) const {
std::string value;
const auto status = request_value_internal(component_id, variable_id, attribute_enum, value, true);
if (status != GetVariableStatusEnum::Accepted) {
EVLOG_critical << "Required value " << variable_id.name << " of component " << component_id.name
<< " could not be retrieved";
EVLOG_AND_THROW(std::runtime_error("Required value not available"));
}
return to_specific_type<T>(value);
}
/// \brief Retrieves a variable attribute value
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param component_variable The component and variable
/// \param attribute_enum The attribute
/// \return The requested value
template <typename T>
T get_value(const ComponentVariable& component_variable,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) const {
if (!component_variable.variable.has_value()) {
EVLOG_critical << "ComponentVariable has no variable set for component: " << component_variable.component;
EVLOG_AND_THROW(std::runtime_error("ComponentVariable has no variable set"));
}
return get_value<T>(component_variable.component, component_variable.variable.value(), attribute_enum);
}
/// \brief Retrieves an optional variable attribute value
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \return The requested value or std::nullopt
template <typename T>
std::optional<T> get_optional_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) const {
std::string value;
const auto status = request_value_internal(component_id, variable_id, attribute_enum, value, true);
if (status != GetVariableStatusEnum::Accepted) {
return std::nullopt;
}
try {
return to_specific_type<T>(value);
} catch (const std::exception&) {
return std::nullopt;
}
}
/// \brief Retrieves an optional variable attribute value
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param component_variable The component and variable
/// \param attribute_enum The attribute
/// \return The requested value or std::nullopt
template <typename T>
std::optional<T> get_optional_value(const ComponentVariable& component_variable,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) const {
if (!component_variable.variable.has_value()) {
return std::nullopt;
}
return get_optional_value<T>(component_variable.component, component_variable.variable.value(), attribute_enum);
}
/// \brief Requests a value of a VariableAttribute specified by combination of \p component_id and \p variable_id
/// from the device model
/// \tparam T datatype of the value that is requested
/// \param component_id
/// \param variable_id
/// \param attribute_enum
/// \return Response to request that contains status of the request and the requested value as std::optional<T> .
/// The value is present if the status is GetVariableStatusEnum::Accepted
template <typename T>
RequestDeviceModelResponse<T> request_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum) const {
std::string value;
const auto status = request_value_internal(component_id, variable_id, attribute_enum, value, false);
if (status != GetVariableStatusEnum::Accepted) {
return {status, std::nullopt};
}
try {
return {status, to_specific_type<T>(value)};
} catch (const std::exception&) {
return {GetVariableStatusEnum::Rejected, std::nullopt};
}
}
private:
virtual GetVariableStatusEnum request_value_internal(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, std::string& value,
bool allow_write_only = false) const = 0;
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,157 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <optional>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <everest/logging.hpp>
#include <ocpp/common/utils.hpp>
#include <ocpp/v2/device_model_interface.hpp>
#include <ocpp/v2/ocpp_types.hpp>
namespace ocpp {
namespace v2 {
template <typename T> T to_specific_type(const std::string& value) {
static_assert(std::is_same_v<T, std::string> || std::is_same_v<T, int> || std::is_same_v<T, double> ||
std::is_same_v<T, size_t> || std::is_same_v<T, DateTime> || std::is_same_v<T, bool> ||
std::is_same_v<T, std::uint64_t>,
"Requested unknown datatype");
if constexpr (std::is_same_v<T, std::string>) {
return value;
} else if constexpr (std::is_same_v<T, int>) {
return std::stoi(value);
} else if constexpr (std::is_same_v<T, double>) {
return std::stod(value);
} else if constexpr (std::is_same_v<T, std::size_t>) {
const std::size_t res = std::stoul(value);
return res;
} else if constexpr (std::is_same_v<T, DateTime>) {
return DateTime(value);
} else if constexpr (std::is_same_v<T, bool>) {
if (!is_boolean(value)) {
throw std::invalid_argument("Invalid boolean value: " + value);
}
return ocpp::conversions::string_to_bool(value);
} else if constexpr (std::is_same_v<T, std::uint64_t>) {
return std::stoull(value);
}
}
template <DataEnum T> auto to_specific_type_auto(const std::string& value) {
static_assert(T == DataEnum::string || T == DataEnum::integer || T == DataEnum::decimal ||
T == DataEnum::dateTime || T == DataEnum::boolean,
"Requested unknown datatype");
if constexpr (T == DataEnum::string) {
return to_specific_type<std::string>(value);
} else if constexpr (T == DataEnum::integer) {
return to_specific_type<int>(value);
} else if constexpr (T == DataEnum::decimal) {
return to_specific_type<double>(value);
} else if constexpr (T == DataEnum::dateTime) {
return to_specific_type<DateTime>(value);
} else if constexpr (T == DataEnum::boolean) {
return to_specific_type<bool>(value);
}
}
template <DataEnum T> bool is_type_numeric() {
static_assert(T == DataEnum::string || T == DataEnum::integer || T == DataEnum::decimal ||
T == DataEnum::dateTime || T == DataEnum::boolean || T == DataEnum::OptionList ||
T == DataEnum::SequenceList || T == DataEnum::MemberList,
"Requested unknown datatype");
if constexpr (T == DataEnum::integer || T == DataEnum::decimal) {
return true;
} else {
return false;
}
}
/// \brief Gets a variable attribute value from the device model
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param dm The device model interface
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \return The requested value
/// \throws std::runtime_error if the value cannot be retrieved
template <typename T>
T get_value(const DeviceModelInterface& dm, const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) {
std::string value;
const auto status = dm.get_variable(component_id, variable_id, attribute_enum, value, true);
if (status != GetVariableStatusEnum::Accepted) {
throw std::runtime_error("Required value not available");
}
return to_specific_type<T>(value);
}
/// \brief Gets a variable attribute value from the device model
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param dm The device model interface
/// \param component_variable The component and variable
/// \param attribute_enum The attribute
/// \return The requested value
/// \throws std::runtime_error if the value cannot be retrieved
template <typename T>
T get_value(const DeviceModelInterface& dm, const ComponentVariable& component_variable,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) {
if (!component_variable.variable.has_value()) {
throw std::runtime_error("ComponentVariable has no variable set");
}
return get_value<T>(dm, component_variable.component, component_variable.variable.value(), attribute_enum);
}
/// \brief Gets an optional variable attribute value from the device model
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param dm The device model interface
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \return The requested value or std::nullopt
template <typename T>
std::optional<T> get_optional_value(const DeviceModelInterface& dm, const Component& component_id,
const Variable& variable_id,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) {
std::string value;
const auto status = dm.get_variable(component_id, variable_id, attribute_enum, value, true);
if (status != GetVariableStatusEnum::Accepted) {
return std::nullopt;
}
try {
return to_specific_type<T>(value);
} catch (const std::exception& e) {
// Conversion failed: the value is present in the DM but cannot be represented as T
// (malformed integer, malformed bool, out-of-range, etc.). Log at warning level so a
// caller seeing std::nullopt can distinguish "absent" from "present-but-unparseable".
EVLOG_warning << "Failed to convert device model value '" << value << "' to requested type for component '"
<< component_id.name.get() << "', variable '" << variable_id.name.get() << "': " << e.what();
return std::nullopt;
}
}
/// \brief Gets an optional variable attribute value from the device model
/// \tparam T The target type (must be: std::string, int, double, size_t, DateTime, bool, or uint64_t)
/// \param dm The device model interface
/// \param component_variable The component and variable
/// \param attribute_enum The attribute
/// \return The requested value or std::nullopt
template <typename T>
std::optional<T> get_optional_value(const DeviceModelInterface& dm, const ComponentVariable& component_variable,
const AttributeEnum& attribute_enum = AttributeEnum::Actual) {
if (!component_variable.variable.has_value()) {
return std::nullopt;
}
return get_optional_value<T>(dm, component_variable.component, component_variable.variable.value(), attribute_enum);
}
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,220 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#ifndef DEVICE_MODEL_INTERFACE_HPP
#define DEVICE_MODEL_INTERFACE_HPP
#include <optional>
#include <string>
#include <vector>
#include <ocpp/v2/enums.hpp>
#include <ocpp/v2/ocpp_types.hpp>
namespace ocpp {
namespace v2 {
/// \brief Helper struct that holds values that don't have spec coverage
struct VariableMonitoringMeta {
VariableMonitoring monitor;
VariableMonitorType type;
std::optional<std::string> reference_value;
};
/// \brief Helper struct that contains all monitors related to a variable that are of a periodic type
struct VariableMonitoringPeriodic {
Component component;
Variable variable;
std::vector<VariableMonitoringMeta> monitors;
};
/// \brief Helper struct that combines VariableCharacteristics and VariableMonitoring
struct VariableMetaData {
VariableCharacteristics characteristics;
std::unordered_map<std::int64_t, VariableMonitoringMeta> monitors;
std::optional<std::string> source;
};
using VariableMap = std::map<Variable, VariableMetaData>;
using DeviceModelMap = std::map<Component, VariableMap>;
class DeviceModelError : public std::exception {
public:
[[nodiscard]] const char* what() const noexcept override {
return this->reason.c_str();
}
explicit DeviceModelError(std::string msg) : reason(std::move(msg)) {
}
explicit DeviceModelError(const char* msg) : reason(std::string(msg)) {
}
private:
std::string reason;
};
/// \brief Pure abstract interface for device model access.
class DeviceModelInterface {
public:
virtual ~DeviceModelInterface() = default;
// ============================================================================
// Value getters
// ============================================================================
/// \brief Gets a variable attribute value
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \param value The value to get (as string)
/// \param allow_write_only If true, write-only variables can be accessed
/// \return Result of the requested operation
virtual GetVariableStatusEnum get_variable(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, std::string& value,
bool allow_write_only = false) const = 0;
// ============================================================================
// Value setters
// ============================================================================
/// \brief Sets a variable attribute value
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \param value The value to set (as string)
/// \param source The source of the value (e.g., 'csms', 'default', 'internal')
/// \param allow_read_only If true, read-only variables can be changed
/// \return Result of the requested operation
virtual SetVariableStatusEnum set_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& value,
const std::string& source, bool allow_read_only = false) = 0;
/// \brief Sets a read-only variable attribute value (only works on certain allowed components)
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \param value The value to set (as string)
/// \param source The source of the value (e.g., 'csms', 'default', 'internal')
/// \return Result of the requested operation
virtual SetVariableStatusEnum set_read_only_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& value,
const std::string& source) = 0;
/// \brief Clear the Actual attribute of \p variable on \p component, bypassing
/// validate_value AND the read-only mutability check. Intended for spec-mandated
/// clears where the empty-string sentinel would otherwise fail length / range
/// constraints (e.g. B09.FR.27 clearing a per-slot BasicAuthPassword that has
/// minLimit=16). Do not use to clear ReadOnly attributes outside of an explicit
/// spec-mandated clear path: this method does not enforce the mutability
/// allowlist that set_read_only_value uses.
/// \param source identifier for the change source ("internal" / OCPP source)
/// \return SetVariableStatusEnum reflecting the storage write outcome
virtual SetVariableStatusEnum clear_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& source) = 0;
// ============================================================================
// Metadata and monitoring
// ============================================================================
/// \brief Get the mutability for the given component, variable and attribute
/// \param component_id The component
/// \param variable_id The variable
/// \param attribute_enum The attribute
/// \return The mutability of the given component variable, or std::nullopt
virtual std::optional<MutabilityEnum> get_mutability(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum) = 0;
/// \brief Gets the VariableMetaData for the given component and variable
/// \param component_id The component
/// \param variable_id The variable
/// \return VariableMetaData or std::nullopt if not present
virtual std::optional<VariableMetaData> get_variable_meta_data(const Component& component_id,
const Variable& variable_id) = 0;
/// \brief Gets the ReportData for the specified report base
/// \param report_base The report base filter
/// \return Vector of ReportData
virtual std::vector<ReportData> get_base_report_data(const ReportBaseEnum& report_base) = 0;
/// \brief Gets the ReportData for the specified filters
/// \param component_variables Optional component variables filter
/// \param component_criteria Optional component criteria filter
/// \return Vector of ReportData
virtual std::vector<ReportData> get_custom_report_data(
const std::optional<std::vector<ComponentVariable>>& component_variables = std::nullopt,
const std::optional<std::vector<ComponentCriterionEnum>>& component_criteria = std::nullopt) = 0;
// ============================================================================
// Monitoring operations
// ============================================================================
/// \brief Sets the given monitor requests in the device model
/// \param requests The monitoring requests
/// \param type The type of monitors (HardWiredMonitor, PreconfiguredMonitor, CustomMonitor)
/// \return List of results of the requested operation
virtual std::vector<SetMonitoringResult>
set_monitors(const std::vector<SetMonitoringData>& requests,
const VariableMonitorType type = VariableMonitorType::CustomMonitor) = 0;
/// \brief Updates the reference value for a monitor
/// \param monitor_id The monitor ID
/// \param reference_value The new reference value
/// \return true if successful, false otherwise
virtual bool update_monitor_reference(std::int32_t monitor_id, const std::string& reference_value) = 0;
/// \brief Gets all periodic monitors
/// \return Vector of periodic monitors
virtual std::vector<VariableMonitoringPeriodic> get_periodic_monitors() = 0;
/// \brief Gets the monitoring data for the requested criteria and component variables
/// \param criteria The monitoring criteria
/// \param component_variables The component variables to get monitors for
/// \return List of monitoring data
virtual std::vector<MonitoringData> get_monitors(const std::vector<MonitoringCriterionEnum>& criteria,
const std::vector<ComponentVariable>& component_variables) = 0;
/// \brief Clears the given monitor IDs from the registered monitors
/// \param request_ids The monitor IDs to clear
/// \param allow_protected If true, non-custom monitors can be deleted
/// \return List of results of the requested operation
virtual std::vector<ClearMonitoringResult> clear_monitors(const std::vector<int>& request_ids,
bool allow_protected = false) = 0;
/// \brief Clears all custom monitors (set by the CSMS)
/// \return Count of monitors deleted
virtual std::int32_t clear_custom_monitors() = 0;
/// \brief Registers a listener for variable changes
/// \param listener The listener function to register
virtual void register_variable_listener(
std::function<void(const std::unordered_map<std::int64_t, VariableMonitoringMeta>& monitors,
const Component& component, const Variable& variable,
const VariableCharacteristics& characteristics, const VariableAttribute& attribute,
const std::string& value_previous, const std::string& value_current)>&& listener) = 0;
/// \brief Registers a listener for monitor updates
/// \param listener The listener function to register
virtual void register_monitor_listener(
std::function<void(const VariableMonitoringMeta& updated_monitor, const Component& component,
const Variable& variable, const VariableCharacteristics& characteristics,
const VariableAttribute& attribute, const std::string& current_value)>&& listener) = 0;
// ============================================================================
// Integrity check
// ============================================================================
/// \brief Check data integrity of the device model
/// \param evse_connector_structure The EVSE connector structure
virtual void check_integrity(const std::map<std::int32_t, std::int32_t>& evse_connector_structure) = 0;
/// \brief Create a fresh NetworkConfiguration_<new_slot> from the embedded default schema.
/// \param new_slot New NetworkConfiguration instance to create.
/// \return true on success; false on failure.
virtual bool create_network_configuration_slot_from_default_schema(std::int32_t /*new_slot*/) {
return false;
}
};
} // namespace v2
} // namespace ocpp
#endif // DEVICE_MODEL_INTERFACE_HPP

View File

@@ -0,0 +1,111 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include <map>
#include <memory>
#include <ocpp/common/support_older_cpp_versions.hpp>
#include <optional>
#include <ocpp/v2/device_model_abstract.hpp>
#include <ocpp/v2/enums.hpp>
#include <ocpp/v2/ocpp_types.hpp>
namespace ocpp {
namespace v2 {
/// \brief Abstract base class for device model interface. This class provides an interface for accessing and modifying
/// device model data. Implementations of this class should provide concrete implementations for the virtual methods
/// declared here.
class DeviceModelStorageInterface {
public:
virtual ~DeviceModelStorageInterface() = default;
/// \brief Gets the device model from the device model interface
/// \return std::map<Component, std::map<Variable, VariableMetaData>> that will contain a full representation of the
/// device model except for the VariableAttribute(s) of each Variable.
virtual DeviceModelMap get_device_model() = 0;
/// \brief Gets a VariableAttribute from the storage if present
/// \param component_id
/// \param variable_id
/// \param attribute_enum
/// \return VariableAttribute or std::nullopt if not present in the storage
virtual std::optional<VariableAttribute> get_variable_attribute(const Component& component_id,
const Variable& variable_id,
const AttributeEnum& attribute_enum) = 0;
/// \brief Gets a std::vector<VariableAttribute> from the storage.
/// \param component_id
/// \param variable_id
/// \param attribute_enum optionally specifies an AttributeEnum. In this case this std::vector will contain max. one
/// element
/// \return std::vector<VariableAttribute> with maximum size of 4 elements (Actual, Target, MinSet, MaxSet) and
/// minum size of 0 elements (if no VariableAttribute is present for the requested parameters)
virtual std::vector<VariableAttribute>
get_variable_attributes(const Component& component_id, const Variable& variable_id,
const std::optional<AttributeEnum>& attribute_enum = std::nullopt) = 0;
/// \brief Sets the value of an VariableAttribute if present
/// \param component_id
/// \param variable_id
/// \param attribute_enum
/// \param value
/// \param source The source of the value.
/// \return Accepted if the value could be set in the storage, RebootRequired or Rejected if not (immediately
/// possible)
virtual SetVariableStatusEnum set_variable_attribute_value(const Component& component_id,
const Variable& variable_id,
const AttributeEnum& attribute_enum,
const std::string& value, const std::string& source) = 0;
/// \brief Inserts or replaces a variable monitor in the database
/// \param data Monitor data to set
/// \return true if the value could be inserted, or valse otherwise
virtual std::optional<VariableMonitoringMeta> set_monitoring_data(const SetMonitoringData& data,
const VariableMonitorType type) = 0;
/// \brief Updates the reference value for a monitor. The reference values is used for the
/// delta monitors to detect a trigger, and must be updated when a trigger is detected
/// \param monitor_id Id of the monitor that requires the reference changed
/// \param reference_value Value to replace the reference with
/// \return true if the reference value could be updated, false otherwise
virtual bool update_monitoring_reference(const std::int32_t monitor_id, const std::string& reference_value) = 0;
/// \brief Returns all the monitors currently in the database based
/// on the provided filtering criteria
/// \param criteria
/// \param component_id
/// \param variable_id
/// \return the monitoring data if it could be found or an empty vector
virtual std::vector<VariableMonitoringMeta>
get_monitoring_data(const std::vector<MonitoringCriterionEnum>& criteria, const Component& component_id,
const Variable& variable_id) = 0;
/// \brief Clears a single monitor based on the ID from the database
/// \param monitor_id Monitor ID
/// \param allow_protected If we are allowed to delete non-custom monitors
/// \return if not Accepted, NotFound if the monitor could not be
/// found, or Rejected if it is a protected monitor
virtual ClearMonitoringStatusEnum clear_variable_monitor(int monitor_id, bool allow_protected) = 0;
/// \brief Clears all custom monitors (that were added by the CSMS)
/// from the database
/// \return count of monitors deleted, or 0 if none were deleted
virtual std::int32_t clear_custom_variable_monitors() = 0;
/// \brief Check data integrity of the stored data:
/// For "required" variables, assert values exist. Checks might be extended in the future.
virtual void check_integrity() = 0;
/// \brief Create a fresh NetworkConfiguration_<new_slot> from the embedded default schema.
/// \param new_slot The instance index to create.
/// \return true on success; false on failure.
virtual bool create_network_configuration_slot_from_default_schema(std::int32_t /*new_slot*/) {
return false;
}
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,88 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#ifndef DEVICE_MODEL_STORAGE_SQLITE_HPP
#define DEVICE_MODEL_STORAGE_SQLITE_HPP
#include <filesystem>
#include <sqlite3.h>
#include <everest/database/sqlite/connection.hpp>
#include <everest/logging.hpp>
#include <ocpp/v2/device_model_storage_interface.hpp>
namespace ocpp {
namespace v2 {
class DeviceModelStorageSqlite : public DeviceModelStorageInterface {
private:
std::unique_ptr<everest::db::sqlite::ConnectionInterface> db;
int get_component_id(const Component& component_id);
int get_variable_id(const Component& component_id, const Variable& variable_id);
void initialize_connection(const fs::path& db_path);
public:
/// \brief Opens SQLite connection at given \p db_path
///
/// If init_db is true, all other paths must be given as well.
///
/// \param db_path Path to database
/// \param migration_files_path Path to the migration files to initialize the database (only needs to be set if
/// `init_db` is true)
/// \param config_path Path to the device model config used to initialize the database
///
explicit DeviceModelStorageSqlite(const fs::path& db_path, const std::filesystem::path& migration_files_path,
const std::filesystem::path& config_path);
/// \brief Opens SQLite connection at given \p db_path
///
/// \param db_path Path to database
/// \param migration_files_path Path to the migration files to initialize the database
///
DeviceModelStorageSqlite(const fs::path& db_path, const fs::path& migration_files_path);
/// \brief Opens SQLite connection at given \p db_path
///
/// \param db_path Path to database
DeviceModelStorageSqlite(const fs::path& db_path);
~DeviceModelStorageSqlite() override = default;
std::map<Component, std::map<Variable, VariableMetaData>> get_device_model() final;
std::optional<VariableAttribute> get_variable_attribute(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum) final;
std::vector<VariableAttribute> get_variable_attributes(const Component& component_id, const Variable& variable_id,
const std::optional<AttributeEnum>& attribute_enum) final;
SetVariableStatusEnum set_variable_attribute_value(const Component& component_id, const Variable& variable_id,
const AttributeEnum& attribute_enum, const std::string& value,
const std::string& source) final;
std::optional<VariableMonitoringMeta> set_monitoring_data(const SetMonitoringData& data,
const VariableMonitorType type) final;
bool update_monitoring_reference(const std::int32_t monitor_id, const std::string& reference_value) final;
std::vector<VariableMonitoringMeta> get_monitoring_data(const std::vector<MonitoringCriterionEnum>& criteria,
const Component& component_id,
const Variable& variable_id) final;
ClearMonitoringStatusEnum clear_variable_monitor(int monitor_id, bool allow_protected) final;
std::int32_t clear_custom_variable_monitors() final;
void check_integrity() final;
bool create_network_configuration_slot_from_default_schema(std::int32_t new_slot) final;
};
} // namespace v2
} // namespace ocpp
#endif // DEVICE_MODEL_STORAGE_SQLITE_HPP

View File

@@ -0,0 +1,51 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2025 Pionix GmbH and Contributors to EVerest
// Manually added enums for OCPP, for the auto-generated ones see 'ocpp_enums.hpp'
#ifndef OCPP_V2_ENUMS_HPP
#define OCPP_V2_ENUMS_HPP
#include <ocpp/v2/ocpp_enums.hpp>
#include <cstdint>
#include <string>
namespace ocpp {
namespace v2 {
enum class VariableMonitorType {
HardWiredMonitor,
PreconfiguredMonitor,
CustomMonitor,
};
namespace conversions {
/// \brief Converts the given std::string \p s to VariableMonitorType
/// \returns a VariableMonitorType from a string representation
VariableMonitorType string_to_variable_monitor_type(const std::string& s);
/// \brief Converts the given VariableMonitorType \p type to std::string
/// \returns a string representation of the VariableMonitorType
EventNotificationEnum variable_monitor_type_to_event_notification_type(const VariableMonitorType& type);
} // namespace conversions
namespace MonitoringLevelSeverity {
constexpr std::int32_t Danger = 0;
constexpr std::int32_t HardwareFailure = 1;
constexpr std::int32_t SystemFailure = 2;
constexpr std::int32_t Critical = 3;
constexpr std::int32_t Error = 4;
constexpr std::int32_t Alert = 5;
constexpr std::int32_t Warning = 6;
constexpr std::int32_t Notice = 7;
constexpr std::int32_t Informational = 8;
constexpr std::int32_t Debug = 9;
constexpr std::int32_t MIN = Danger;
constexpr std::int32_t MAX = Debug;
} // namespace MonitoringLevelSeverity
} // namespace v2
} // namespace ocpp
#endif // OCPP_V2_ENUMS_HPP

View File

@@ -0,0 +1,309 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2023 Pionix GmbH and Contributors to EVerest
#pragma once
#include <functional>
#include <map>
#include <memory>
#include <ocpp/v2/average_meter_values.hpp>
#include <ocpp/v2/component_state_manager.hpp>
#include <ocpp/v2/connector.hpp>
#include <ocpp/v2/database_handler.hpp>
#include <ocpp/v2/device_model_abstract.hpp>
#include <ocpp/v2/ocpp_types.hpp>
#include <ocpp/v2/transaction.hpp>
namespace ocpp {
namespace v2 {
enum class CurrentPhaseType {
AC,
DC,
Unknown,
};
class EvseInterface {
public:
virtual ~EvseInterface() = default;
/// \brief Return the evse_id of this EVSE
/// \return
virtual std::int32_t get_id() const = 0;
/// \brief Returns the number of connectors of this EVSE
/// \return
virtual std::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(CiString<20> connector_type) const = 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<CiString<20>> connector_type) = 0;
/// \brief Opens a new transaction
/// \param transaction_id id of the transaction
/// \param connector_id id of the connector
/// \param timestamp timestamp of the start of the transaction
/// \param meter_start start meter value of the transaction
/// \param id_token id_token with which the transaction was authorized / started
/// \param group_id_token optional group id_token
/// \param reservation optional reservation_id if evse was reserved
/// \param sampled_data_tx_updated_interval Interval between sampling of metering (or other) data, intended to
/// be transmitted via TransactionEventRequest (eventType = Updated) messages
virtual void open_transaction(const std::string& transaction_id, const std::int32_t connector_id,
const DateTime& timestamp, const MeterValue& meter_start,
const std::optional<IdToken>& id_token, const std::optional<IdToken>& group_id_token,
const std::optional<std::int32_t> reservation_id,
const ChargingStateEnum charging_state) = 0;
/// \brief Closes the transaction on this evse by adding the given \p timestamp \p meter_stop and \p reason .
/// \param timestamp
/// \param meter_stop
/// \param reason
virtual void close_transaction(const DateTime& timestamp, const MeterValue& meter_stop,
const ReasonEnum& reason) = 0;
/// \brief Start checking if the max energy on invalid id has exceeded.
/// Will call pause_charging_callback when that happens.
virtual void start_checking_max_energy_on_invalid_id() = 0;
/// \brief Indicates if a transaction is active at this evse
/// \return
virtual bool has_active_transaction() const = 0;
/// \brief Indicates if a transaction is active at this evse at the given \p connector_id
/// \param connector_id id of the connector of the evse
/// \return
virtual bool has_active_transaction(const std::int32_t connector_id) const = 0;
/// \brief Releases the reference of the transaction on this evse
virtual void release_transaction() = 0;
/// \brief Returns a pointer to the EnhancedTransaction of this evse
/// \return pointer to transaction (nullptr if no transaction is active)
virtual std::unique_ptr<EnhancedTransaction>& get_transaction() = 0;
/// \brief Submits the given \p event to the state machine controller of the connector with the given
/// \p connector_id
/// \param connector_id id of the connector of the evse
/// \param event
virtual void submit_event(const std::int32_t connector_id, ConnectorEvent event) = 0;
/// \brief Event handler that should be called when a new meter_value for this evse is present
/// \param meter_value
virtual void on_meter_value(const MeterValue& meter_value) = 0;
/// \brief Returns the last present meter value for this evse
/// \return
virtual MeterValue get_meter_value() = 0;
/// @brief Return the idle meter values for this evse
/// \return MeterValue type
virtual MeterValue get_idle_meter_value() = 0;
/// @brief Clear the idle meter values for this evse
virtual void clear_idle_meter_values() = 0;
/// \brief Returns a pointer to the connector with ID \param connector_id in this EVSE.
virtual Connector* get_connector(std::int32_t connector_id) const = 0;
/// \brief Gets the effective Operative/Inoperative status of this EVSE
virtual OperationalStatusEnum get_effective_operational_status() = 0;
/// \brief Switches the operative status of the EVSE
/// \param new_status The operative status to switch to
/// \param persist True the updated operative state should be persisted
virtual void set_evse_operative_status(OperationalStatusEnum new_status, bool persist) = 0;
/// \brief Switches the operative status of a connector within this EVSE
/// \param connector_id The ID of the connector
/// \param new_status The operative status to switch to
/// \param persist True the updated operative state should be persisted
virtual void set_connector_operative_status(std::int32_t connector_id, OperationalStatusEnum new_status,
bool persist) = 0;
/// \brief Restores the operative status of a connector within this EVSE to the persisted status and recomputes its
/// effective status \param connector_id The ID of the connector
virtual void restore_connector_operative_status(std::int32_t connector_id) = 0;
/// \brief Get the operational status of a connector within this evse.
/// \param connector_id The id of the connector.
/// \return The operational status.
virtual OperationalStatusEnum get_connector_effective_operational_status(const std::int32_t connector_id) = 0;
/// \brief Returns the phase type for the EVSE based on its SupplyPhases. It can be AC, DC, or Unknown.
virtual CurrentPhaseType get_current_phase_type() = 0;
///
/// \brief Set metervalue triggers for California Pricing.
/// \param trigger_metervalue_on_power_kw Send metervalues on this amount of kw (with hysteresis).
/// \param trigger_metervalue_on_energy_kwh Send metervalues when this kwh is reached.
/// \param trigger_metervalue_at_time Send metervalues at a specific time.
/// \param send_metervalue_function Function used to send the metervalues.
/// \param io_context io context for the timers.
///
virtual void set_meter_value_pricing_triggers(
std::optional<double> trigger_metervalue_on_power_kw, std::optional<double> trigger_metervalue_on_energy_kwh,
std::optional<DateTime> trigger_metervalue_at_time,
std::function<void(const std::vector<MeterValue>& meter_values)> send_metervalue_function,
boost::asio::io_context& io_context) = 0;
};
/// \brief Represents an EVSE. An EVSE can contain multiple Connector objects, but can only supply energy to one of
/// them.
class Evse : public EvseInterface {
private:
std::int32_t evse_id;
DeviceModelAbstract& device_model;
std::map<std::int32_t, std::unique_ptr<Connector>> id_connector_map;
std::function<void(const MeterValue& meter_value, EnhancedTransaction& transaction)> transaction_meter_value_req;
std::function<void(std::int32_t evse_id)> pause_charging_callback;
std::unique_ptr<EnhancedTransaction> transaction; // pointer to active transaction (can be nullptr)
MeterValue meter_value; // represents current meter value
std::recursive_mutex meter_value_mutex;
Everest::SteadyTimer sampled_meter_values_timer;
std::shared_ptr<DatabaseHandler> database_handler;
std::optional<double> trigger_metervalue_on_power_kw;
std::optional<double> trigger_metervalue_on_energy_kwh;
std::unique_ptr<Everest::SystemTimer> trigger_metervalue_at_time_timer;
std::optional<double> last_triggered_metervalue_power_kw;
std::function<void(const std::vector<MeterValue>& meter_values)> send_metervalue_function;
boost::asio::io_context io_context;
/// \brief gets the active import energy meter value from meter_value, normalized to Wh.
std::optional<float> get_active_import_register_meter_value();
/// \brief function to check if the max energy has been exceeded, calls pause_charging_callback if so.
void check_max_energy_on_invalid_id();
/// \brief Start all metering timers referenced to \p timestamp
/// \param timestamp
void start_metering_timers(const DateTime& timestamp);
///
/// \brief Send metervalue to CSMS after a pricing trigger occured.
/// \param meter_value The metervalue to send.
///
void send_meter_value_on_pricing_trigger(const MeterValue& meter_value);
///
/// \brief Reset pricing triggers.
///
/// Resets timer, set all pricing trigger related members to std::nullopt and / or nullptr.
///
void reset_pricing_triggers();
AverageMeterValues aligned_data_updated;
AverageMeterValues aligned_data_tx_end;
/// \brief Perform a check to see if there is an open transaction and resume it if there is.
void try_resume_transaction();
/// \brief Delete the transaction related to this EVSE from the database, if there is one.
void delete_database_transaction();
/// \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<CiString<20>> get_evse_connector_type(const std::uint32_t connector_id) const;
public:
/// \brief Construct a new Evse object
/// \param evse_id id of the evse
/// \param number_of_connectors of the evse
/// \param device_model reference to the device model
/// \param database_handler shared_ptr to the database handler
/// \param component_state_manager shared_ptr to the component state manager
/// \param transaction_meter_value_req that is called to transmit a meter value request related to a transaction
/// \param pause_charging_callback that is called when the charging should be paused due to max energy on
/// invalid id being exceeded
Evse(const std::int32_t evse_id, const std::int32_t number_of_connectors, DeviceModelAbstract& device_model,
std::shared_ptr<DatabaseHandler> database_handler,
std::shared_ptr<ComponentStateManagerInterface> component_state_manager,
const std::function<void(const MeterValue& meter_value, EnhancedTransaction& transaction)>&
transaction_meter_value_req,
const std::function<void(std::int32_t evse_id)>& pause_charging_callback);
~Evse() override;
std::int32_t get_id() const override;
std::uint32_t get_number_of_connectors() const override;
bool does_connector_exist(const CiString<20> connector_type) const override;
std::optional<ConnectorStatusEnum> get_connector_status(std::optional<CiString<20>> connector_type) override;
void open_transaction(const std::string& transaction_id, const std::int32_t connector_id, const DateTime& timestamp,
const MeterValue& meter_start, const std::optional<IdToken>& id_token,
const std::optional<IdToken>& group_id_token,
const std::optional<std::int32_t> reservation_id,
const ChargingStateEnum charging_state) override;
void close_transaction(const DateTime& timestamp, const MeterValue& meter_stop, const ReasonEnum& reason) override;
/// \brief Start checking if the max energy on invalid id has exceeded.
/// Will call pause_charging_callback when that happens.
void start_checking_max_energy_on_invalid_id() override;
bool has_active_transaction() const override;
bool has_active_transaction(const std::int32_t connector_id) const override;
void release_transaction() override;
std::unique_ptr<EnhancedTransaction>& get_transaction() override;
void submit_event(const std::int32_t connector_id, ConnectorEvent event) override;
void on_meter_value(const MeterValue& meter_value) override;
MeterValue get_meter_value() override;
MeterValue get_idle_meter_value() override;
void clear_idle_meter_values() override;
Connector* get_connector(std::int32_t connector_id) const override;
OperationalStatusEnum get_effective_operational_status() override;
void set_evse_operative_status(OperationalStatusEnum new_status, bool persist) override;
void set_connector_operative_status(std::int32_t connector_id, OperationalStatusEnum new_status,
bool persist) override;
void restore_connector_operative_status(std::int32_t connector_id) override;
OperationalStatusEnum get_connector_effective_operational_status(const std::int32_t connector_id) override;
CurrentPhaseType get_current_phase_type() override;
///
/// \brief Set pricing triggers to send the meter value.
/// \param trigger_metervalue_on_power_kw Trigger for this amount of kw
/// \param trigger_metervalue_on_energy_kwh Trigger when amount of kwh is reached
/// \param trigger_metervalue_at_time Trigger for a specific time
/// \param send_metervalue_function Function to send metervalues when trigger 'fires'
/// \param io_context Io service needed for the timer
///
void set_meter_value_pricing_triggers(
std::optional<double> trigger_metervalue_on_power_kw, std::optional<double> trigger_metervalue_on_energy_kwh,
std::optional<DateTime> trigger_metervalue_at_time,
std::function<void(const std::vector<MeterValue>& meter_values)> send_metervalue_function,
boost::asio::io_context& io_context) override;
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,111 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2020 - 2024 Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/common/custom_iterators.hpp>
#include <ocpp/v2/evse.hpp>
namespace ocpp {
namespace v2 {
///
/// \brief Set all connectors of a given evse to unavailable.
/// \param evse The evse.
/// \param persist True if unavailability should persist. If it is set to false, there will be a check per
/// connector if it was already set to true and if that is the case, it will be persisted anyway.
///
void set_evse_connectors_unavailable(EvseInterface& evse, bool persist);
/// \brief Class used to access the Evse instances
class EvseManagerInterface {
public:
using EvseIterator = ForwardIterator<EvseInterface>;
/// \brief Default destructor
virtual ~EvseManagerInterface() = default;
/// \brief Get a reference to the evse with \p id
/// \note If \p id is not present this could throw an EvseOutOfRangeException
virtual EvseInterface& get_evse(std::int32_t id) = 0;
/// \brief Get a const reference to the evse with \p id
/// \note If \p id is not present this could throw an EvseOutOfRangeException
virtual const EvseInterface& get_evse(std::int32_t id) const = 0;
/// \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.
virtual bool does_connector_exist(const std::int32_t evse_id, const CiString<20> connector_type) const = 0;
/// \brief Check if an evse with \p id exists
virtual bool does_evse_exist(std::int32_t id) const = 0;
/// \brief Checks if all connectors are effectively inoperative.
/// If this is the case, calls the all_connectors_unavailable_callback
/// This is used e.g. to allow firmware updates once all transactions have finished
virtual bool are_all_connectors_effectively_inoperative() const = 0;
/// \brief Get the number of evses
virtual size_t get_number_of_evses() const = 0;
/// \brief Get evseid for the given transaction id.
/// \param transaction_id The transactionid
/// \return The evse id belonging the the transaction id. std::nullopt if there is no transaction with the given
/// transaction id.
///
virtual std::optional<std::int32_t> get_transaction_evseid(const CiString<36>& transaction_id) const = 0;
/// \brief Helper function to determine if there is any active transaction for the given \p evse
/// \param evse if optional is not set, this function will check if there is any transaction active for the whole
/// charging station
/// \return
virtual bool any_transaction_active(const std::optional<EVSE>& evse) const = 0;
///
/// \brief Check if the given evse is valid.
/// \param evse The evse to check.
/// \return True when evse is valid.
///
virtual bool is_valid_evse(const EVSE& evse) const = 0;
/// \brief Gets an iterator pointing to the first evse
virtual EvseIterator begin() = 0;
/// \brief Gets an iterator pointing past the last evse
virtual EvseIterator end() = 0;
};
class EvseManager : public EvseManagerInterface {
private:
std::vector<std::unique_ptr<EvseInterface>> evses;
public:
EvseManager(const std::map<std::int32_t, std::int32_t>& evse_connector_structure, DeviceModelAbstract& device_model,
std::shared_ptr<DatabaseHandler> database_handler,
std::shared_ptr<ComponentStateManagerInterface> component_state_manager,
const std::function<void(const MeterValue& meter_value, EnhancedTransaction& transaction)>&
transaction_meter_value_req,
const std::function<void(std::int32_t evse_id)>& pause_charging_callback);
EvseInterface& get_evse(std::int32_t id) override;
const EvseInterface& get_evse(const std::int32_t id) const override;
bool does_connector_exist(const std::int32_t evse_id, const CiString<20> connector_type) const override;
bool does_evse_exist(const std::int32_t id) const override;
bool are_all_connectors_effectively_inoperative() const override;
size_t get_number_of_evses() const override;
std::optional<std::int32_t> get_transaction_evseid(const CiString<36>& transaction_id) const override;
bool any_transaction_active(const std::optional<EVSE>& evse) const override;
bool is_valid_evse(const EVSE& evse) const override;
EvseIterator begin() override;
EvseIterator end() override;
};
} // namespace v2
} // namespace ocpp

View File

@@ -0,0 +1,94 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#pragma once
#include <ocpp/v2/message_handler.hpp>
namespace ocpp::v2 {
struct FunctionalBlockContext;
struct AuthorizationCacheEntry;
struct AuthorizeResponse;
struct ClearCacheRequest;
struct SendLocalListRequest;
struct GetLocalListVersionRequest;
class DatabaseHandlerInterface;
class AuthorizationInterface : public MessageHandlerInterface {
public:
~AuthorizationInterface() override = default;
virtual void start_auth_cache_cleanup_thread() = 0;
virtual AuthorizeResponse authorize_req(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) = 0;
virtual void trigger_authorization_cache_cleanup() = 0;
///\brief Calculate and update the authorization cache size in the device model
///
virtual void update_authorization_cache_size() = 0;
virtual bool is_auth_cache_ctrlr_enabled() = 0;
virtual void authorization_cache_insert_entry(const std::string& id_token_hash,
const IdTokenInfo& id_token_info) = 0;
virtual std::optional<AuthorizationCacheEntry> authorization_cache_get_entry(const std::string& id_token_hash) = 0;
virtual void authorization_cache_delete_entry(const std::string& id_token_hash) = 0;
/// \brief Validates provided \p id_token \p certificate and \p ocsp_request_data using CSMS, AuthCache or AuthList
/// \param id_token
/// \param certificate
/// \param ocsp_request_data
/// \return AuthorizeResponse containing the result of the validation
virtual AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) = 0;
};
class Authorization : public AuthorizationInterface {
private: // Members
const FunctionalBlockContext& context;
// threads and synchronization
bool auth_cache_cleanup_required;
std::condition_variable auth_cache_cleanup_cv;
std::mutex auth_cache_cleanup_mutex;
std::thread auth_cache_cleanup_thread;
std::atomic_bool auth_cache_cleanup_handler_running;
public:
explicit Authorization(const FunctionalBlockContext& context);
~Authorization() override;
void start_auth_cache_cleanup_thread() override;
void handle_message(const ocpp::EnhancedMessage<MessageType>& message) override;
AuthorizeResponse authorize_req(const IdToken id_token, const std::optional<ocpp::CiString<10000>>& certificate,
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) override;
void trigger_authorization_cache_cleanup() override;
void update_authorization_cache_size() override;
bool is_auth_cache_ctrlr_enabled() override;
void authorization_cache_insert_entry(const std::string& id_token_hash, const IdTokenInfo& id_token_info) override;
std::optional<AuthorizationCacheEntry> authorization_cache_get_entry(const std::string& id_token_hash) override;
void authorization_cache_delete_entry(const std::string& id_token_hash) override;
/// \brief Validates provided \p id_token \p certificate and \p ocsp_request_data using CSMS, AuthCache or AuthList
/// \param id_token
/// \param certificate
/// \param ocsp_request_data
/// \return AuthorizeResponse containing the result of the validation
AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) override;
private: // Functions
void stop_auth_cache_cleanup_thread();
// Functional Block C: Authorization
void handle_clear_cache_req(Call<ClearCacheRequest> call);
void cache_cleanup_handler();
// Functional Block D: Local authorization list management
void handle_send_local_authorization_list_req(Call<SendLocalListRequest> call);
void handle_get_local_authorization_list_version_req(Call<GetLocalListVersionRequest> call);
///\brief Apply a local list request to the database if allowed
///
///\param request The local list request to apply
///\retval Accepted if applied, otherwise will return either Failed or VersionMismatch
SendLocalListStatusEnum apply_local_authorization_list(const SendLocalListRequest& request);
};
} // namespace ocpp::v2

Some files were not shown because too many files have changed in this diff Show More