mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 19:13:13 +00:00
client: Use EncodableToTLV class for encoding command data field and attribute value
This commit is contained in:
@@ -33,6 +33,7 @@
|
||||
#include "app/CommandPathParams.h"
|
||||
#include "app/CommandSender.h"
|
||||
#include "app/InteractionModelEngine.h"
|
||||
#include "app/data-model/EncodableToTLV.h"
|
||||
|
||||
using namespace chip::app::Clusters;
|
||||
using chip::DeviceProxy;
|
||||
@@ -220,6 +221,8 @@ void binding_init()
|
||||
}
|
||||
|
||||
namespace interaction {
|
||||
using chip::app::DataModel::EncodableToTLV;
|
||||
|
||||
namespace invoke {
|
||||
|
||||
using command_data_tag = chip::app::CommandDataIB::Tag;
|
||||
@@ -230,6 +233,22 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
|
||||
const char *command_data_json_str, custom_command_callback::on_success_callback_t on_success,
|
||||
custom_command_callback::on_error_callback_t on_error,
|
||||
const Optional<uint16_t> &timed_invoke_timeout_ms, const Optional<Timeout> &response_timeout)
|
||||
{
|
||||
custom_encodable_type type(command_data_json_str, custom_encodable_type::interaction_type::k_invoke_cmd);
|
||||
return send_request(ctx, remote_device, command_path, type, on_success, on_error, timed_invoke_timeout_ms, response_timeout);
|
||||
}
|
||||
|
||||
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
|
||||
const char *command_data_json_str)
|
||||
{
|
||||
custom_encodable_type type(command_data_json_str, custom_encodable_type::interaction_type::k_invoke_cmd);
|
||||
return send_group_request(fabric_index, command_path, type);
|
||||
}
|
||||
|
||||
esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPathParams &command_path,
|
||||
const EncodableToTLV &encodable, custom_command_callback::on_success_callback_t on_success,
|
||||
custom_command_callback::on_error_callback_t on_error,
|
||||
const Optional<uint16_t> &timed_invoke_timeout_ms, const Optional<Timeout> &response_timeout)
|
||||
{
|
||||
if (!remote_device->GetSecureSession().HasValue() || remote_device->GetSecureSession().Value()->IsGroupSession()) {
|
||||
ESP_LOGE(TAG, "Invalid Session Type");
|
||||
@@ -256,26 +275,8 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
|
||||
ESP_LOGE(TAG, "No memory for command sender");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
chip::app::CommandSender::PrepareCommandParameters prepare_command_params;
|
||||
if (command_sender->PrepareCommand(command_path, prepare_command_params) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to prepare command");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
TLVWriter *writer = command_sender->GetCommandDataIBTLVWriter();
|
||||
if (writer == nullptr) {
|
||||
ESP_LOGE(TAG, "No TLV writer in command sender");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_err_t err = json_to_tlv(command_data_json_str, *writer, ContextTag(command_data_tag::kFields));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to convert json string to TLV");
|
||||
return err;
|
||||
}
|
||||
chip::app::CommandSender::FinishCommandParameters finish_command_params(timed_invoke_timeout_ms);
|
||||
if (command_sender->FinishCommand(finish_command_params) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to finish command");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
chip::app::CommandSender::AddRequestDataParameters add_request_data_params(timed_invoke_timeout_ms);
|
||||
command_sender->AddRequestData(command_path, encodable, add_request_data_params);
|
||||
if (command_sender->SendCommandRequest(remote_device->GetSecureSession().Value(), response_timeout) !=
|
||||
CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to send command request");
|
||||
@@ -287,7 +288,7 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
|
||||
}
|
||||
|
||||
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
|
||||
const char *command_data_json_str)
|
||||
const EncodableToTLV &encodeable)
|
||||
{
|
||||
if (!command_path.mFlags.Has(chip::app::CommandPathFlags::kGroupIdValid)) {
|
||||
ESP_LOGE(TAG, "Invalid CommandPathFlags");
|
||||
@@ -301,26 +302,8 @@ esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams
|
||||
ESP_LOGE(TAG, "No memory for command sender");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
chip::app::CommandSender::PrepareCommandParameters prepare_command_params;
|
||||
if (command_sender->PrepareCommand(command_path, prepare_command_params) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to prepare command");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
TLVWriter *writer = command_sender->GetCommandDataIBTLVWriter();
|
||||
if (writer == nullptr) {
|
||||
ESP_LOGE(TAG, "No TLV writer in command sender");
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
}
|
||||
esp_err_t err = json_to_tlv(command_data_json_str, *writer, ContextTag(command_data_tag::kFields));
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to convert json string to TLV");
|
||||
return err;
|
||||
}
|
||||
chip::app::CommandSender::FinishCommandParameters finish_command_params;
|
||||
if (command_sender->FinishCommand(finish_command_params) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to finish command");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
chip::app::CommandSender::AddRequestDataParameters add_request_data_params;
|
||||
command_sender->AddRequestData(command_path, encodeable, add_request_data_params);
|
||||
if (command_sender->SendGroupCommandRequest(SessionHandle(session)) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to send command request");
|
||||
return ESP_FAIL;
|
||||
@@ -545,7 +528,7 @@ private:
|
||||
WriteClient::Callback &m_callback;
|
||||
};
|
||||
|
||||
static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf_size, const char *attr_val_json_str,
|
||||
static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf_size, const EncodableToTLV &encodable,
|
||||
TLVReader &out_reader)
|
||||
{
|
||||
TLVWriter writer;
|
||||
@@ -554,9 +537,9 @@ static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf
|
||||
esp_err_t err = ESP_OK;
|
||||
|
||||
writer.Init(encoded_buf, encoded_buf_size);
|
||||
if ((err = json_to_tlv(attr_val_json_str, writer, chip::TLV::AnonymousTag())) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to parse attribute value");
|
||||
return err;
|
||||
if (encodable.EncodeTo(writer, chip::TLV::AnonymousTag()) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to encode attribute value");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (writer.Finalize() != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to finalize tlv writer");
|
||||
@@ -584,7 +567,7 @@ static esp_err_t encode_attribute_value(uint8_t *encoded_buf, size_t encoded_buf
|
||||
}
|
||||
|
||||
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
|
||||
const char *attr_val_json_str, WriteClient::Callback &callback,
|
||||
const chip::app::DataModel::EncodableToTLV &encodable, WriteClient::Callback &callback,
|
||||
const chip::Optional<uint16_t> &timeout_ms)
|
||||
{
|
||||
esp_err_t err = ESP_OK;
|
||||
@@ -617,7 +600,7 @@ esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
TLVReader attr_val_reader;
|
||||
err = encode_attribute_value(encoded_buf.Get(), k_encoded_buf_size, attr_val_json_str, attr_val_reader);
|
||||
err = encode_attribute_value(encoded_buf.Get(), k_encoded_buf_size, encodable, attr_val_reader);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to encode attribute value to a TLV reader");
|
||||
return err;
|
||||
@@ -634,6 +617,15 @@ esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams
|
||||
write_client.release();
|
||||
client_deleter_callback.release();
|
||||
return ESP_OK;
|
||||
|
||||
}
|
||||
|
||||
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
|
||||
const char *attr_val_json_str, WriteClient::Callback &callback,
|
||||
const chip::Optional<uint16_t> &timeout_ms)
|
||||
{
|
||||
custom_encodable_type type(attr_val_json_str, custom_encodable_type::interaction_type::k_write_attr);
|
||||
return send_request(remote_device, attr_path, type, callback, timeout_ms);
|
||||
}
|
||||
|
||||
} // namespace write
|
||||
|
||||
@@ -14,9 +14,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <json_to_tlv.h>
|
||||
#include <app-common/zap-generated/cluster-objects.h>
|
||||
#include <app/data-model/EncodableToTLV.h>
|
||||
#include <cassert>
|
||||
#include <esp_err.h>
|
||||
#include <esp_matter_core.h>
|
||||
#include <string.h>
|
||||
|
||||
namespace esp_matter {
|
||||
namespace client {
|
||||
@@ -35,6 +39,44 @@ using chip::Messaging::ExchangeManager;
|
||||
using chip::System::Clock::Timeout;
|
||||
using chip::TLV::TLVReader;
|
||||
using client::peer_device_t;
|
||||
using chip::app::DataModel::EncodableToTLV;
|
||||
|
||||
class custom_encodable_type : public EncodableToTLV
|
||||
{
|
||||
public:
|
||||
const char *k_empty_command_data = "{}";
|
||||
const char *k_null_attribute_data = "null";
|
||||
enum interaction_type {
|
||||
k_invoke_cmd = 0,
|
||||
k_write_attr,
|
||||
};
|
||||
|
||||
custom_encodable_type(const char *json_str, interaction_type usage)
|
||||
{
|
||||
if (json_str) {
|
||||
m_json_str = strdup(json_str);
|
||||
} else {
|
||||
if (usage == k_invoke_cmd) {
|
||||
m_json_str = strdup("{}");
|
||||
} else if (usage == k_write_attr) {
|
||||
m_json_str = strdup("null");
|
||||
}
|
||||
}
|
||||
assert(m_json_str);
|
||||
}
|
||||
|
||||
~custom_encodable_type() { free(m_json_str); }
|
||||
|
||||
CHIP_ERROR EncodeTo(chip::TLV::TLVWriter & writer, chip::TLV::Tag tag) const override
|
||||
{
|
||||
if (json_to_tlv(m_json_str, writer, tag) != ESP_OK) {
|
||||
return CHIP_ERROR_INTERNAL;
|
||||
}
|
||||
return CHIP_NO_ERROR;
|
||||
}
|
||||
private:
|
||||
char *m_json_str = NULL;
|
||||
};
|
||||
|
||||
/** Command invoke APIs
|
||||
*
|
||||
@@ -108,6 +150,18 @@ esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPat
|
||||
|
||||
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
|
||||
const char *command_data_json_str);
|
||||
|
||||
esp_err_t send_request(void *ctx, peer_device_t *remote_device, const CommandPathParams &command_path,
|
||||
const chip::app::DataModel::EncodableToTLV &encodable,
|
||||
custom_command_callback::on_success_callback_t on_success,
|
||||
custom_command_callback::on_error_callback_t on_error,
|
||||
const Optional<uint16_t> &timed_invoke_timeout_ms,
|
||||
const Optional<Timeout> &response_timeout = chip::NullOptional);
|
||||
|
||||
|
||||
esp_err_t send_group_request(const uint8_t fabric_index, const CommandPathParams &command_path,
|
||||
const chip::app::DataModel::EncodableToTLV &encodable);
|
||||
|
||||
} // namespace invoke
|
||||
|
||||
/** Attribute/event read API
|
||||
@@ -127,6 +181,10 @@ namespace write {
|
||||
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
|
||||
const char *attr_val_json_str, WriteClient::Callback &callback,
|
||||
const chip::Optional<uint16_t> &timeout_ms);
|
||||
|
||||
esp_err_t send_request(client::peer_device_t *remote_device, AttributePathParams &attr_path,
|
||||
const chip::app::DataModel::EncodableToTLV &encodable, WriteClient::Callback &callback,
|
||||
const chip::Optional<uint16_t> &timeout_ms);
|
||||
} // namespace write
|
||||
|
||||
namespace subscribe {
|
||||
|
||||
@@ -20,14 +20,6 @@ menu "ESP Matter Controller"
|
||||
help
|
||||
Enable the matter commissioner in the ESP Matter controller.
|
||||
|
||||
config ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN
|
||||
int "Max JSON string buffer length"
|
||||
depends on ESP_MATTER_CONTROLLER_ENABLE
|
||||
default 1024
|
||||
help
|
||||
Max JSON string buffer length. This buffer will be used to store the command data field
|
||||
for cluster-invoked command or attribute value for write-attribute command.
|
||||
|
||||
choice ESP_MATTER_COMMISSIONER_ATTESTATION_TRUST_STORE
|
||||
prompt "Attestation Trust Store"
|
||||
depends on ESP_MATTER_COMMISSIONER_ENABLE
|
||||
|
||||
@@ -259,10 +259,6 @@ esp_err_t send_invoke_cluster_command(uint64_t destination_id, uint16_t endpoint
|
||||
uint32_t command_id, const char *command_data_field,
|
||||
chip::Optional<uint16_t> timed_invoke_timeout_ms)
|
||||
{
|
||||
if (command_data_field && strlen(command_data_field) >= k_command_data_field_buffer_size) {
|
||||
ESP_LOGE(TAG, "The command data field buffer is too small for this command, please increase the buffer size");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
cluster_command *cmd = chip::Platform::New<cluster_command>(destination_id, endpoint_id, cluster_id, command_id,
|
||||
command_data_field, timed_invoke_timeout_ms);
|
||||
if (!cmd) {
|
||||
|
||||
@@ -31,9 +31,7 @@ using chip::Messaging::ExchangeManager;
|
||||
using chip::TLV::TLVReader;
|
||||
using esp_matter::client::peer_device_t;
|
||||
using esp_matter::client::interaction::invoke::custom_command_callback;
|
||||
|
||||
constexpr char k_empty_command_data_field[] = "{}";
|
||||
constexpr size_t k_command_data_field_buffer_size = CONFIG_ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN;
|
||||
using esp_matter::client::interaction::custom_encodable_type;
|
||||
|
||||
/** Cluster command class to send an invoke interaction command to a server **/
|
||||
class cluster_command {
|
||||
@@ -47,19 +45,13 @@ public:
|
||||
, m_endpoint_id(endpoint_id)
|
||||
, m_cluster_id(cluster_id)
|
||||
, m_command_id(command_id)
|
||||
, m_command_data_field(command_data_field, custom_encodable_type::interaction_type::k_invoke_cmd)
|
||||
, m_timed_invoke_timeout_ms(timed_invoke_timeout_ms)
|
||||
, on_device_connected_cb(on_device_connected_fcn, this)
|
||||
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this)
|
||||
, on_success_cb(on_success)
|
||||
, on_error_cb(on_error)
|
||||
{
|
||||
if (command_data_field) {
|
||||
strncpy(m_command_data_field, command_data_field, k_command_data_field_buffer_size - 1);
|
||||
m_command_data_field[strnlen(command_data_field, k_command_data_field_buffer_size - 1)] = 0;
|
||||
} else {
|
||||
strcpy(m_command_data_field, k_empty_command_data_field);
|
||||
m_command_data_field[strlen(k_empty_command_data_field)] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~cluster_command() {}
|
||||
@@ -73,7 +65,7 @@ private:
|
||||
uint16_t m_endpoint_id;
|
||||
uint32_t m_cluster_id;
|
||||
uint32_t m_command_id;
|
||||
char m_command_data_field[k_command_data_field_buffer_size];
|
||||
custom_encodable_type m_command_data_field;
|
||||
chip::Optional<uint16_t> m_timed_invoke_timeout_ms;
|
||||
|
||||
static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
|
||||
|
||||
@@ -46,7 +46,7 @@ void write_command::on_device_connected_fcn(void *context, ExchangeManager &exch
|
||||
{
|
||||
write_command *cmd = (write_command *)context;
|
||||
chip::OperationalDeviceProxy device_proxy(&exchangeMgr, sessionHandle);
|
||||
esp_err_t err = interaction::write::send_request(&device_proxy, cmd->m_attr_path, cmd->m_attr_val_str,
|
||||
esp_err_t err = interaction::write::send_request(&device_proxy, cmd->m_attr_path, cmd->m_attr_val,
|
||||
cmd->m_chunked_callback, chip::NullOptional);
|
||||
if (err != ESP_OK) {
|
||||
chip::Platform::Delete(cmd);
|
||||
|
||||
@@ -33,9 +33,7 @@ using chip::app::WriteClient;
|
||||
using chip::Messaging::ExchangeManager;
|
||||
using chip::TLV::TLVElementType;
|
||||
using esp_matter::client::peer_device_t;
|
||||
|
||||
constexpr char *k_null_attribute_val_str = "null";
|
||||
constexpr size_t k_attr_val_str_buf_size = CONFIG_ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN;
|
||||
using esp_matter::client::interaction::custom_encodable_type;
|
||||
|
||||
/** Write command class to send a write interaction command to a server **/
|
||||
class write_command : public WriteClient::Callback {
|
||||
@@ -46,17 +44,9 @@ public:
|
||||
: m_node_id(node_id)
|
||||
, m_attr_path(endpoint_id, cluster_id, attribute_id)
|
||||
, m_chunked_callback(this)
|
||||
, m_attr_val(attribute_val_str, custom_encodable_type::interaction_type::k_write_attr)
|
||||
, on_device_connected_cb(on_device_connected_fcn, this)
|
||||
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this)
|
||||
{
|
||||
if (attribute_val_str) {
|
||||
strncpy(m_attr_val_str, attribute_val_str, k_attr_val_str_buf_size - 1);
|
||||
m_attr_val_str[strnlen(attribute_val_str, k_attr_val_str_buf_size - 1)] = 0;
|
||||
} else {
|
||||
strcpy(m_attr_val_str, k_null_attribute_val_str);
|
||||
m_attr_val_str[strlen(k_null_attribute_val_str)] = 0;
|
||||
}
|
||||
}
|
||||
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this) {}
|
||||
|
||||
~write_command() {}
|
||||
|
||||
@@ -86,7 +76,7 @@ private:
|
||||
uint64_t m_node_id;
|
||||
AttributePathParams m_attr_path;
|
||||
ChunkedWriteCallback m_chunked_callback;
|
||||
char m_attr_val_str[k_attr_val_str_buf_size];
|
||||
custom_encodable_type m_attr_val;
|
||||
|
||||
static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
|
||||
const SessionHandle &sessionHandle);
|
||||
|
||||
Reference in New Issue
Block a user