esp_matter_controller: Add json_parser support for matter controller

This commit is contained in:
WanqQixiang
2022-11-18 11:30:26 +08:00
parent 449160b1ed
commit aec8bd7aac
6 changed files with 399 additions and 37 deletions
@@ -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)
@@ -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 <esp_matter_controller_utils.h>
#include <string.h>
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;
}
@@ -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 <stdint.h>
int oct_str_to_byte_arr(char *oct_str, uint8_t *byte_array);
@@ -12,11 +12,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <esp_check.h>
#include <esp_matter_commissioner.h>
#include <esp_matter_controller_utils.h>
#include <esp_matter_controller_write_command.h>
#include <json_parser.h>
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<T>::on_device_connected_fcn(void *context, ExchangeManager &e
write_command<T> *cmd = (write_command<T> *)context;
CHIP_ERROR err = CHIP_NO_ERROR;
WriteClient *write_client =
chip::Platform::New<WriteClient>(&exchangeMgr, &(cmd->get_chunked_write_callback()), chip::NullOptional, false);
New<WriteClient>(&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<uint16_t> *cmd = chip::Platform::New<write_command<uint16_t>>(
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<uint16_t> *cmd = New<write_command<uint16_t>>(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<uint8_t> *cmd = chip::Platform::New<write_command<uint8_t>>(
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<uint8_t> *cmd = New<write_command<uint8_t>>(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<uint16_t> *cmd = chip::Platform::New<write_command<uint16_t>>(
write_command<uint16_t> *cmd = New<write_command<uint16_t>>(
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<uint8_t> *cmd = chip::Platform::New<write_command<uint8_t>>(
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<uint8_t> *cmd = New<write_command<uint8_t>>(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<uint16_t> *cmd = chip::Platform::New<write_command<uint16_t>>(
write_command<uint16_t> *cmd = New<write_command<uint16_t>>(
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<uint8_t> *cmd = chip::Platform::New<write_command<uint8_t>>(
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<uint8_t> *cmd = New<write_command<uint8_t>>(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<acl_attr_t *>(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<uint32_t>(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<uint16_t>(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<uint32_t>(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 fabrics 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<extension_attr_t *>(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<acl_attr_t>();
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<acl_obj> access_control_list(attr_val->acl_array, acl_size);
write_command<List<acl_obj>> *cmd = New<write_command<List<acl_obj>>>(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<extension_attr_t>();
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_obj> extension_list(attr_val->extension_array, extension_size);
write_command<List<extension_obj>> *cmd = New<write_command<List<extension_obj>>>(
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<binding_attr_t *>(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<binding_attr_t>();
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_obj> binding_list(attr_val->binding_array, binding_size);
write_command<List<binding_obj>> *cmd =
New<write_command<List<binding_obj>>>(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;
}
@@ -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);
@@ -0,0 +1,3 @@
## IDF Component Manager Manifest File
dependencies:
espressif/json_parser: "1.0.0"