diff --git a/components/esp_matter_controller/CMakeLists.txt b/components/esp_matter_controller/CMakeLists.txt index 0abf888a5..6e1ef193f 100644 --- a/components/esp_matter_controller/CMakeLists.txt +++ b/components/esp_matter_controller/CMakeLists.txt @@ -7,4 +7,4 @@ endif() idf_component_register(SRC_DIRS ${src_dirs_list} INCLUDE_DIRS ${include_dirs_list} - REQUIRES chip esp_matter esp_matter_console) + REQUIRES chip esp_matter esp_matter_console json_parser) diff --git a/components/esp_matter_controller/esp_matter_controller_utils.cpp b/components/esp_matter_controller/esp_matter_controller_utils.cpp new file mode 100644 index 000000000..23c8141d9 --- /dev/null +++ b/components/esp_matter_controller/esp_matter_controller_utils.cpp @@ -0,0 +1,46 @@ +// Copyright 2022 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include + +static uint8_t char_to_hex_digit(char c) +{ + if (c >= '0' && c <= '9') { + return c - '0'; + } else if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } else { + return 0xFF; + } +} + +int oct_str_to_byte_arr(char *oct_str, uint8_t *byte_array) +{ + if (strlen(oct_str) % 2 != 0) { + return -1; + } + size_t byte_array_len = strlen(oct_str) / 2; + for (size_t idx = 0; idx < byte_array_len; ++idx) { + uint8_t digit1 = char_to_hex_digit(oct_str[2 * idx]); + uint8_t digit2 = char_to_hex_digit(oct_str[2 * idx + 1]); + if (digit1 == 0xFF || digit2 == 0xFF) { + return -1; + } + byte_array[idx] = (digit1 << 4) + digit2; + } + return byte_array_len; +} diff --git a/components/esp_matter_controller/esp_matter_controller_utils.h b/components/esp_matter_controller/esp_matter_controller_utils.h new file mode 100644 index 000000000..0447538ac --- /dev/null +++ b/components/esp_matter_controller/esp_matter_controller_utils.h @@ -0,0 +1,19 @@ +// Copyright 2022 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +int oct_str_to_byte_arr(char *oct_str, uint8_t *byte_array); diff --git a/components/esp_matter_controller/esp_matter_controller_write_command.cpp b/components/esp_matter_controller/esp_matter_controller_write_command.cpp index 2a782e01d..8d910d4bf 100644 --- a/components/esp_matter_controller/esp_matter_controller_write_command.cpp +++ b/components/esp_matter_controller/esp_matter_controller_write_command.cpp @@ -12,11 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include #include +#include #include +#include using namespace chip::app::Clusters; +using chip::ByteSpan; using chip::DeviceProxy; +using chip::app::DataModel::List; +using chip::Platform::New; static const char *TAG = "write_command"; @@ -30,7 +36,7 @@ void write_command::on_device_connected_fcn(void *context, ExchangeManager &e write_command *cmd = (write_command *)context; CHIP_ERROR err = CHIP_NO_ERROR; WriteClient *write_client = - chip::Platform::New(&exchangeMgr, &(cmd->get_chunked_write_callback()), chip::NullOptional, false); + New(&exchangeMgr, &(cmd->get_chunked_write_callback()), chip::NullOptional, false); if (!write_client) { ESP_LOGE(TAG, "Failed to alloc memory for WriteClient"); chip::Platform::Delete(cmd); @@ -81,22 +87,16 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_ switch (attribute_id) { case OnOff::Attributes::OnTime::Id: case OnOff::Attributes::OffWaitTime::Id: { - write_command *cmd = chip::Platform::New>( - node_id, endpoint_id, OnOff::Id, attribute_id, (uint16_t)strtol(attribute_val_str, NULL, 10)); - if (!cmd) { - ESP_LOGE(TAG, "Failed to alloc memory for write_command"); - return ESP_ERR_NO_MEM; - } + write_command *cmd = New>(node_id, endpoint_id, OnOff::Id, attribute_id, + (uint16_t)strtol(attribute_val_str, NULL, 10)); + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); return cmd->send_command(); break; } case OnOff::Attributes::StartUpOnOff::Id: { - write_command *cmd = chip::Platform::New>( - node_id, endpoint_id, OnOff::Id, attribute_id, (uint8_t)strtol(attribute_val_str, NULL, 10)); - if (!cmd) { - ESP_LOGE(TAG, "Failed to alloc memory for write_command"); - return ESP_ERR_NO_MEM; - } + write_command *cmd = New>(node_id, endpoint_id, OnOff::Id, attribute_id, + (uint8_t)strtol(attribute_val_str, NULL, 10)); + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); return cmd->send_command(); break; } @@ -118,12 +118,9 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_ case LevelControl::Attributes::OnOffTransitionTime::Id: case LevelControl::Attributes::OnTransitionTime::Id: case LevelControl::Attributes::OffTransitionTime::Id: { - write_command *cmd = chip::Platform::New>( + write_command *cmd = New>( node_id, endpoint_id, LevelControl::Id, attribute_id, (uint16_t)strtol(attribute_val_str, NULL, 10)); - if (!cmd) { - ESP_LOGE(TAG, "Failed to alloc memory for write_command"); - return ESP_ERR_NO_MEM; - } + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); return cmd->send_command(); break; } @@ -131,12 +128,9 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_ case LevelControl::Attributes::DefaultMoveRate::Id: case LevelControl::Attributes::Options::Id: case LevelControl::Attributes::StartUpCurrentLevel::Id: { - write_command *cmd = chip::Platform::New>( - node_id, endpoint_id, LevelControl::Id, attribute_id, (uint8_t)strtol(attribute_val_str, NULL, 10)); - if (!cmd) { - ESP_LOGE(TAG, "Failed to alloc memory for write_command"); - return ESP_ERR_NO_MEM; - } + write_command *cmd = New>(node_id, endpoint_id, LevelControl::Id, attribute_id, + (uint8_t)strtol(attribute_val_str, NULL, 10)); + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); return cmd->send_command(); break; } @@ -156,22 +150,16 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_ esp_err_t err = ESP_OK; switch (attribute_id) { case ColorControl::Attributes::StartUpColorTemperatureMireds::Id: { - write_command *cmd = chip::Platform::New>( + write_command *cmd = New>( node_id, endpoint_id, ColorControl::Id, attribute_id, (uint16_t)strtol(attribute_val_str, NULL, 10)); - if (!cmd) { - ESP_LOGE(TAG, "Failed to alloc memory for write_command"); - return ESP_ERR_NO_MEM; - } + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); return cmd->send_command(); break; } case ColorControl::Attributes::Options::Id: { - write_command *cmd = chip::Platform::New>( - node_id, endpoint_id, ColorControl::Id, attribute_id, (uint8_t)strtol(attribute_val_str, NULL, 10)); - if (!cmd) { - ESP_LOGE(TAG, "Failed to alloc memory for write_command"); - return ESP_ERR_NO_MEM; - } + write_command *cmd = New>(node_id, endpoint_id, ColorControl::Id, attribute_id, + (uint8_t)strtol(attribute_val_str, NULL, 10)); + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); return cmd->send_command(); break; } @@ -183,6 +171,287 @@ static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_ } } // namespace color_control +namespace access_control { + +using AccessControl::AuthMode; +using AccessControl::Privilege; + +constexpr size_t k_max_acl_entries = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_ENTRIES_PER_FABRIC; +constexpr size_t k_max_subjects_per_acl = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_SUBJECTS_PER_ENTRY; +constexpr size_t k_max_targets_per_acl = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_TARGETS_PER_ENTRY; + +using acl_obj = AccessControl::Structs::AccessControlEntry::Type; +using acl_target_obj = AccessControl::Structs::Target::Type; +typedef struct acl_attr { + acl_obj acl_array[k_max_acl_entries]; + uint64_t subjects_array[k_max_acl_entries][k_max_subjects_per_acl]; + acl_target_obj targets_array[k_max_acl_entries][k_max_targets_per_acl]; +} acl_attr_t; + +static void acl_attr_free(void *ctx) +{ + acl_attr_t *attr_ptr = reinterpret_cast(ctx); + chip::Platform::Delete(attr_ptr); +} + +static esp_err_t parse_acl_json(char *json_str, acl_attr_t *acl, size_t *acl_size) +{ + jparse_ctx_t jctx; + ESP_RETURN_ON_FALSE(json_parse_start(&jctx, json_str, strlen(json_str)) == 0, ESP_ERR_INVALID_ARG, TAG, + "ACL json string is wrong"); + size_t acl_index = 0; + while (acl_index < k_max_acl_entries && json_arr_get_object(&jctx, acl_index) == 0) { + int int_val; + // FabricIndex + if (json_obj_get_int(&jctx, "fabricIndex", &int_val) == 0) { + acl->acl_array[acl_index].fabricIndex = int_val; + } + // Privilege + ESP_RETURN_ON_FALSE(json_obj_get_int(&jctx, "privilege", &int_val) == 0, ESP_ERR_INVALID_ARG, TAG, + "ACL json string is wrong on privilege"); + acl->acl_array[acl_index].privilege = Privilege(int_val); + // AuthMode + ESP_RETURN_ON_FALSE(json_obj_get_int(&jctx, "authMode", &int_val) == 0, ESP_ERR_INVALID_ARG, TAG, + "ACL json string is wrong on authMode"); + acl->acl_array[acl_index].authMode = AuthMode(int_val); + // Subjects + int subjects_num = 0; + if (json_obj_get_array(&jctx, "subjects", &subjects_num) == 0 && subjects_num > 0) { + ESP_RETURN_ON_FALSE(subjects_num <= k_max_subjects_per_acl, ESP_ERR_INVALID_ARG, TAG, + "ACL json string is wrong on subjects length"); + for (size_t subj_index = 0; subj_index < subjects_num; ++subj_index) { + int64_t subject_val; + ESP_RETURN_ON_FALSE(json_arr_get_int64(&jctx, subj_index, &subject_val) == 0, ESP_ERR_INVALID_ARG, TAG, + "ACL json string is wrong subject value"); + acl->subjects_array[acl_index][subj_index] = subject_val; + } + acl->acl_array[acl_index].subjects.SetNonNull(acl->subjects_array[acl_index], subjects_num); + json_obj_leave_array(&jctx); + } else { + acl->acl_array[acl_index].subjects.SetNull(); + } + // Targets + int targets_num = 0; + if (json_obj_get_array(&jctx, "targets", &targets_num) == 0 && targets_num > 0) { + ESP_RETURN_ON_FALSE(targets_num <= k_max_targets_per_acl, ESP_ERR_INVALID_ARG, TAG, + "ACL json string is wrong on targets length"); + for (size_t targ_index = 0; targ_index < targets_num; ++targ_index) { + ESP_RETURN_ON_FALSE(json_arr_get_object(&jctx, targ_index) == 0, ESP_ERR_INVALID_ARG, TAG, + "Failed to get target at index %d", targ_index); + int64_t cluster_val, device_type_val; + int endpoint_val; + bool exist_cluster, exist_endpoint, exist_device_type; + + exist_cluster = json_obj_get_int64(&jctx, "cluster", &cluster_val) == 0; + exist_endpoint = json_obj_get_int(&jctx, "endpoint", &endpoint_val) == 0; + exist_device_type = json_obj_get_int64(&jctx, "deviceType", &device_type_val) == 0; + if ((!exist_cluster && !exist_endpoint && !exist_device_type) || + (exist_endpoint && exist_device_type)) { + ESP_LOGE(TAG, "ACL json string is wrong targets value, skip"); + json_arr_leave_object(&jctx); + continue; + } + // Cluster + if (exist_cluster) { + acl->targets_array[acl_index][targ_index].cluster.SetNonNull(static_cast(cluster_val)); + } else { + acl->targets_array[acl_index][targ_index].cluster.SetNull(); + } + // Endpoint + if (exist_endpoint) { + acl->targets_array[acl_index][targ_index].endpoint.SetNonNull(static_cast(endpoint_val)); + } else { + acl->targets_array[acl_index][targ_index].endpoint.SetNull(); + } + // DeviceType + if (exist_device_type) { + acl->targets_array[acl_index][targ_index].deviceType.SetNonNull( + static_cast(device_type_val)); + } else { + acl->targets_array[acl_index][targ_index].deviceType.SetNull(); + } + json_arr_leave_object(&jctx); + } + acl->acl_array[acl_index].targets.SetNonNull(acl->targets_array[acl_index], targets_num); + json_obj_leave_array(&jctx); + } else { + acl->acl_array[acl_index].targets.SetNull(); + } + // Leave Object + json_arr_leave_object(&jctx); + acl_index++; + } + *acl_size = acl_index; + return ESP_OK; +} + +// The extension data may be used to store arbitrary TLV-encoded data related to a fabric’s ACL Entries. +constexpr size_t k_max_extension_entries = CHIP_CONFIG_EXAMPLE_ACCESS_CONTROL_MAX_ENTRIES_PER_FABRIC; +constexpr size_t k_max_extension_data_len = 128; + +using extension_obj = AccessControl::Structs::ExtensionEntry::Type; +typedef struct extension_attr { + extension_obj extension_array[k_max_extension_entries]; + uint8_t data_array[k_max_extension_entries][k_max_extension_data_len]; +} extension_attr_t; + +static void extension_attr_free(void *ctx) +{ + extension_attr_t *attr = reinterpret_cast(ctx); + chip::Platform::Delete(attr); +} + +static esp_err_t parse_extension_json(char *json_str, extension_attr_t *extension, size_t *extension_size) +{ + jparse_ctx_t jctx; + ESP_RETURN_ON_FALSE(json_parse_start(&jctx, json_str, strlen(json_str)) == 0, ESP_ERR_INVALID_ARG, TAG, + "Extension json string is wrong"); + size_t index = 0; + while (index < k_max_extension_entries && json_arr_get_object(&jctx, index) == 0) { + int fabric_index; + if (json_obj_get_int(&jctx, "fabricIndex", &fabric_index) == 0) { + extension->extension_array[index].fabricIndex = fabric_index; + } + + char data_oct_str[k_max_extension_data_len * 2 + 1] = {0}; + if (json_obj_get_string(&jctx, "data", data_oct_str, k_max_extension_data_len * 2 + 1) != 0) { + ESP_LOGE(TAG, "Failed to parse the data json octstring"); + return ESP_ERR_INVALID_ARG; + } else { + size_t data_len = oct_str_to_byte_arr(data_oct_str, extension->data_array[index]); + ESP_RETURN_ON_FALSE(data_len > 0, ESP_ERR_INVALID_ARG, TAG, + "Failed to convert the data octstring to byte array"); + extension->extension_array[index].data = ByteSpan(extension->data_array[index], data_len); + } + json_arr_leave_object(&jctx); + index++; + } + *extension_size = index; + return ESP_OK; +} + +static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_t attribute_id, char *attribute_val_str) +{ + esp_err_t err = ESP_OK; + switch (attribute_id) { + case AccessControl::Attributes::Acl::Id: { + size_t acl_size = 0; + acl_attr_t *attr_val = New(); + ESP_RETURN_ON_FALSE(attr_val, ESP_ERR_NO_MEM, TAG, "Failed to alloc acl_attr_t"); + ESP_RETURN_ON_ERROR(parse_acl_json(attribute_val_str, attr_val, &acl_size), TAG, + "Failed to parse the acl json string"); + List access_control_list(attr_val->acl_array, acl_size); + write_command> *cmd = New>>(node_id, endpoint_id, AccessControl::Id, + attribute_id, access_control_list); + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); + cmd->set_attribute_free_handler(acl_attr_free, attr_val); + return cmd->send_command(); + break; + } + case AccessControl::Attributes::Extension::Id: { + size_t extension_size = 0; + extension_attr_t *attr_val = New(); + ESP_RETURN_ON_FALSE(attr_val, ESP_ERR_NO_MEM, TAG, "Failed to alloc extension_attr_t"); + ESP_RETURN_ON_ERROR(parse_extension_json(attribute_val_str, attr_val, &extension_size), TAG, + "Failed to parse the acl json string"); + List extension_list(attr_val->extension_array, extension_size); + write_command> *cmd = New>>( + node_id, endpoint_id, AccessControl::Id, attribute_id, extension_list); + cmd->set_attribute_free_handler(extension_attr_free, attr_val); + return cmd->send_command(); + break; + } + default: + err = ESP_ERR_NOT_SUPPORTED; + break; + } + return err; +} + +} // namespace access_control + +namespace binding { +using binding_obj = Binding::Structs::TargetStruct::Type; +typedef struct binding_attr { + binding_obj binding_array[CONFIG_MAX_BINDINGS]; +} binding_attr_t; + +static void binding_attr_free(void *ctx) +{ + binding_attr_t *attr_ptr = reinterpret_cast(ctx); + chip::Platform::Delete(attr_ptr); +} + +static esp_err_t parse_binding_json(char *json_str, binding_attr_t *binding, size_t *binding_size) +{ + jparse_ctx_t jctx; + ESP_RETURN_ON_FALSE(json_parse_start(&jctx, json_str, strlen(json_str)) == 0, ESP_ERR_INVALID_ARG, TAG, + "Binding Table json string is wrong"); + size_t index = 0; + while (index < CONFIG_MAX_BINDINGS && json_arr_get_object(&jctx, index) == 0) { + int int_val; + int64_t int64_val; + // Fabric + if (json_obj_get_int(&jctx, "fabricIndex", &int_val) == 0) { + binding->binding_array[index].fabricIndex = int_val; + } + + if (json_obj_get_int64(&jctx, "node", &int64_val) == 0) { + // Unicast Binding + binding->binding_array[index].node.SetValue(int64_val); + binding->binding_array[index].group.ClearValue(); + + ESP_RETURN_ON_FALSE(json_obj_get_int(&jctx, "endpoint", &int_val) == 0, ESP_ERR_INVALID_ARG, TAG, + "Binding Table json string is wrong"); + binding->binding_array[index].endpoint.SetValue(int_val); + + ESP_RETURN_ON_FALSE(json_obj_get_int(&jctx, "cluster", &int_val) == 0, ESP_ERR_INVALID_ARG, TAG, + "Binding Table json string is wrong"); + binding->binding_array[index].cluster.SetValue(int_val); + } else if (json_obj_get_int64(&jctx, "group", &int64_val) == 0) { + // Group binding + binding->binding_array[index].group.SetValue(int64_val); + binding->binding_array[index].node.ClearValue(); + binding->binding_array[index].endpoint.ClearValue(); + binding->binding_array[index].cluster.ClearValue(); + } else { + ESP_LOGE(TAG, "Binding Table json string is wrong"); + return ESP_ERR_INVALID_ARG; + } + json_arr_leave_object(&jctx); + index++; + } + *binding_size = index; + return ESP_OK; +} + +static esp_err_t write_attribute(uint64_t node_id, uint16_t endpoint_id, uint32_t attribute_id, char *attribute_val_str) +{ + esp_err_t err = ESP_OK; + switch (attribute_id) { + case Binding::Attributes::Binding::Id: { + size_t binding_size = 0; + binding_attr_t *attr_val = chip::Platform::New(); + ESP_RETURN_ON_FALSE(attr_val, ESP_ERR_NO_MEM, TAG, "Failed to alloc binding_attr_t"); + ESP_RETURN_ON_ERROR(parse_binding_json(attribute_val_str, attr_val, &binding_size), TAG, + "Failed to parse binding json string"); + List binding_list(attr_val->binding_array, binding_size); + write_command> *cmd = + New>>(node_id, endpoint_id, Binding::Id, attribute_id, binding_list); + ESP_RETURN_ON_FALSE(cmd, ESP_ERR_NO_MEM, TAG, "Failed to alloc memory for write_command"); + cmd->set_attribute_free_handler(binding_attr_free, attr_val); + return cmd->send_command(); + break; + } + default: + err = ESP_ERR_NOT_SUPPORTED; + break; + } + return err; +} + +} // namespace binding + } // namespace clusters esp_err_t send_write_attr_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, @@ -198,6 +467,12 @@ esp_err_t send_write_attr_command(uint64_t node_id, uint16_t endpoint_id, uint32 case ColorControl::Id: return clusters::color_control::write_attribute(node_id, endpoint_id, attribute_id, attribute_val_str); break; + case AccessControl::Id: + return clusters::access_control::write_attribute(node_id, endpoint_id, attribute_id, attribute_val_str); + break; + case Binding::Id: + return clusters::binding::write_attribute(node_id, endpoint_id, attribute_id, attribute_val_str); + break; default: return ESP_ERR_NOT_SUPPORTED; } diff --git a/components/esp_matter_controller/esp_matter_controller_write_command.h b/components/esp_matter_controller/esp_matter_controller_write_command.h index 5c05f7965..17eeeebbb 100644 --- a/components/esp_matter_controller/esp_matter_controller_write_command.h +++ b/components/esp_matter_controller/esp_matter_controller_write_command.h @@ -39,12 +39,19 @@ public: , m_attr_path(endpoint_id, cluster_id, attribute_id) , m_chunked_callback(this) , m_attr_val(attribute_val) + , m_attr_free(nullptr) + , m_attr_free_ctx(nullptr) , on_device_connected_cb(on_device_connected_fcn, this) , on_device_connection_failure_cb(on_device_connection_failure_fcn, this) { } - ~write_command() {} + ~write_command() + { + if (m_attr_free && m_attr_free_ctx) { + m_attr_free(m_attr_free_ctx); + } + } AttributePathParams &get_attribute_path() { return m_attr_path; } @@ -54,6 +61,14 @@ public: esp_err_t send_command(); + using attribute_free_handler = void (*)(void *); + esp_err_t set_attribute_free_handler(attribute_free_handler attr_free_handler, void *ctx) + { + m_attr_free = attr_free_handler; + m_attr_free_ctx = ctx; + return ESP_OK; + } + // WriteClient Callback Interface void OnResponse(const WriteClient *client, const ConcreteDataAttributePath &path, StatusIB status) override { @@ -80,6 +95,10 @@ private: AttributePathParams m_attr_path; ChunkedWriteCallback m_chunked_callback; T m_attr_val; + // We need to alloc memory for writing complex attributes asynchronously and free the memory when we delete the + // write_command. + attribute_free_handler m_attr_free; + void *m_attr_free_ctx; static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr, SessionHandle &sessionHandle); static void on_device_connection_failure_fcn(void *context, const ScopedNodeId &peerId, CHIP_ERROR error); diff --git a/components/esp_matter_controller/idf_component.yml b/components/esp_matter_controller/idf_component.yml new file mode 100644 index 000000000..58f130c72 --- /dev/null +++ b/components/esp_matter_controller/idf_component.yml @@ -0,0 +1,3 @@ +## IDF Component Manager Manifest File +dependencies: + espressif/json_parser: "1.0.0"