Merge branch 'bridge/endpoint_num' into 'main'

Bridge: fix the endpoint number limit issue

Closes CON-761 and CON-830

See merge request app-frameworks/esp-matter!493
This commit is contained in:
Shu Chen
2023-11-09 10:17:58 +08:00
9 changed files with 395 additions and 191 deletions
+5 -1
View File
@@ -1,6 +1,10 @@
# 2-November-2023
All of the non-volatile attribute values now are stored in the namespace `esp_matter_kvs` with the attribute key base64-encoded of bytes (`endpoint-id`+`cluster-id`+`attribute-id`). For the devices that store the non-volatile attribute values in the previous namespace with previous attribute-key, the values will be moved and the previous keys will be erased.
# 29-August-2023
- `ot_storage` partition is no longere required for thread devices as the mechanism for storing data related to the Thread network has been changed in the `openthread` component in ESP-IDF.
- `ot_storage` partition is no longer required for thread devices as the mechanism for storing data related to the Thread network has been changed in the `openthread` component in ESP-IDF.
# 14-April-2023
+50 -58
View File
@@ -67,7 +67,6 @@ using chip::DeviceLayer::ThreadStackMgr;
#define ESP_MATTER_NVS_PART_NAME CONFIG_ESP_MATTER_NVS_PART_NAME
#define ESP_MATTER_MAX_DEVICE_TYPE_COUNT CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT
#define ESP_MATTER_NVS_NODE_NAMESPACE "node"
static const char *TAG = "esp_matter_core";
static bool esp_matter_started = false;
@@ -210,7 +209,7 @@ static esp_err_t store_min_unused_endpoint_id()
}
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_NVS_NODE_NAMESPACE,
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE,
NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open the node nvs_namespace");
@@ -230,18 +229,39 @@ static esp_err_t read_min_unused_endpoint_id()
}
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_NVS_NODE_NAMESPACE,
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE,
NVS_READONLY, &handle);
if (err == ESP_OK) {
err = nvs_get_u16(handle, "min_uu_ep_id", &node->min_unused_endpoint_id);
nvs_close(handle);
}
if (err == ESP_ERR_NVS_NOT_FOUND) {
ESP_LOGI(TAG, "Cannot find the node nvs namespace");
return err;
ESP_LOGI(TAG, "Cannot find minimum unused endpoint_id, try to find in the previous namespace");
// Try to read the minimum unused endpoint_id from the previous node namespace.
err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, "node", NVS_READONLY, &handle);
if (err != ESP_OK) {
ESP_LOGI(TAG, "Failed to open node namespace");
return err;
}
err = nvs_get_u16(handle, "min_uu_ep_id", &node->min_unused_endpoint_id);
nvs_close(handle);
if (err == ESP_OK) {
// If the minimum unused endpoint_id is got, we will erase it from the previous namespace
// and store it to the new namespace.
if (nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, "node", NVS_READWRITE, &handle) == ESP_OK) {
if (nvs_erase_key(handle, "min_uu_ep_id") != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase minimum unused endpoint_id");
} else {
nvs_commit(handle);
}
nvs_close(handle);
}
return store_min_unused_endpoint_id();
}
} else if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to get minimum unused endpoint_id in the %s nvs_namespace", ESP_MATTER_KVS_NAMESPACE);
}
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open the node nvs_namespace");
return err;
}
err = nvs_get_u16(handle, "min_uu_ep_id", &node->min_unused_endpoint_id);
nvs_close(handle);
return err;
}
@@ -414,27 +434,6 @@ static int get_next_index()
return 0xFFFF;
}
static esp_err_t erase_persistent_data(endpoint_t *endpoint)
{
uint16_t endpoint_id = endpoint::get_id(endpoint);
char nvs_namespace[16] = {0};
snprintf(nvs_namespace, 16, "endpoint_%" PRIX16 "", endpoint_id); /* endpoint_id */
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, nvs_namespace, NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition: %s, %d", nvs_namespace, err);
return err;
}
err = nvs_erase_all(handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error erasing partition: %s, %d", nvs_namespace, err);
}
nvs_commit(handle);
nvs_close(handle);
return err;
}
static esp_err_t disable(endpoint_t *endpoint)
{
if (!endpoint) {
@@ -504,8 +503,7 @@ static esp_err_t disable(endpoint_t *endpoint)
esp_matter_mem_free(endpoint_type);
current_endpoint->endpoint_type = NULL;
/* Clear endpoint persistent data in nvs flash */
return erase_persistent_data(endpoint);
return ESP_OK;
}
esp_err_t enable(endpoint_t *endpoint)
@@ -1056,29 +1054,18 @@ esp_err_t factory_reset()
node_t *node = node::get();
if (node) {
/* ESP Matter data model is used. Erase all the data that we have added in nvs. */
nvs_handle_t node_handle;
err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_NVS_NODE_NAMESPACE,
NVS_READWRITE, &node_handle);
if (err == ESP_OK) {
nvs_erase_all(node_handle);
}
nvs_commit(node_handle);
nvs_close(node_handle);
nvs_commit(node_handle);
nvs_close(node_handle);
endpoint_t *endpoint = endpoint::get_first(node);
while (endpoint) {
err = endpoint::erase_persistent_data(endpoint);
nvs_handle_t handle;
err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, ESP_MATTER_KVS_NAMESPACE, NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed to open esp_matter nvs partition ");
} else {
err = nvs_erase_all(handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error erasing persistent data of endpoint %" PRIu16 "", endpoint::get_id(endpoint));
continue;
ESP_LOGE(TAG, "Failed to erase esp_matter nvs namespace");
} else {
nvs_commit(handle);
}
endpoint = endpoint::get_next(endpoint);
}
if (err == ESP_OK) {
ESP_LOGI(TAG, "Erasing attribute data completed");
nvs_close(handle);
}
}
@@ -1188,6 +1175,11 @@ static esp_err_t destroy(attribute_t *attribute)
esp_matter_mem_free(current_attribute->bounds);
}
/* Erase the persistent data */
if (current_attribute->flags & ATTRIBUTE_FLAG_NONVOLATILE) {
erase_val_in_nvs(current_attribute->endpoint_id, current_attribute->cluster_id, current_attribute->attribute_id);
}
/* Free */
esp_matter_mem_free(current_attribute);
return ESP_OK;
@@ -1860,11 +1852,11 @@ endpoint_t *resume(node_t *node, uint8_t flags, uint16_t endpoint_id, void *priv
current_endpoint = current_endpoint->next;
}
/* Check */
if (endpoint_id >= current_node->min_unused_endpoint_id) {
/* Check */
if (endpoint_id >= current_node->min_unused_endpoint_id) {
ESP_LOGE(TAG, "The endpoint_id of the resumed endpoint should have been used");
return NULL;
}
}
/* Allocate */
_endpoint_t *endpoint = (_endpoint_t *)esp_matter_mem_calloc(1, sizeof(_endpoint_t));
-23
View File
@@ -582,29 +582,6 @@ esp_err_t set_override_callback(attribute_t *attribute, callback_t callback);
*/
callback_t get_override_callback(attribute_t *attribute);
/** Store in NVS
*
* Store the current attribute val in NVS.
*
* @param[in] attribute Attribute handle.
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t store_val_in_nvs(attribute_t *attribute);
/** Get from NVS
*
* Get the val for current attribute from NVS.
*
* @param[in] attribute Attribute handle.
* @param[out] val Pointer to `esp_matter_attr_val_t`. Use appropriate elements as per the value type.
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t get_val_from_nvs(attribute_t *attribute, esp_matter_attr_val_t *val);
} /* attribute */
namespace command {
@@ -18,6 +18,9 @@
#include <nvs_flash.h>
#include <esp_matter_attribute_utils.h>
#include <esp_matter_mem.h>
#include <esp_matter_nvs.h>
#include <lib/support/Base64.h>
#define ESP_MATTER_NVS_PART_NAME CONFIG_ESP_MATTER_NVS_PART_NAME
@@ -26,21 +29,30 @@ namespace attribute {
const char * TAG = "mtr_nvs";
esp_err_t get_val_from_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t & val)
static void get_attribute_key(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, char *attribute_key)
{
/* Get keys */
char nvs_namespace[16] = {0};
char attribute_key[16] = {0};
snprintf(nvs_namespace, 16, "endpoint_%" PRIX16 "", endpoint_id); /* endpoint_id */
snprintf(attribute_key, 16, "%" PRIX32 ":%" PRIX32 "", cluster_id, attribute_id); /* cluster_id:attribute_id */
// Convert the the endpoint_id, cluster_id, attribute_id to base64 string
uint8_t encode_buf[10] = {0};
char base64_str[17] = {0};
memcpy(&encode_buf[0], &endpoint_id, sizeof(endpoint_id));
memcpy(&encode_buf[2], &cluster_id, sizeof(cluster_id));
memcpy(&encode_buf[6], &attribute_id, sizeof(attribute_id));
chip::Base64Encode(encode_buf, 10, base64_str);
// The last two character must be '='
assert(base64_str[14] == '=' && base64_str[15] == '=');
// Copy the string before '='
strncpy(attribute_key, base64_str, 14);
attribute_key[14] = 0;
}
static esp_err_t nvs_get_val(const char *nvs_namespace, const char *attribute_key, esp_matter_attr_val_t & val)
{
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, nvs_namespace, NVS_READONLY, &handle);
if (err != ESP_OK) {
return err;
}
ESP_LOGD(TAG, "read attribute from nvs: endpoint_id-0x%" PRIx16 ", cluster_id-0x%" PRIx32 ", attribute_id-0x%" PRIx32 "",
endpoint_id, cluster_id, attribute_id);
if (val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
@@ -175,20 +187,14 @@ esp_err_t get_val_from_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t a
return err;
}
esp_err_t store_val_in_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, const esp_matter_attr_val_t & val)
static esp_err_t nvs_store_val(const char *nvs_namespace, const char *attribute_key, const esp_matter_attr_val_t & val)
{
char nvs_namespace[16] = {0};
char attribute_key[16] = {0};
snprintf(nvs_namespace, 16, "endpoint_%" PRIX16 "", endpoint_id); /* endpoint_id */
snprintf(attribute_key, 16, "%" PRIX32 ":%" PRIX32 "", cluster_id, attribute_id); /* cluster_id:attribute_id */
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, nvs_namespace, NVS_READWRITE, &handle);
if (err != ESP_OK) {
return err;
}
ESP_LOGD(TAG, "Store attribute in nvs: endpoint_id-0x%" PRIx16 ", cluster_id-0x%" PRIx32 ", attribute_id-0x%" PRIx32 "",
endpoint_id, cluster_id, attribute_id);
if (val.type == ESP_MATTER_VAL_TYPE_CHAR_STRING ||
val.type == ESP_MATTER_VAL_TYPE_LONG_CHAR_STRING ||
val.type == ESP_MATTER_VAL_TYPE_OCTET_STRING ||
@@ -310,5 +316,69 @@ esp_err_t store_val_in_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t a
return err;
}
static esp_err_t nvs_erase_val(const char *nvs_namespace, const char *attribute_key)
{
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(ESP_MATTER_NVS_PART_NAME, nvs_namespace, NVS_READWRITE, &handle);
if (err != ESP_OK) {
return err;
}
err = nvs_erase_key(handle, attribute_key);
nvs_commit(handle);
nvs_close(handle);
return err;
}
esp_err_t get_val_from_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t & val)
{
/* Get attribute key */
char attribute_key[16] = {0};
get_attribute_key(endpoint_id, cluster_id, attribute_id, attribute_key);
ESP_LOGD(TAG, "read attribute from nvs: endpoint_id-0x%" PRIx16 ", cluster_id-0x%" PRIx32 ","
" attribute_id-0x%" PRIx32 "", endpoint_id, cluster_id, attribute_id);
esp_err_t err = nvs_get_val(ESP_MATTER_KVS_NAMESPACE, attribute_key, val);
if (err == ESP_ERR_NVS_NOT_FOUND) {
// If we don't find attribute key in the esp_matter_kvs namespace, we will try to get the attribute value
// with the previous key from the previous namespace.
char nvs_namespace[16] = {0};
char old_attribute_key[16] = {0};
snprintf(nvs_namespace, 16, "endpoint_%" PRIX16 "", endpoint_id); /* endpoint_id */
snprintf(old_attribute_key, 16, "%" PRIX32 ":%" PRIX32 "", cluster_id, attribute_id); /* cluster_id:attribute_id */
err = nvs_get_val(nvs_namespace, old_attribute_key, val);
if (err == ESP_OK) {
// If we get the attribute value with the previous key, we will erase it and store it in current namespace
// with the new attribute key.
if (nvs_erase_val(nvs_namespace, old_attribute_key) != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase old attribute key");
}
if (nvs_store_val(ESP_MATTER_KVS_NAMESPACE, attribute_key, val) != ESP_OK) {
ESP_LOGE(TAG, "Failed to store attribute_val with new attribute key");
}
}
}
return err;
}
esp_err_t store_val_in_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, const esp_matter_attr_val_t & val)
{
/* Get attribute key */
char attribute_key[16] = {0};
get_attribute_key(endpoint_id, cluster_id, attribute_id, attribute_key);
ESP_LOGD(TAG, "Store attribute in nvs: endpoint_id-0x%" PRIx16 ", cluster_id-0x%" PRIx32 ", attribute_id-0x%" PRIx32 "",
endpoint_id, cluster_id, attribute_id);
return nvs_store_val(ESP_MATTER_KVS_NAMESPACE, attribute_key, val);
}
esp_err_t erase_val_in_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id)
{
/* Get attribute key */
char attribute_key[16] = {0};
get_attribute_key(endpoint_id, cluster_id, attribute_id, attribute_key);
ESP_LOGD(TAG, "Erase attribute in nvs: endpoint_id-0x%" PRIx16 ", cluster_id-0x%" PRIx32 ", attribute_id-0x%" PRIx32 "",
endpoint_id, cluster_id, attribute_id);
return nvs_erase_val(ESP_MATTER_KVS_NAMESPACE, attribute_key);
}
} // namespace attribute
} // namespace esp_matter
+15 -4
View File
@@ -20,9 +20,10 @@
namespace esp_matter {
namespace attribute {
#define ESP_MATTER_KVS_NAMESPACE "esp_matter_kvs"
/**
* @brief Gets the attribute value from the NVS, it generates the namespace and key based on endpoint, cluster,
* and attribute id.
* @brief Gets the attribute value from the NVS, it generates the key based on endpoint, cluster, and attribute id.
*
* @param endpoint_id Endpoint Id
* @param cluster_id Cluster Id
@@ -33,8 +34,7 @@ namespace attribute {
esp_err_t get_val_from_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, esp_matter_attr_val_t & val);
/**
* @brief Stores the attribute value in NVS, it generates the namespace and key based on endpoint, cluster,
* and attribute id.
* @brief Stores the attribute value in NVS, it generates the key based on endpoint, cluster, and attribute id.
*
* @param endpoint_id Endpoint Id
* @param cluster_id Cluster Id
@@ -44,5 +44,16 @@ esp_err_t get_val_from_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t a
*/
esp_err_t store_val_in_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id, const esp_matter_attr_val_t & val);
/**
* @brief Erases the attribute value in NVS, it generates the key based on endpoint, cluster, and attribute id.
*
* @param endpoint_id Endpoint Id
* @param cluster_id Cluster Id
* @param attribute_id Attribute Id
*
* @return ESP_OK on success, appropriate error code otherwise
*/
esp_err_t erase_val_in_nvs(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id);
} // namespace attribute
} // namespace esp_matter
@@ -20,10 +20,8 @@
#include <esp_matter_bridge.h>
#include <esp_matter_mem.h>
#include <nvs_key_allocator.h>
#if MAX_BRIDGED_DEVICE_COUNT > 0
#define ESP_MATTER_BRIDGE_PESISTENT_INFO_KEY "persistent_info"
#define ESP_MATTER_BRIDGE_NAMESPACE "bridge"
#define ESP_MATTER_BRIDGE_ENDPOINT_ID_ARRAY_KEY "ep_id_array"
static const char *TAG = "esp_matter_bridge";
@@ -35,31 +33,7 @@ namespace esp_matter_bridge {
static uint16_t bridged_endpoint_id_array[MAX_BRIDGED_DEVICE_COUNT];
/** Persistent Bridged Device Info **/
static esp_err_t store_device_persistent_info(device_t *device)
{
esp_err_t err = ESP_OK;
if (!device) {
ESP_LOGE(TAG, "device cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
nvs_handle_t handle;
char namespace_name[16] = {0};
snprintf(namespace_name, 16, "bridge_ep_%X", device->persistent_info.device_endpoint_id);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, namespace_name, NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
namespace_name, err);
return err;
}
err = nvs_set_blob(handle, ESP_MATTER_BRIDGE_PESISTENT_INFO_KEY, &device->persistent_info,
sizeof(device_persistent_info_t));
nvs_commit(handle);
nvs_close(handle);
return err;
}
static esp_err_t read_device_persistent_info(device_persistent_info_t *persistent_info, uint16_t endpoint_id)
static esp_err_t store_device_persistent_info(device_persistent_info_t *persistent_info)
{
esp_err_t err = ESP_OK;
if (!persistent_info) {
@@ -68,19 +42,79 @@ static esp_err_t read_device_persistent_info(device_persistent_info_t *persisten
}
nvs_handle_t handle;
char namespace_name[16] = {0};
snprintf(namespace_name, 16, "bridge_ep_%X", endpoint_id);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, namespace_name, NVS_READONLY, &handle);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE, NVS_READWRITE,
&handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
namespace_name, err);
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
uint16_t endpoint_id = persistent_info->device_endpoint_id;
err = nvs_set_blob(handle, nvs_key_allocator::endpoint_pesistent_info(endpoint_id).KeyName(),
persistent_info, sizeof(device_persistent_info_t));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed on nvs_set_blob when storing device_persistent_info");
}
err = nvs_commit(handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed on nvs_commit when storing device_persistent_info");
}
nvs_close(handle);
return err;
}
static esp_err_t nvs_get_device_persistent_info(const char *nvs_namespace, const char *nvs_key,
device_persistent_info_t *persistent_info)
{
esp_err_t err = ESP_OK;
nvs_handle_t handle;
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, nvs_namespace, NVS_READONLY, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
nvs_namespace, err);
return err;
}
size_t len = sizeof(device_persistent_info_t);
err = nvs_get_blob(handle, ESP_MATTER_BRIDGE_PESISTENT_INFO_KEY, persistent_info, &len);
err = nvs_get_blob(handle, nvs_key, persistent_info, &len);
nvs_close(handle);
return err;
}
static esp_err_t read_device_persistent_info(device_persistent_info_t *persistent_info, uint16_t endpoint_id)
{
if (!persistent_info) {
ESP_LOGE(TAG, "persistent_info cannot be NULL");
return ESP_ERR_INVALID_ARG;
}
esp_err_t err = nvs_get_device_persistent_info(ESP_MATTER_BRIDGE_NAMESPACE,
nvs_key_allocator::endpoint_pesistent_info(endpoint_id).KeyName(),
persistent_info);
if (err == ESP_ERR_NVS_NOT_FOUND) {
// If we don't find persistent_info key in the bridge namespace, we will try to get the persistent_info
// with the previous key from the previous namespace.
char nvs_namespace[16] = {0};
snprintf(nvs_namespace, 16, "bridge_ep_%X", endpoint_id);
err = nvs_get_device_persistent_info(nvs_namespace, "persistent_info", persistent_info);
if (err == ESP_OK) {
nvs_handle_t handle;
// If we get the persistent_info with the previous key, we will erase it and store it in current namespace
// with the new persistent_info key.
if (nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, nvs_namespace, NVS_READWRITE,
&handle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to open %s namespace", nvs_namespace);
} else {
if (nvs_erase_key(handle, "persistent_info") != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase persistent_info");
} else {
nvs_commit(handle);
}
nvs_close(handle);
}
store_device_persistent_info(persistent_info);
}
}
return err;
}
static esp_err_t store_bridged_endpoint_ids()
{
@@ -93,27 +127,61 @@ static esp_err_t store_bridged_endpoint_ids()
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
err = nvs_set_blob(handle, ESP_MATTER_BRIDGE_ENDPOINT_ID_ARRAY_KEY, bridged_endpoint_id_array,
err = nvs_set_blob(handle, nvs_key_allocator::endpoint_ids_array().KeyName(), bridged_endpoint_id_array,
sizeof(bridged_endpoint_id_array));
nvs_commit(handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed on nvs_set_blob when storing bridged_endpoint_ids");
}
err = nvs_commit(handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Failed on nvs_commit when storing bridged_endpoint_ids");
}
nvs_close(handle);
return err;
}
static esp_err_t nvs_get_bridged_endpoint_ids(const char *nvs_namespace, const char *nvs_key)
{
esp_err_t err = ESP_OK;
nvs_handle_t handle;
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, nvs_namespace, NVS_READONLY, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
nvs_namespace, err);
return err;
}
size_t len = sizeof(bridged_endpoint_id_array);
err = nvs_get_blob(handle, nvs_key, bridged_endpoint_id_array, &len);
nvs_close(handle);
return err;
}
static esp_err_t read_bridged_endpoint_ids()
{
esp_err_t err = ESP_OK;
nvs_handle_t handle;
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE, NVS_READONLY,
&handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
esp_err_t err =
nvs_get_bridged_endpoint_ids(ESP_MATTER_BRIDGE_NAMESPACE, nvs_key_allocator::endpoint_ids_array().KeyName());
if (err == ESP_ERR_NVS_NOT_FOUND) {
err = nvs_get_bridged_endpoint_ids(ESP_MATTER_BRIDGE_NAMESPACE, "ep_id_array");
// If we don't find endpoint_ids_array in the bridge namespace, we will try to get the attribute value
// with the previous key from the previous namespace.
if (err == ESP_OK) {
// If we get endpoint_ids_array with the previous key, we will erase it and store it in current namespace
// with the new endpoint_ids_array key.
nvs_handle_t handle;
if (nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE,
NVS_READWRITE, &handle) != ESP_OK) {
ESP_LOGE(TAG, "Failed to open bridge namespace");
} else {
if (nvs_erase_key(handle, "ep_id_array") != ESP_OK) {
ESP_LOGE(TAG, "Failed to erase old key");
} else {
nvs_commit(handle);
}
nvs_close(handle);
}
store_bridged_endpoint_ids();
}
}
size_t len = sizeof(bridged_endpoint_id_array);
err = nvs_get_blob(handle, ESP_MATTER_BRIDGE_ENDPOINT_ID_ARRAY_KEY, bridged_endpoint_id_array, &len);
nvs_close(handle);
return err;
}
@@ -143,15 +211,15 @@ esp_err_t erase_bridged_device_info(uint16_t endpoint_id)
}
// Clear the persistent information of the removed endpoint
nvs_handle_t handle;
char namespace_name[16] = {0};
snprintf(namespace_name, 16, "bridge_ep_%X", endpoint_id);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, namespace_name, NVS_READWRITE, &handle);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE, NVS_READWRITE,
&handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
namespace_name, err);
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
err = nvs_erase_all(handle);
err = nvs_erase_key(handle, nvs_key_allocator::endpoint_pesistent_info(endpoint_id).KeyName());
nvs_commit(handle);
nvs_close(handle);
return err;
}
@@ -298,7 +366,7 @@ device_t *create_device(node_t *node, uint16_t parent_endpoint_id, uint32_t devi
// Store the persistent information
dev->persistent_info.device_endpoint_id = esp_matter::endpoint::get_id(dev->endpoint);
dev->persistent_info.device_type_id = device_type_id;
if (store_device_persistent_info(dev) != ESP_OK) {
if (store_device_persistent_info(&dev->persistent_info) != ESP_OK) {
ESP_LOGE(TAG, "Failed to store the persistent info for the bridged device");
remove_device(dev);
return NULL;
@@ -405,20 +473,22 @@ esp_err_t initialize(node_t *node)
return err;
}
// TODO: Add a factory_reset_cb_register so that when we call esp_matter::factory_reset, we can erase other namespaces/partitions.
// TODO: Add a factory_reset_cb_register so that when we call esp_matter::factory_reset, we can erase other
// namespaces/partitions.
esp_err_t factory_reset()
{
if (read_bridged_endpoint_ids() != ESP_OK) {
ESP_LOGE(TAG, "Failed to read the endpoint id array");
nvs_handle_t handle;
esp_err_t err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE,
NVS_READWRITE, &handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
for (size_t idx = 0; idx < MAX_BRIDGED_DEVICE_COUNT; ++idx) {
if (bridged_endpoint_id_array[idx] != chip::kInvalidEndpointId) {
erase_bridged_device_info(bridged_endpoint_id_array[idx]);
bridged_endpoint_id_array[idx] = chip::kInvalidEndpointId;
}
}
return store_bridged_endpoint_ids();
err = nvs_erase_all(handle);
nvs_commit(handle);
nvs_close(handle);
return err;
}
} // namespace esp_matter_bridge
@@ -40,7 +40,8 @@ esp_err_t get_bridged_endpoint_ids(uint16_t *matter_endpoint_id_array);
esp_err_t erase_bridged_device_info(uint16_t matter_endpoint_id);
device_t *create_device(esp_matter::node_t *node, uint16_t parent_endpoint_id, uint32_t device_type_id, void *priv_data);
device_t *create_device(esp_matter::node_t *node, uint16_t parent_endpoint_id, uint32_t device_type_id,
void *priv_data);
device_t *resume_device(esp_matter::node_t *node, uint16_t device_endpoint_id, void *priv_data);
@@ -0,0 +1,38 @@
// Copyright 2023 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 <lib/support/DefaultStorageKeyAllocator.h>
#define ESP_MATTER_BRIDGE_NAMESPACE "bridge"
using chip::StorageKeyName;
namespace esp_matter_bridge {
namespace nvs_key_allocator {
inline StorageKeyName endpoint_ids_array()
{
return StorageKeyName::FromConst("b/epida");
}
inline StorageKeyName endpoint_pesistent_info(uint16_t endpoint_id)
{
return StorageKeyName::Formatted("b/%x/pi", endpoint_id);
}
} // namespace nvs_key_allocator
} // namespace esp_matter_bridge
@@ -19,11 +19,25 @@
#include <app_bridged_device.h>
#include <esp_matter_mem.h>
#include <nvs_key_allocator.h>
// The bridge app can be used only when MAX_BRIDGED_DEVICE_COUNT > 0
#if defined(MAX_BRIDGED_DEVICE_COUNT) && MAX_BRIDGED_DEVICE_COUNT > 0
#define APP_BRIDGE_BRIDGED_DEVICE_ADDR_KEY "dev_addr"
#define APP_BRIDGE_BRIDGED_DEVICE_TYPE_KEY "dev_type"
namespace esp_matter_bridge {
namespace nvs_key_allocator {
static inline StorageKeyName endpoint_dev_addr(uint16_t endpoint_id)
{
return StorageKeyName::Formatted("b/%x/da", endpoint_id);
}
static inline StorageKeyName endpoint_dev_type(uint16_t endpoint_id)
{
return StorageKeyName::Formatted("b/%x/dt", endpoint_id);
}
} // namespace nvs_key_allocator
} // namespace esp_matter_bridge
using namespace esp_matter;
@@ -41,21 +55,21 @@ static esp_err_t app_bridge_store_bridged_device_info(app_bridged_device_t *brid
return ESP_ERR_INVALID_ARG;
}
nvs_handle_t handle;
char namespace_name[16] = {0};
snprintf(namespace_name, 16, "bridge_ep_%X", bridged_device->dev->persistent_info.device_endpoint_id);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, namespace_name, NVS_READWRITE, &handle);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE, NVS_READWRITE,
&handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
namespace_name, err);
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
err = nvs_set_blob(handle, APP_BRIDGE_BRIDGED_DEVICE_ADDR_KEY, &bridged_device->dev_addr,
sizeof(app_bridged_device_address_t));
uint16_t endpoint_id = endpoint::get_id(bridged_device->dev->endpoint);
err = nvs_set_blob(handle, esp_matter_bridge::nvs_key_allocator::endpoint_dev_addr(endpoint_id).KeyName(),
&bridged_device->dev_addr, sizeof(app_bridged_device_address_t));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error storing the device address");
}
err = nvs_set_blob(handle, APP_BRIDGE_BRIDGED_DEVICE_TYPE_KEY, &bridged_device->dev_type,
sizeof(app_bridged_device_type_t));
err = nvs_set_blob(handle, esp_matter_bridge::nvs_key_allocator::endpoint_dev_type(endpoint_id).KeyName(),
&bridged_device->dev_type, sizeof(app_bridged_device_type_t));
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error storing the device type");
}
@@ -74,21 +88,22 @@ static esp_err_t app_bridge_read_bridged_device_info(app_bridged_device_type_t *
return ESP_ERR_INVALID_ARG;
}
nvs_handle_t handle;
char namespace_name[16] = {0};
snprintf(namespace_name, 16, "bridge_ep_%X", matter_endpoint_id);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, namespace_name, NVS_READONLY, &handle);
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE, NVS_READONLY,
&handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
namespace_name, err);
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
size_t len = sizeof(app_bridged_device_address_t);
err = nvs_get_blob(handle, APP_BRIDGE_BRIDGED_DEVICE_ADDR_KEY, device_addr, &len);
err = nvs_get_blob(handle, esp_matter_bridge::nvs_key_allocator::endpoint_dev_addr(matter_endpoint_id).KeyName(),
device_addr, &len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error reading the device address");
}
len = sizeof(app_bridged_device_type_t);
err = nvs_get_blob(handle, APP_BRIDGE_BRIDGED_DEVICE_TYPE_KEY, device_type, &len);
err = nvs_get_blob(handle, esp_matter_bridge::nvs_key_allocator::endpoint_dev_type(matter_endpoint_id).KeyName(),
device_type, &len);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error reading the device type");
}
@@ -96,6 +111,30 @@ static esp_err_t app_bridge_read_bridged_device_info(app_bridged_device_type_t *
return err;
}
static esp_err_t app_bridge_erase_bridged_device_info(uint16_t endpoint_id)
{
esp_err_t err = ESP_OK;
nvs_handle_t handle;
err = nvs_open_from_partition(CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME, ESP_MATTER_BRIDGE_NAMESPACE, NVS_READWRITE,
&handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error opening partition %s namespace %s. Err: %d", CONFIG_ESP_MATTER_BRIDGE_INFO_PART_NAME,
ESP_MATTER_BRIDGE_NAMESPACE, err);
return err;
}
err = nvs_erase_key(handle, esp_matter_bridge::nvs_key_allocator::endpoint_dev_addr(endpoint_id).KeyName());
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error erasing the device address");
}
err = nvs_erase_key(handle, esp_matter_bridge::nvs_key_allocator::endpoint_dev_type(endpoint_id).KeyName());
if (err != ESP_OK) {
ESP_LOGE(TAG, "Error erasing the device type");
}
nvs_commit(handle);
nvs_close(handle);
return err;
}
/** Bridged Device's Address APIs */
app_bridged_device_address_t app_bridge_zigbee_address(uint8_t zigbee_endpointid, uint16_t zigbee_shortaddr)
{
@@ -181,7 +220,8 @@ esp_err_t app_bridge_initialize(node_t *node)
matter_endpoint_id_array[idx]);
continue;
}
app_bridged_device_t *new_dev = (app_bridged_device_t *)esp_matter_mem_calloc(1, sizeof(app_bridged_device_t));
app_bridged_device_t *new_dev =
(app_bridged_device_t *)esp_matter_mem_calloc(1, sizeof(app_bridged_device_t));
if (!new_dev) {
ESP_LOGE(TAG, "Failed to alloc memory for the resumed bridged device");
continue;
@@ -198,7 +238,7 @@ esp_err_t app_bridge_initialize(node_t *node)
g_bridged_device_list = new_dev;
g_current_bridged_device_count++;
//Enable the resumed endpoint
// Enable the resumed endpoint
esp_matter::endpoint::enable(new_dev->dev->endpoint);
}
}
@@ -230,6 +270,9 @@ esp_err_t app_bridge_remove_device(app_bridged_device_t *bridged_device)
}
}
uint16_t endpoint_id = endpoint::get_id(bridged_device->dev->endpoint);
app_bridge_erase_bridged_device_info(endpoint_id);
// Remove the bridged device from the node.
error = esp_matter_bridge::remove_device(bridged_device->dev);
if (error != ESP_OK) {
@@ -325,9 +368,8 @@ app_bridged_device_t *app_bridge_get_device_by_espnow_macaddr(uint8_t espnow_mac
{
app_bridged_device_t *current_dev = g_bridged_device_list;
while (current_dev) {
if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ESPNOW) && current_dev->dev
&& !memcmp(current_dev->dev_addr.espnow_macaddr, espnow_macaddr, 6)
) {
if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ESPNOW) && current_dev->dev &&
!memcmp(current_dev->dev_addr.espnow_macaddr, espnow_macaddr, 6)) {
return current_dev;
}
current_dev = current_dev->next;
@@ -339,9 +381,8 @@ uint16_t app_bridge_get_matter_endpointid_by_espnow_macaddr(uint8_t espnow_macad
{
app_bridged_device_t *current_dev = g_bridged_device_list;
while (current_dev) {
if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ESPNOW) && current_dev->dev
&& !memcmp(current_dev->dev_addr.espnow_macaddr, espnow_macaddr, 6)
) {
if ((current_dev->dev_type == ESP_MATTER_BRIDGED_DEVICE_TYPE_ESPNOW) && current_dev->dev &&
!memcmp(current_dev->dev_addr.espnow_macaddr, espnow_macaddr, 6)) {
return esp_matter::endpoint::get_id(current_dev->dev->endpoint);
}
current_dev = current_dev->next;
@@ -349,7 +390,7 @@ uint16_t app_bridge_get_matter_endpointid_by_espnow_macaddr(uint8_t espnow_macad
return chip::kInvalidEndpointId;
}
uint8_t* app_bridge_get_espnow_macaddr_by_matter_endpointid(uint16_t matter_endpointid)
uint8_t *app_bridge_get_espnow_macaddr_by_matter_endpointid(uint16_t matter_endpointid)
{
app_bridged_device_t *current_dev = g_bridged_device_list;
while (current_dev) {