Skip to content

Commit 46af839

Browse files
committed
Squashing OCPP2.1 messages into a single commit:
OCPP2.1 message generation * Adds changes to code generator and jinja files in order to support OCPP2.1 messages * Adds OCPP2.1 messages into separate v21 directory Introduced SupportedOcppVersions variable * Added internal variable SupportedOcppVersions that allows to specify the supported protocol versions in order of preference * Added member variable ocpp_version to ChargePoint to indicate the selected version * ConnectivityManager now uses the configured value to set up the WebsocketConnectionOptions Refactored smart charging tests * seperated smart_charging_test_utils into hpp and cpp * moved redundant definitions of test cpp files into smart_charging_test_utils * implemented a couple operator== overloads for v21 types Support OCPP 2.1 variables * Extended RequiredComponentVariable with additional property to specify for which ocpp version a variable is required. This is the base to continue implementing a device model integrity check inside libocpps DeviceModel class * Aligned data ctrlr and sampled data ctrlr must always be available and the required variables are really always required. * Check for 'optional required' variables (only required when a component is available) and if they are not used while the whole ctrlr is not available. Adjustments as a result of the changed message types: * allowing more characters in CiStrings if required by OCPP2.1 types * ChargingSchedulePeriod limit property became optional and was required before. It's ensured to be always set so that existing did not have to change * Throwing ConversionsExceptions for enum values that have been added with OCPP2.1 messages but have no handling yet Misc: * Implemented code generator for EVerest yaml types from OCPP JSON Schemas Signed-off-by: Piet Gömpel <pietgoempel@gmail.com>
1 parent 055caef commit 46af839

File tree

271 files changed

+17384
-4154
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

271 files changed

+17384
-4154
lines changed

config/v2/component_config/custom/Connector_1_1.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
}
2020
],
2121
"description": "This variable reports current availability state for the Connector. Optional, because already reported in StatusNotification.",
22-
"type": "string"
22+
"type": "string",
23+
"default": ""
2324
},
2425
"ConnectorAvailable": {
2526
"variable_name": "Available",

config/v2/component_config/custom/Connector_2_1.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
}
2020
],
2121
"description": "This variable reports current availability state for the Connector. Optional, because already reported in StatusNotification.",
22-
"type": "string"
22+
"type": "string",
23+
"default": ""
2324
},
2425
"ConnectorAvailable": {
2526
"variable_name": "Available",

config/v2/component_config/standardized/InternalCtrlr.json

+20-1
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,24 @@
835835
"description": "If enabled we allow connections using security level 0. This does pose a security risk and is not allowed according to the OCPP spec",
836836
"default": false,
837837
"type": "boolean"
838+
},
839+
"SupportedOcppVersions": {
840+
"variable_name": "SupportedOcppVersions",
841+
"characteristics": {
842+
"supportsMonitoring": true,
843+
"dataType": "SequenceList",
844+
"valuesList": "ocpp2.0.1,ocpp2.1"
845+
},
846+
"attributes": [
847+
{
848+
"type": "Actual",
849+
"mutability": "ReadOnly",
850+
"value": "ocpp2.1,ocpp2.0.1"
851+
}
852+
],
853+
"description": "List of supported OCPP versions in order of preference",
854+
"default": "ocpp2.1,ocpp2.0.1",
855+
"type": "string"
838856
}
839857
},
840858
"required": [
@@ -847,6 +865,7 @@
847865
"NetworkConnectionProfiles",
848866
"NumberOfConnectors",
849867
"SupportedCiphers12",
850-
"SupportedCiphers13"
868+
"SupportedCiphers13",
869+
"SupportedOcppVersions"
851870
]
852871
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE VARIABLE
2+
ADD REQUIRED INTEGER DEFAULT FALSE;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE VARIABLE
2+
DROP COLUMN REQUIRED;

doc/v2/ocpp_201_device_model_initialization.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# OCPP 2.0.1: Device model initialization and inserting of config values
1+
# OCPP 2.0.1 and 2.1: Device model initialization and inserting of config values
22

