Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support OCPP 2.1 variables #988

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion config/v201/component_config/custom/Connector_1_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
}
],
"description": "This variable reports current availability state for the Connector. Optional, because already reported in StatusNotification.",
"type": "string"
"type": "string",
"default": ""
},
"ConnectorAvailable": {
"variable_name": "Available",
Expand Down
3 changes: 2 additions & 1 deletion config/v201/component_config/custom/Connector_2_1.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
}
],
"description": "This variable reports current availability state for the Connector. Optional, because already reported in StatusNotification.",
"type": "string"
"type": "string",
"default": ""
},
"ConnectorAvailable": {
"variable_name": "Available",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE VARIABLE

Check failure on line 1 in config/v201/device_model_migrations/3_down-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_down-variable_required.sql#L1

Expected SET ANSI_NULLS ON near top of file

Check failure on line 1 in config/v201/device_model_migrations/3_down-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_down-variable_required.sql#L1

Expected SET QUOTED_IDENTIFIER ON near top of file

Check failure on line 1 in config/v201/device_model_migrations/3_down-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_down-variable_required.sql#L1

Expected SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED near top of file

Check failure on line 1 in config/v201/device_model_migrations/3_down-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_down-variable_required.sql#L1

Object name not schema qualified
ADD REQUIRED INTEGER DEFAULT FALSE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ALTER TABLE VARIABLE

Check failure on line 1 in config/v201/device_model_migrations/3_up-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_up-variable_required.sql#L1

Expected SET ANSI_NULLS ON near top of file

Check failure on line 1 in config/v201/device_model_migrations/3_up-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_up-variable_required.sql#L1

Expected SET QUOTED_IDENTIFIER ON near top of file

Check failure on line 1 in config/v201/device_model_migrations/3_up-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_up-variable_required.sql#L1

Expected SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED near top of file

Check failure on line 1 in config/v201/device_model_migrations/3_up-variable_required.sql

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

config/v201/device_model_migrations/3_up-variable_required.sql#L1

Object name not schema qualified
DROP COLUMN REQUIRED;
15 changes: 14 additions & 1 deletion doc/v201/ocpp_201_device_model_initialization.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OCPP 2.0.1: Device model initialization and inserting of config values
# OCPP 2.0.1 and 2.1: Device model initialization and inserting of config values

If there is no custom database used for the device model, and 'initialize_device_model' is set to true in the
constructor of ChargePoint, the device model will be created or updated when ChargePoint is created. This document will
Expand Down Expand Up @@ -43,3 +43,16 @@
Note: OCPP requires EVSE and Connector numbering starting from 1 counting upwards.

Note: There should be no duplicate components or variables in the component config files.


## Required variables

There are some required Variables, which can be found in the OCPP spec.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There are some required Variables, which can be found in the OCPP spec.
There are Variables that are defined as **required** in the OCPP specification.

Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.

Check notice on line 51 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L51

Expected: 0 or 2; Actual: 1

Check notice on line 51 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L51

Expected: 80; Actual: 118
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Some `Variables` are only required if the `Component` is `Available`, for example `Reservation` and `Smart Charging`.
Some `Variables` are only required if the `Available` variable of the respective `Component` is present and configured to true. Examples for this are the `ReservationCtrlr` and the `SmartChargingCtrlr`.

There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and

Check notice on line 52 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L52

Expected: 0 or 2; Actual: 1

Check notice on line 52 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L52

Expected: 80; Actual: 110
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
There are some Components that are always required because that is how libocpp works: `AlignedDataCtrlr` and
There are some Components that are always required because they are required by libocpp: `AlignedDataCtrlr` and

`SampledDataCtrlr`.
When libocpp is started and initialized, all required Variables will be checked and an DeviceModelError is thrown if

Check notice on line 54 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L54

Expected: 0 or 2; Actual: 1

Check notice on line 54 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L54

Expected: 80; Actual: 117
one of the required Variables is not there.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
one of the required Variables is not there.
one of the required Variables is not present.


This also implies, that if you write code that needs a required `Variable`, when trying to get that variable with

Check notice on line 57 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L57

Expected: 0 or 2; Actual: 1

Check notice on line 57 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L57

Expected: 80; Actual: 114
`DeviceModel::get_value(...)`, you should first check if the Component that Variable belongs to is `Available`.

Check notice on line 58 in doc/v201/ocpp_201_device_model_initialization.md

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

doc/v201/ocpp_201_device_model_initialization.md#L58

Expected: 80; Actual: 111
53 changes: 53 additions & 0 deletions include/ocpp/v201/ctrlr_component_variables.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,63 @@
#ifndef OCPP_V201_CTRLR_COMPONENT_VARIABLES
#define OCPP_V201_CTRLR_COMPONENT_VARIABLES

#include <set>

#include <ocpp/v201/ocpp_types.hpp>

namespace ocpp {
namespace v201 {
///
/// \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;

namespace ControllerComponents {
extern const Component InternalCtrlr;
Expand Down
31 changes: 31 additions & 0 deletions include/ocpp/v201/device_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <everest/logging.hpp>

#include <ocpp/v201/ctrlr_component_variables.hpp>
#include <ocpp/v201/device_model_storage_interface.hpp>

namespace ocpp {
Expand Down Expand Up @@ -136,6 +137,36 @@ class DeviceModel {
const ocpp::v201::Component& component_,
const struct ocpp::v201::Variable& variable_);

///
/// \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
Expand Down
5 changes: 5 additions & 0 deletions include/ocpp/v201/functional_blocks/diagnostics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@

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

Check notice on line 74 in include/ocpp/v201/functional_blocks/diagnostics.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/functional_blocks/diagnostics.hpp#L74

class member 'Diagnostics::is_monitoring_available' is never used.

private: // Functions
/* OCPP message requests */
Expand Down Expand Up @@ -109,5 +110,9 @@
void clear_customer_information(const std::optional<CertificateHashDataType> customer_certificate,
const std::optional<IdToken> id_token,
const std::optional<CiString<64>> customer_identifier);

/// \brief Check if monitoring is available and if not, throw.
/// \param type Message type to include in MessageTypeNotImplementedException when thrown.
void throw_when_monitoring_not_available(const MessageType type);
};
} // namespace ocpp::v201
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
RemoteTransactionControl(MessageDispatcherInterface<MessageType>& message_dispatcher, DeviceModel& device_model,
ConnectivityManagerInterface& connectivity_manager, EvseManagerInterface& evse_manager,
ComponentStateManagerInterface& component_state_manager, TransactionInterface& transaction,
SmartChargingInterface& smart_charging, MeterValuesInterface& meter_values,
SmartChargingInterface* smart_charging, MeterValuesInterface& meter_values,
AvailabilityInterface& availability, FirmwareUpdateInterface& firmware_update,
SecurityInterface& security, ReservationInterface* reservation,
ProvisioningInterface& provisioning, UnlockConnectorCallback unlock_connector_callback,
Expand All @@ -66,7 +66,7 @@
ComponentStateManagerInterface& component_state_manager;

TransactionInterface& transaction;
SmartChargingInterface& smart_charging;
SmartChargingInterface* smart_charging;

Check notice on line 69 in include/ocpp/v201/functional_blocks/remote_transaction_control.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/functional_blocks/remote_transaction_control.hpp#L69

class member 'RemoteTransactionControl::smart_charging' is never used.
MeterValuesInterface& meter_values;
AvailabilityInterface& availability;
FirmwareUpdateInterface& firmware_update;
Expand Down
6 changes: 3 additions & 3 deletions include/ocpp/v201/functional_blocks/transaction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@
ConnectivityManagerInterface& connectivity_manager, EvseManagerInterface& evse_manager,
MessageQueue<v201::MessageType>& message_queue, DatabaseHandlerInterface& database_handler,
AuthorizationInterface& authorization, AvailabilityInterface& availability,
SmartChargingInterface& smart_charging, TariffAndCostInterface& tariff_and_cost,
SmartChargingInterface* smart_charging, TariffAndCostInterface* tariff_and_cost,
StopTransactionCallback stop_transaction_callback, PauseChargingCallback pause_charging_callback,
std::optional<TransactionEventCallback> transaction_event_callback,
std::optional<TransactionEventResponseCallback> transaction_event_response_callback,
Expand Down Expand Up @@ -129,8 +129,8 @@
DatabaseHandlerInterface& database_handler;
AuthorizationInterface& authorization;
AvailabilityInterface& availability;
SmartChargingInterface& smart_charging;
TariffAndCostInterface& tariff_and_cost;
SmartChargingInterface* smart_charging;

Check notice on line 132 in include/ocpp/v201/functional_blocks/transaction.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/functional_blocks/transaction.hpp#L132

class member 'TransactionBlock::smart_charging' is never used.
TariffAndCostInterface* tariff_and_cost;

Check notice on line 133 in include/ocpp/v201/functional_blocks/transaction.hpp

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

include/ocpp/v201/functional_blocks/transaction.hpp#L133

class member 'TransactionBlock::tariff_and_cost' is never used.
StopTransactionCallback stop_transaction_callback;
PauseChargingCallback pause_charging_callback;
std::optional<TransactionEventCallback> transaction_event_callback;
Expand Down
8 changes: 1 addition & 7 deletions include/ocpp/v201/init_device_model_db.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,13 @@ namespace ocpp::v201 {
/// \brief Class that holds a component.
///
/// When the component is read from the database, the component id will be set.
/// When the component is read from the component config file, the 'required' vector will be filled.
///
struct ComponentKey {
std::optional<uint64_t> db_id; ///< \brief Component id in the database.
std::string name; ///< \brief Component name.
std::optional<std::string> instance; ///< \brief Component instance.
std::optional<int32_t> evse_id; ///< \brief Component evse id.
std::optional<int32_t> connector_id; ///< \brief Component connector id.
std::vector<std::string> required; ///< \brief List of required variables.

///
/// \brief operator <, needed to add this class as key in a map.
Expand Down Expand Up @@ -85,8 +83,6 @@ struct DeviceModelVariable {
VariableCharacteristics characteristics;
/// \brief Variable attributes
std::vector<DbVariableAttribute> attributes;
/// \brief True if variable is required
bool required;
/// \brief Variable instance
std::optional<std::string> instance;
/// \brief Default value, if this is set in the component config json
Expand Down Expand Up @@ -221,11 +217,9 @@ class InitDeviceModelDb : public common::DatabaseHandlerCommon {
///
/// \brief Get all component properties (variables) from the given (component) json.
/// \param component_properties The json component properties
/// \param required_properties The vector of required properties of this component.
/// \return A vector with all Variables belonging to this component.
///
std::vector<DeviceModelVariable> get_all_component_properties(const json& component_properties,
std::vector<std::string> required_properties);
std::vector<DeviceModelVariable> get_all_component_properties(const json& component_properties);

///
/// \brief Insert variable characteristics
Expand Down
4 changes: 1 addition & 3 deletions include/ocpp/v201/ocpp_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2235,11 +2235,9 @@ void to_json(json& j, const Firmware& k);
/// \brief Conversion from a given json object \p j to a given Firmware \p k
void from_json(const json& j, Firmware& k);

// \brief Writes the string representation of the given Firmware \p k to the given output stream \p os
/// \brief Writes the string representation of the given Firmware \p k to the given output stream \p os
/// \returns an output stream with the Firmware written to
std::ostream& operator<<(std::ostream& os, const Firmware& k);

struct RequiredComponentVariable : ComponentVariable {};
} // namespace v201
} // namespace ocpp

Expand Down
Loading