Skip to content

Commit 9c9c481

Browse files
maaikezPietfried
andauthored
Support OCPP 2.1 variables (#988)
* 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. --------- Signed-off-by: Piet Gömpel <pietgoempel@gmail.com> Signed-off-by: Maaike Zijderveld, iolar <git.mail@iolar.nl> Co-authored-by: Piet Gömpel <pietgoempel@gmail.com>
1 parent 9917745 commit 9c9c481

29 files changed

+679
-267
lines changed

config/v201/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/v201/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",
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/v201/ocpp_201_device_model_initialization.md

+14-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,16 @@ 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+
48+
## Required variables
49+
50+
There are some required Variables, which can be found in the OCPP spec.
51+
Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.
52+
There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and
53+
`SampledDataCtrlr`.
54+
When libocpp is started and initialized, all required Variables will be checked and an DeviceModelError is thrown if
55+
one of the required Variables is not there.
56+
57+
This also implies, that if you write code that needs a required `Variable`, when trying to get that variable with
58+
`DeviceModel::get_value(...)`, you should first check if the Component that Variable belongs to is `Available`.

include/ocpp/v201/ctrlr_component_variables.hpp

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

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

911
namespace ocpp {
1012
namespace v201 {
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;

include/ocpp/v201/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/v201/ctrlr_component_variables.hpp>
1112
#include <ocpp/v201/device_model_storage_interface.hpp>
1213

1314
namespace ocpp {
@@ -136,6 +137,36 @@ class DeviceModel {
136137
const ocpp::v201::Component& component_,
137138
const struct ocpp::v201::Variable& variable_);
138139

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

include/ocpp/v201/functional_blocks/diagnostics.hpp

+5
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Diagnostics : public DiagnosticsInterface {
7171

7272
/// \brief Callback function that can be called to clear customer information based on the given arguments
7373
std::optional<ClearCustomerInformationCallback> clear_customer_information_callback;
74+
const bool is_monitoring_available;
7475

7576
private: // Functions
7677
/* OCPP message requests */
@@ -109,5 +110,9 @@ class Diagnostics : public DiagnosticsInterface {
109110
void clear_customer_information(const std::optional<CertificateHashDataType> customer_certificate,
110111
const std::optional<IdToken> id_token,
111112
const std::optional<CiString<64>> customer_identifier);
113+
114+
/// \brief Check if monitoring is available and if not, throw.
115+
/// \param type Message type to include in MessageTypeNotImplementedException when thrown.
116+
void throw_when_monitoring_not_available(const MessageType type);
112117
};
113118
} // namespace ocpp::v201

include/ocpp/v201/functional_blocks/remote_transaction_control.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class RemoteTransactionControl : public RemoteTransactionControlInterface {
4747
RemoteTransactionControl(MessageDispatcherInterface<MessageType>& message_dispatcher, DeviceModel& device_model,
4848
ConnectivityManagerInterface& connectivity_manager, EvseManagerInterface& evse_manager,
4949
ComponentStateManagerInterface& component_state_manager, TransactionInterface& transaction,
50-
SmartChargingInterface& smart_charging, MeterValuesInterface& meter_values,
50+
SmartChargingInterface* smart_charging, MeterValuesInterface& meter_values,
5151
AvailabilityInterface& availability, FirmwareUpdateInterface& firmware_update,
5252
SecurityInterface& security, ReservationInterface* reservation,
5353
ProvisioningInterface& provisioning, UnlockConnectorCallback unlock_connector_callback,
@@ -66,7 +66,7 @@ class RemoteTransactionControl : public RemoteTransactionControlInterface {
6666
ComponentStateManagerInterface& component_state_manager;
6767

6868
TransactionInterface& transaction;
69-
SmartChargingInterface& smart_charging;
69+
SmartChargingInterface* smart_charging;
7070
MeterValuesInterface& meter_values;
7171
AvailabilityInterface& availability;
7272
FirmwareUpdateInterface& firmware_update;

include/ocpp/v201/functional_blocks/transaction.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class TransactionBlock : public TransactionInterface {
9090
ConnectivityManagerInterface& connectivity_manager, EvseManagerInterface& evse_manager,
9191
MessageQueue<v201::MessageType>& message_queue, DatabaseHandlerInterface& database_handler,
9292
AuthorizationInterface& authorization, AvailabilityInterface& availability,
93-
SmartChargingInterface& smart_charging, TariffAndCostInterface& tariff_and_cost,
93+
SmartChargingInterface* smart_charging, TariffAndCostInterface* tariff_and_cost,
9494
StopTransactionCallback stop_transaction_callback, PauseChargingCallback pause_charging_callback,
9595
std::optional<TransactionEventCallback> transaction_event_callback,
9696
std::optional<TransactionEventResponseCallback> transaction_event_response_callback,
@@ -129,8 +129,8 @@ class TransactionBlock : public TransactionInterface {
129129
DatabaseHandlerInterface& database_handler;
130130
AuthorizationInterface& authorization;
131131
AvailabilityInterface& availability;
132-
SmartChargingInterface& smart_charging;
133-
TariffAndCostInterface& tariff_and_cost;
132+
SmartChargingInterface* smart_charging;
133+
TariffAndCostInterface* tariff_and_cost;
134134
StopTransactionCallback stop_transaction_callback;
135135
PauseChargingCallback pause_charging_callback;
136136
std::optional<TransactionEventCallback> transaction_event_callback;

include/ocpp/v201/init_device_model_db.hpp

+1-7
Original file line numberDiff line numberDiff line change
@@ -43,15 +43,13 @@ namespace ocpp::v201 {
4343
/// \brief Class that holds a component.
4444
///
4545
/// When the component is read from the database, the component id will be set.
46-
/// When the component is read from the component config file, the 'required' vector will be filled.
4746
///
4847
struct ComponentKey {
4948
std::optional<uint64_t> db_id; ///< \brief Component id in the database.
5049
std::string name; ///< \brief Component name.
5150
std::optional<std::string> instance; ///< \brief Component instance.
5251
std::optional<int32_t> evse_id; ///< \brief Component evse id.
5352
std::optional<int32_t> connector_id; ///< \brief Component connector id.
54-
std::vector<std::string> required; ///< \brief List of required variables.
5553

5654
///
5755
/// \brief operator <, needed to add this class as key in a map.
@@ -85,8 +83,6 @@ struct DeviceModelVariable {
8583
VariableCharacteristics characteristics;
8684
/// \brief Variable attributes
8785
std::vector<DbVariableAttribute> attributes;
88-
/// \brief True if variable is required
89-
bool required;
9086
/// \brief Variable instance
9187
std::optional<std::string> instance;
9288
/// \brief Default value, if this is set in the component config json
@@ -221,11 +217,9 @@ class InitDeviceModelDb : public common::DatabaseHandlerCommon {
221217
///
222218
/// \brief Get all component properties (variables) from the given (component) json.
223219
/// \param component_properties The json component properties
224-
/// \param required_properties The vector of required properties of this component.
225220
/// \return A vector with all Variables belonging to this component.
226221
///
227-
std::vector<DeviceModelVariable> get_all_component_properties(const json& component_properties,
228-
std::vector<std::string> required_properties);
222+
std::vector<DeviceModelVariable> get_all_component_properties(const json& component_properties);
229223

230224
///
231225
/// \brief Insert variable characteristics

include/ocpp/v201/ocpp_types.hpp

+1-3
Original file line numberDiff line numberDiff line change
@@ -2235,11 +2235,9 @@ void to_json(json& j, const Firmware& k);
22352235
/// \brief Conversion from a given json object \p j to a given Firmware \p k
22362236
void from_json(const json& j, Firmware& k);
22372237

2238-
// \brief Writes the string representation of the given Firmware \p k to the given output stream \p os
2238+
/// \brief Writes the string representation of the given Firmware \p k to the given output stream \p os
22392239
/// \returns an output stream with the Firmware written to
22402240
std::ostream& operator<<(std::ostream& os, const Firmware& k);
2241-
2242-
struct RequiredComponentVariable : ComponentVariable {};
22432241
} // namespace v201
22442242
} // namespace ocpp
22452243

0 commit comments

Comments
 (0)