In this post, I look at adding “Delete” behaviour to my Matter Controller. This will allow me to cleanly remove nodes from my Matter fabric.
This follows on from these previous posts on the subject
- Building a new heating monitor using Matter and ESP32
- Matter Heating Monitor – showing commissioned Nodes
The Unpair Operation
To get started, I added a Remove Node button to the Device details page. This page is empty at present, showing only the NodeId.

Wired to this button was a call to the /nodes/ endpoint, using the DELETE verb. The handler for this was defined in the Web Server.
const httpd_uri_t node_delete_uri = {
.uri = "/nodes/*",
.method = HTTP_DELETE,
.handler = node_delete_handler,
.user_ctx = NULL};
The node_delete_handler function looked like this
static esp_err_t node_delete_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "Unpairing node...");
size_t size = strlen(req->uri);
char *pch = strrchr(req->uri, '/');
int index_of_last_slash = pch - req->uri + 1;
int length_of_nodeId = size - index_of_last_slash;
char node_id_str[length_of_nodeId + 1];
memcpy(node_id_str, &req->uri[index_of_last_slash], length_of_nodeId);
node_id_str[length_of_nodeId] = '\0';
ESP_LOGI(TAG, "Unpairing node %s", node_id_str);
uint64_t node_id = strtoull(node_id_str, NULL, 10);
lock::chip_stack_lock(portMAX_DELAY);
esp_err_t err = esp_matter::controller::unpair_device(node_id); //, on_unpair_callback);
lock::chip_stack_unlock();
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Unpairing failed");
httpd_resp_set_status(req, "500 Internal Server Error");
}
else
{
httpd_resp_set_type(req, "application/json");
httpd_resp_set_status(req, "202 Accepted");
}
return ESP_OK;
}
The main challenge was extracting the node id from the URL and converting it into a uint64_t. This was accomplished with some splitting and the use of strtoull.
I then called the unpair_device function on the controller. This is wrapped in a chip_stack_lock to prevent any concurrency issues.
Removing my record of the node
Whist the unpair_device function will remove the node from my controller’s fabric, it doesn’t remove from my keystore. This means the node will still appear on my Devices page.
The challenge here is that unpair_device doesn’t offer a callback to tell me when the unpair operation is done. This is different to the commissioning methods, which do. Unfortunately, this was a bit of a deal breaker for me.
So I wasn’t blocked, I just assumed the unpair operation would work and removed the node’s key from the NVS.
char nodeIdStr[32];
snprintf(nodeIdStr, sizeof(nodeIdStr), "%" PRIu64, node_id);
nvs_handle_t nvs_handle;
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs_handle);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to open NVS node!");
return;
}
err = nvs_erase_key(nvs_handle, nodeIdStr);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to erase node!");
return;
}
err = nvs_commit(nvs_handle);
I raised an issue and pull request against esp-matter to try and introduce a callback. Let’s see if that gets approved.
Next Steps
My controller could now add and delete nodes.
Next up was reading the device types from the commissioned nodes. This would help me to identify the Temperature Sensors and to read the values from each!
Stay tuned!
Code
All the code is available at
https://github.com/tomasmcguinness/matter-esp32-heating-monitor
Support
If you found this blog post useful and want to support my efforts, you can buy me a coffee. Better yet, why not subscribe to my Patreon so I can continue making these posts. Thanks!!





Leave a comment