From a1339411cf640152134f03f4f1ccb54c00f5447b Mon Sep 17 00:00:00 2001 From: SNSubramanya <139965468+SNSubramanya@users.noreply.github.com> Date: Thu, 26 Oct 2023 07:26:11 +0200 Subject: [PATCH] B06:- Get variables requests (#218) B06.FR.09 B06.FR.16 B06.FR.17 --- config/v201/config.json | 4 ++-- include/ocpp/common/message_queue.hpp | 1 + include/ocpp/v201/charge_point.hpp | 2 +- include/ocpp/v201/device_model.hpp | 26 ++++++++++++++---------- lib/ocpp/v201/charge_point.cpp | 29 ++++++++++++++++++++++----- lib/ocpp/v201/device_model.cpp | 11 ++++++++-- 6 files changed, 52 insertions(+), 21 deletions(-) diff --git a/config/v201/config.json b/config/v201/config.json index 134d4a0e8..db2529aae 100644 --- a/config/v201/config.json +++ b/config/v201/config.json @@ -529,7 +529,7 @@ "BytesPerMessageGetVariables": { "variable_name": "BytesPerMessage", "attributes": { - "Actual": 42 + "Actual": 250 }, "instance": "GetVariables" }, @@ -550,7 +550,7 @@ "ItemsPerMessageGetVariables": { "variable_name": "ItemsPerMessage", "attributes": { - "Actual": 42 + "Actual": 2 }, "instance": "GetVariables" }, diff --git a/include/ocpp/common/message_queue.hpp b/include/ocpp/common/message_queue.hpp index 0353025cc..dd53d1024 100644 --- a/include/ocpp/common/message_queue.hpp +++ b/include/ocpp/common/message_queue.hpp @@ -30,6 +30,7 @@ const auto STANDARD_MESSAGE_TIMEOUT = std::chrono::seconds(30); /// \brief Contains a OCPP message in json form with additional information template struct EnhancedMessage { json message; ///< The OCPP message as json + size_t message_size; ///< size of the json message in bytes MessageId uniqueId; ///< The unique ID of the json message M messageType = M::InternalError; ///< The OCPP message type MessageTypeId messageTypeId; ///< The OCPP message type ID (CALL/CALLRESULT/CALLERROR) diff --git a/include/ocpp/v201/charge_point.hpp b/include/ocpp/v201/charge_point.hpp index 1e8755fda..6951dcfb2 100644 --- a/include/ocpp/v201/charge_point.hpp +++ b/include/ocpp/v201/charge_point.hpp @@ -311,7 +311,7 @@ class ChargePoint : ocpp::ChargingStationBase { // Functional Block B: Provisioning void handle_boot_notification_response(CallResult call_result); void handle_set_variables_req(Call call); - void handle_get_variables_req(Call call); + void handle_get_variables_req(const EnhancedMessage& message); void handle_get_base_report_req(Call call); void handle_get_report_req(Call call); void handle_set_network_profile_req(Call call); diff --git a/include/ocpp/v201/device_model.hpp b/include/ocpp/v201/device_model.hpp index 59e3d222d..9e4f65fb5 100644 --- a/include/ocpp/v201/device_model.hpp +++ b/include/ocpp/v201/device_model.hpp @@ -55,9 +55,11 @@ class DeviceModel { /// \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(const Component& component_id, const Variable& variable_id, - const AttributeEnum& attribute_enum, std::string& value); + GetVariableStatusEnum request_value_internal(const Component& component_id, const Variable& variable_id, + const AttributeEnum& attribute_enum, std::string& value, + bool allow_write_only); /// \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 find as part of a component this function @@ -92,10 +94,11 @@ class DeviceModel { template T get_value(const ComponentVariable& component_variable, const AttributeEnum& attribute_enum = AttributeEnum::Actual) { - const auto response = - this->request_value(component_variable.component, component_variable.variable.value(), attribute_enum); - if (response.value.has_value()) { - return response.value.value(); + std::string value; + const auto response = this->request_value_internal( + component_variable.component, component_variable.variable.value(), attribute_enum, value, true); + if (response == GetVariableStatusEnum::Accepted) { + return to_specific_type(value); } else { EVLOG_critical << "Directly requested value for ComponentVariable that doesn't exist in the device model storage: " @@ -114,10 +117,11 @@ class DeviceModel { template std::optional get_optional_value(const ComponentVariable& component_variable, const AttributeEnum& attribute_enum = AttributeEnum::Actual) { - const auto response = - this->request_value(component_variable.component, component_variable.variable.value(), attribute_enum); - if (response.status == GetVariableStatusEnum::Accepted) { - return response.value.value(); + std::string value; + const auto response = this->request_value_internal( + component_variable.component, component_variable.variable.value(), attribute_enum, value, true); + if (response == GetVariableStatusEnum::Accepted) { + return to_specific_type(value); } else { return std::nullopt; } @@ -135,7 +139,7 @@ class DeviceModel { RequestDeviceModelResponse request_value(const Component& component_id, const Variable& variable_id, const AttributeEnum& attribute_enum) { std::string value; - const auto req_status = this->request_value(component_id, variable_id, attribute_enum, value); + const auto req_status = this->request_value_internal(component_id, variable_id, attribute_enum, value, false); if (req_status == GetVariableStatusEnum::Accepted) { return {GetVariableStatusEnum::Accepted, to_specific_type(value)}; diff --git a/lib/ocpp/v201/charge_point.cpp b/lib/ocpp/v201/charge_point.cpp index 28f4ae4f3..0d7800f7c 100644 --- a/lib/ocpp/v201/charge_point.cpp +++ b/lib/ocpp/v201/charge_point.cpp @@ -691,7 +691,7 @@ void ChargePoint::handle_message(const EnhancedMessage& messa this->handle_set_variables_req(json_message); break; case MessageType::GetVariables: - this->handle_get_variables_req(json_message); + this->handle_get_variables_req(message); break; case MessageType::GetBaseReport: this->handle_get_base_report_req(json_message); @@ -754,9 +754,9 @@ void ChargePoint::handle_message(const EnhancedMessage& messa void ChargePoint::message_callback(const std::string& message) { auto enhanced_message = this->message_queue->receive(message); + enhanced_message.message_size = message.size(); auto json_message = enhanced_message.message; this->logging->central_system(conversions::messagetype_to_string(enhanced_message.messageType), message); - try { if (this->registration_status == RegistrationStatusEnum::Accepted) { this->handle_message(enhanced_message); @@ -1493,11 +1493,30 @@ void ChargePoint::handle_set_variables_req(Call call) { } } -void ChargePoint::handle_get_variables_req(Call call) { +void ChargePoint::handle_get_variables_req(const EnhancedMessage& message) { + Call call = message.call_message; const auto msg = call.msg; - // FIXME(piet): add handling for B06.FR.16 - // FIXME(piet): add handling for B06.FR.17 + const auto max_variables_per_message = + this->device_model->get_value(ControllerComponentVariables::ItemsPerMessageGetVariables); + const auto max_bytes_per_message = + this->device_model->get_value(ControllerComponentVariables::BytesPerMessageGetVariables); + + // B06.FR.16 + if (msg.getVariableData.size() > max_variables_per_message) { + // send a CALLERROR + const auto call_error = CallError(call.uniqueId, "OccurenceConstraintViolation", "", json({})); + this->send(call_error); + return; + } + + // B06.FR.17 + if (message.message_size > max_bytes_per_message) { + // send a CALLERROR + const auto call_error = CallError(call.uniqueId, "FormatViolation", "", json({})); + this->send(call_error); + return; + } GetVariablesResponse response; diff --git a/lib/ocpp/v201/device_model.cpp b/lib/ocpp/v201/device_model.cpp index 9e91ee3e0..ccc2b6982 100644 --- a/lib/ocpp/v201/device_model.cpp +++ b/lib/ocpp/v201/device_model.cpp @@ -92,8 +92,9 @@ bool validate_value(const VariableCharacteristics& characteristics, const std::s } } -GetVariableStatusEnum DeviceModel::request_value(const Component& component_id, const Variable& variable_id, - const AttributeEnum& attribute_enum, std::string& value) { +GetVariableStatusEnum DeviceModel::request_value_internal(const Component& component_id, const Variable& variable_id, + const AttributeEnum& attribute_enum, std::string& value, + bool allow_write_only) { const auto component_it = this->device_model.find(component_id); if (component_it == this->device_model.end()) { return GetVariableStatusEnum::UnknownComponent; @@ -112,6 +113,12 @@ GetVariableStatusEnum DeviceModel::request_value(const Component& component_id, return GetVariableStatusEnum::NotSupportedAttributeType; } + // only internal functions can access WriteOnly variables + if (!allow_write_only and attribute_opt.value().mutability.has_value() and + attribute_opt.value().mutability.value() == MutabilityEnum::WriteOnly) { + return GetVariableStatusEnum::Rejected; + } + value = attribute_opt->value->get(); return GetVariableStatusEnum::Accepted; }