33
If there is no custom database used for the device model, and 'initialize_device_model' is set to true in the
44
constructor of ChargePoint, the device model will be created or updated when ChargePoint is created. This document will
@@ -43,3 +43,15 @@ addition of a new one.
4343
Note: OCPP requires EVSE and Connector numbering starting from 1 counting upwards.
4444

4545
Note: There should be no duplicate components or variables in the component config files.
46+
47+
## Required variables
48+
49+
There are some required Variables, which can be found in the OCPP spec.
50+
Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.
51+
There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and
52+
`SampledDataCtrlr`.
53+
When libocpp is started and initialized, all required Variables will be checked and an DeviceModelError is thrown if
54+
one of the required Variables is not there.
55+
56+
This also implies, that if you write code that needs a required `Variable`, when trying to get that variable with
57+
`DeviceModel::get_value(...)`, you should first check if the Component that Variable belongs to is `Available`.

include/ocpp/common/types.hpp

+5-2
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,8 @@ enum class CaCertificateType {
442442
V2G,
443443
MO,
444444
CSMS,
445-
MF
445+
MF,
446+
OEM
446447
};
447448

448449
namespace conversions {
@@ -577,6 +578,7 @@ enum class CertificateType {
577578
CSMSRootCertificate,
578579
V2GCertificateChain,
579580
MFRootCertificate,
581+
OEMRootCertificate,
580582
};
581583

582584
namespace conversions {
@@ -633,7 +635,8 @@ std::ostream& operator<<(std::ostream& os, const OcppProtocolVersion& ocpp_proto
633635
enum class CertificateSigningUseEnum {
634636
ChargingStationCertificate,
635637
V2GCertificate,
636-
ManufacturerCertificate
638+
ManufacturerCertificate,
639+
V2G20Certificate
637640
};
638641

639642
namespace conversions {

include/ocpp/v2/charge_point.hpp

+6-3
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ class ChargePointInterface {
248248
/// \param certificate
249249
/// \param ocsp_request_data
250250
/// \return AuthorizeResponse containing the result of the validation
251-
virtual AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<5500>>& certificate,
251+
virtual AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
252252
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) = 0;
253253

254254
/// \brief Data transfer mechanism initiated by charger
@@ -363,6 +363,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa
363363

364364
// states
365365
std::atomic<RegistrationStatusEnum> registration_status;
366+
std::atomic<OcppProtocolVersion> ocpp_version =
367+
OcppProtocolVersion::Unknown; // version that is currently in use, selected by CSMS in websocket handshake
366368
std::atomic<UploadLogStatusEnum> upload_log_status;
367369
std::atomic<int32_t> upload_log_status_id;
368370
BootReasonEnum bootreason;
@@ -400,7 +402,8 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa
400402
// internal helper functions
401403
void initialize(const std::map<int32_t, int32_t>& evse_connector_structure, const std::string& message_log_path);
402404
void websocket_connected_callback(const int configuration_slot,
403-
const NetworkConnectionProfile& network_connection_profile);
405+
const NetworkConnectionProfile& network_connection_profile,
406+
const OcppProtocolVersion ocpp_version);
404407
void websocket_disconnected_callback(const int configuration_slot,
405408
const NetworkConnectionProfile& network_connection_profile);
406409
void websocket_connection_failed(ConnectionFailedReason reason);
@@ -562,7 +565,7 @@ class ChargePoint : public ChargePointInterface, private ocpp::ChargingStationBa
562565

563566
std::optional<std::string> get_evse_transaction_id(int32_t evse_id) override;
564567

565-
AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<5500>>& certificate,
568+
AuthorizeResponse validate_token(const IdToken id_token, const std::optional<CiString<10000>>& certificate,
566569
const std::optional<std::vector<OCSPRequestData>>& ocsp_request_data) override;
567570

568571
void on_event(const std::vector<EventData>& events) override;

include/ocpp/v2/charge_point_callbacks.hpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,8 @@ struct Callbacks {
8484
/// \brief Check if the current reservation for the given evse id is made for the id token / group id token.
8585
/// \return The reservation check status of this evse / id token.
8686
///
87-
std::function<ocpp::ReservationCheckStatus(const int32_t evse_id, const CiString<36> idToken,
88-
const std::optional<CiString<36>> groupIdToken)>
87+
std::function<ocpp::ReservationCheckStatus(const int32_t evse_id, const CiString<255> idToken,
88+
const std::optional<CiString<255>> groupIdToken)>
8989
is_reservation_for_token_callback;
9090
std::function<UpdateFirmwareResponse(const UpdateFirmwareRequest& request)> update_firmware_request_callback;
9191
// callback to be called when a variable has been changed by the CSMS
@@ -145,7 +145,8 @@ struct Callbacks {
145145

146146
/// \brief Callback function is called when the websocket connection status changes
147147
std::optional<std::function<void(const bool is_connected, const int configuration_slot,
148-
const NetworkConnectionProfile& network_connection_profile)>>
148+
const NetworkConnectionProfile& network_connection_profile,
149+
const OcppProtocolVersion ocpp_version)>>
149150
connection_state_changed_callback;
150151

151152
/// \brief Callback functions called for get / set / clear display messages

include/ocpp/v2/connectivity_manager.hpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@ namespace v2 {
1515

1616
class DeviceModel;
1717

18-
using WebsocketConnectionCallback = std::function<void(
19-
int configuration_slot, const NetworkConnectionProfile& network_connection_profile, OcppProtocolVersion version)>;
18+
/// \brief The result of a configuration of a network profile.
19+
struct ConfigNetworkResult {
20+
std::optional<std::string> interface_address; ///< ip address or interface string
21+
bool success; ///< true if the configuration was successful
22+
};
23+
24+
using WebsocketConnectionCallback =
25+
std::function<void(int configuration_slot, const NetworkConnectionProfile& network_connection_profile,
26+
const OcppProtocolVersion version)>;
2027
using WebsocketConnectionFailedCallback = std::function<void(ConnectionFailedReason reason)>;
2128
using ConfigureNetworkConnectionProfileCallback = std::function<std::future<ConfigNetworkResult>(
2229
const int32_t configuration_slot, const NetworkConnectionProfile& network_connection_profile)>;

include/ocpp/v2/constants.hpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ namespace v2 {
1010

1111
/// \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
1212
/// the device model, which we do as well
13-
constexpr std::size_t ISO15118_GET_EV_CERTIFICATE_EXI_RESPONSE_SIZE = 7500;
13+
/// 17000 is the vminimum alue from OCPP 2.1
14+
constexpr std::size_t ISO15118_GET_EV_CERTIFICATE_EXI_RESPONSE_SIZE = 17000;
1415

1516
} // namespace v2
1617
} // namespace ocpp

include/ocpp/v2/ctrlr_component_variables.hpp

+54
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,63 @@
44
#ifndef OCPP_V2_CTRLR_COMPONENT_VARIABLES
55
#define OCPP_V2_CTRLR_COMPONENT_VARIABLES
66

7+
#include <set>
8+
79
#include <ocpp/v2/ocpp_types.hpp>
810

911
namespace ocpp {
1012
namespace v2 {
13+
///
14+
/// \brief Required ComponentVariable.
15+
///
16+
struct RequiredComponentVariable : ComponentVariable {
17+
/// \brief Constructor
18+
RequiredComponentVariable() : required_for({OcppProtocolVersion::v201, OcppProtocolVersion::v21}){};
19+
20+
///
21+
/// \brief RequiredComponentVariable
22+
/// \param component Component
23+
/// \param variable Variable
24+
/// \param custom_data Custom data (default nullopt)
25+
/// \param required_for Required for which version. Multiple versions can be given.
26+
///
27+
RequiredComponentVariable(const Component component, const std::optional<Variable> variable,
28+
const std::optional<CustomData> custom_data = std::nullopt,
29+
const std::set<OcppProtocolVersion>& required_for = {OcppProtocolVersion::v201,
30+
OcppProtocolVersion::v21}) :
31+
ComponentVariable(), required_for(required_for) {
32+
this->component = component;
33+
this->variable = variable;
34+
this->customData = custom_data;
35+
};
36+
37+
/// \brief For which ocpp protocol version(s) this component variable is required.
38+
std::set<OcppProtocolVersion> required_for;
39+
};
40+
41+
///
42+
/// \brief Required variables per component.
43+
///
44+
/// First value is the 'available' variable from the specific component. Second value is a set of required variables.
45+
/// This makes it possible to check only for the required variables if a component is available.
46+
///
47+
extern const std::vector<std::pair<ComponentVariable, std::vector<RequiredComponentVariable>>>
48+
required_component_available_variables;
49+
50+
///
51+
/// \brief Required variables that should always exist, regardless of any available or not available controller.
52+
///
53+
extern const std::vector<RequiredComponentVariable> required_variables;
54+
55+
///
56+
/// \brief Required variables of an EVSE.
57+
///
58+
extern const std::vector<Variable> required_evse_variables;
59+
60+
///
61+
/// \brief Required variables of a connector.
62+
///
63+
extern const std::vector<Variable> required_connector_variables;
1164

1265
namespace ControllerComponents {
1366
extern const Component InternalCtrlr;
@@ -88,6 +141,7 @@ extern const ComponentVariable MessageQueueSizeThreshold;
88141
extern const ComponentVariable MaxMessageSize;
89142
extern const ComponentVariable ResumeTransactionsOnBoot;
90143
extern const ComponentVariable AllowSecurityLevelZeroConnections;
144+
extern const RequiredComponentVariable SupportedOcppVersions;
91145
extern const ComponentVariable AlignedDataCtrlrEnabled;
92146
extern const ComponentVariable AlignedDataCtrlrAvailable;
93147
extern const RequiredComponentVariable AlignedDataInterval;

include/ocpp/v2/database_handler.hpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ class DatabaseHandlerInterface {
167167
/// \brief Inserts or updates the given \p profile to CHARGING_PROFILES table
168168
virtual void insert_or_update_charging_profile(
169169
const int evse_id, const v2::ChargingProfile& profile,
170-
const ChargingLimitSourceEnum charging_limit_source = ChargingLimitSourceEnum::CSO) = 0;
170+
const CiString<20> charging_limit_source = ChargingLimitSourceEnumStringType::CSO) = 0;
171171

172172
/// \brief Deletes the profile with the given \p profile_id
173173
virtual bool delete_charging_profile(const int profile_id) = 0;
@@ -196,7 +196,7 @@ class DatabaseHandlerInterface {
196196
/// \brief Retrieves all ChargingProfiles grouped by EVSE ID
197197
virtual std::map<int32_t, std::vector<v2::ChargingProfile>> get_all_charging_profiles_group_by_evse() = 0;
198198

199-
virtual ChargingLimitSourceEnum get_charging_limit_source_for_profile(const int profile_id) = 0;
199+
virtual CiString<20> get_charging_limit_source_for_profile(const int profile_id) = 0;
200200

201201
virtual std::unique_ptr<common::SQLiteStatementInterface> new_statement(const std::string& sql) = 0;
202202
};
@@ -270,7 +270,7 @@ class DatabaseHandler : public DatabaseHandlerInterface, public common::Database
270270
/// charging profiles
271271
void insert_or_update_charging_profile(
272272
const int evse_id, const v2::ChargingProfile& profile,
273-
const ChargingLimitSourceEnum charging_limit_source = ChargingLimitSourceEnum::CSO) override;
273+
const CiString<20> charging_limit_source = ChargingLimitSourceEnumStringType::CSO) override;
274274
bool delete_charging_profile(const int profile_id) override;
275275
void delete_charging_profile_by_transaction_id(const std::string& transaction_id) override;
276276
bool clear_charging_profiles() override;
@@ -282,7 +282,7 @@ class DatabaseHandler : public DatabaseHandlerInterface, public common::Database
282282
std::vector<v2::ChargingProfile> get_charging_profiles_for_evse(const int evse_id) override;
283283
std::vector<v2::ChargingProfile> get_all_charging_profiles() override;
284284
virtual std::map<int32_t, std::vector<v2::ChargingProfile>> get_all_charging_profiles_group_by_evse() override;
285-
ChargingLimitSourceEnum get_charging_limit_source_for_profile(const int profile_id) override;
285+
CiString<20> get_charging_limit_source_for_profile(const int profile_id) override;
286286

287287
std::unique_ptr<common::SQLiteStatementInterface> new_statement(const std::string& sql) override;
288288
};

include/ocpp/v2/device_model.hpp

+31
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <everest/logging.hpp>
1010

11+
#include <ocpp/v2/ctrlr_component_variables.hpp>
1112
#include <ocpp/v2/device_model_storage_interface.hpp>
1213

1314
namespace ocpp {
@@ -135,6 +136,36 @@ class DeviceModel {
135136
bool component_variables_match(const std::vector<ComponentVariable>& component_variables,
136137
const ocpp::v2::Component& component_, const struct ocpp::v2::Variable& variable_);
137138

139+
///
140+
/// \brief Helper function to check if a variable has a value.
141+
/// \param component_variable Component variable to check.
142+
/// \param attribute Attribute to check.
143+
///
144+
/// \throws DeviceModelError if variable has no value or value is an empty string.
145+
///
146+
void check_variable_has_value(const ComponentVariable& component_variable,
147+
const AttributeEnum attribute = AttributeEnum::Actual);
148+
149+
///
150+
/// \brief Helper function to check if a required variable has a value.
151+
/// \param required_variable Required component variable to check.
152+
/// \param supported_versions The current supported ocpp versions.
153+
/// \throws DeviceModelError if variable has no value or value is an empty string.
154+
///
155+
void check_required_variable(const RequiredComponentVariable& required_variable,
156+
const std::vector<OcppProtocolVersion>& supported_versions);
157+
158+
///
159+
/// \brief Loop over all required variables to check if they have a value.
160+
///
161+
/// This will check for all required variables from `ctrlr_component_variables.cpp` `required_variables`.
162+
/// It will also check for specific required variables that belong to a specific controller. If a controller is not
163+
/// available, the 'required' variables of that component are not required at this point.
164+
///
165+
/// \throws DeviceModelError if one of the variables does not have a value or value is an empty string.
166+
///
167+
void check_required_variables();
168+
138169
public:
139170
/// \brief Constructor for the device model
140171
/// \param device_model_storage_interface pointer to a device model interface class

include/ocpp/v2/evse.hpp

+5-5
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ class EvseInterface {
4141
/// \param connector_type The connector type to check.
4242
/// \return True if connector type is unknown or this evse has the given connector type.
4343
///
44-
virtual bool does_connector_exist(ConnectorEnum connector_type) const = 0;
44+
virtual bool does_connector_exist(CiString<20> connector_type) const = 0;
4545

4646
///
4747
/// \brief Get connector status.
@@ -54,7 +54,7 @@ class EvseInterface {
5454
/// \param connector_type The connector type to filter on (optional).
5555
/// \return Connector status. If connector type is given and does not exist, std::nullopt.
5656
///
57-
virtual std::optional<ConnectorStatusEnum> get_connector_status(std::optional<ConnectorEnum> connector_type) = 0;
57+
virtual std::optional<ConnectorStatusEnum> get_connector_status(std::optional<CiString<20>> connector_type) = 0;
5858

5959
/// \brief Opens a new transaction
6060
/// \param transaction_id id of the transaction
@@ -228,7 +228,7 @@ class Evse : public EvseInterface {
228228
/// \param connector_id Connector id
229229
/// \return The connector type. If evse or connector id is not correct: std::nullopt.
230230
///
231-
std::optional<ConnectorEnum> get_evse_connector_type(const uint32_t connector_id) const;
231+
std::optional<CiString<20>> get_evse_connector_type(const uint32_t connector_id) const;
232232

233233
public:
234234
/// \brief Construct a new Evse object
@@ -252,8 +252,8 @@ class Evse : public EvseInterface {
252252
int32_t get_id() const;
253253

254254
uint32_t get_number_of_connectors() const;
255-
bool does_connector_exist(const ConnectorEnum connector_type) const override;
256-
std::optional<ConnectorStatusEnum> get_connector_status(std::optional<ConnectorEnum> connector_type) override;
255+
bool does_connector_exist(const CiString<20> connector_type) const override;
256+
std::optional<ConnectorStatusEnum> get_connector_status(std::optional<CiString<20>> connector_type) override;
257257

258258
void open_transaction(const std::string& transaction_id, const int32_t connector_id, const DateTime& timestamp,
259259
const MeterValue& meter_start, const std::optional<IdToken>& id_token,

0 commit comments

Comments
 (0)