Merge branch 'fix_endpoint_enable_v1_5' into 'release/v1.5'

components/esp_matter: call init function and report attribute change (v1.5)

See merge request app-frameworks/esp-matter!1430
This commit is contained in:
Shu Chen
2026-03-12 09:15:42 +00:00
3 changed files with 97 additions and 27 deletions
@@ -212,11 +212,27 @@ esp_err_t read_min_unused_endpoint_id()
namespace endpoint {
static void report_parts_list_change_internal(endpoint_t *endpoint)
{
chip::EndpointId parent_endpoint_id = endpoint::get_parent_endpoint_id(endpoint);
while (parent_endpoint_id != chip::kInvalidEndpointId) {
MatterReportingAttributeChangeCallback(parent_endpoint_id, chip::app::Clusters::Descriptor::Id,
chip::app::Clusters::Descriptor::Attributes::PartsList::Id);
parent_endpoint_id = endpoint::get_parent_endpoint_id(endpoint::get(parent_endpoint_id));
}
MatterReportingAttributeChangeCallback(/* endpoint = */ 0, chip::app::Clusters::Descriptor::Id,
chip::app::Clusters::Descriptor::Attributes::PartsList::Id);
}
esp_err_t disable(endpoint_t *endpoint)
{
VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL"));
_endpoint_t *current_endpoint = (_endpoint_t *)endpoint;
current_endpoint->enabled = false;
{
esp_matter::lock::ScopedChipStackLock lock(portMAX_DELAY);
report_parts_list_change_internal(endpoint);
}
return ESP_OK;
}
@@ -240,12 +256,62 @@ static esp_err_t init_identification(endpoint_t *endpoint)
return ESP_OK;
}
static void invoke_init_callbacks_internal(endpoint_t *endpoint)
{
cluster_t *cluster = cluster::get_first(endpoint);
while (cluster) {
/* Delegate server init callback */
cluster::delegate_init_callback_t delegate_init_callback = cluster::get_delegate_init_callback(cluster);
if (delegate_init_callback) {
delegate_init_callback(cluster::get_delegate_impl(cluster), endpoint::get_id(endpoint));
}
/* Add bounds callback */
cluster::add_bounds_callback_t add_bounds_callback = cluster::get_add_bounds_callback(cluster);
if (add_bounds_callback) {
add_bounds_callback(cluster);
}
/* Plugin server init callback */
cluster::plugin_server_init_callback_t plugin_server_init_callback =
cluster::get_plugin_server_init_callback(cluster);
if (plugin_server_init_callback) {
plugin_server_init_callback();
}
/* Initialization callback */
uint8_t flags = cluster::get_flags(cluster);
cluster::initialization_callback_t init_callback = cluster::get_init_callback(cluster);
if (init_callback) {
init_callback(endpoint::get_id(endpoint));
}
/* Init function */
if ((flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_INIT_FUNCTION)) {
cluster::function_cluster_init_t init_function =
(cluster::function_cluster_init_t)cluster::get_function(cluster, CLUSTER_FLAG_INIT_FUNCTION);
if (init_function) {
init_function(endpoint::get_id(endpoint));
}
}
cluster = cluster::get_next(cluster);
}
}
esp_err_t enable(endpoint_t *endpoint)
{
VerifyOrReturnError(endpoint, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Endpoint cannot be NULL"));
_endpoint_t *current_endpoint = (_endpoint_t *)endpoint;
current_endpoint->enabled = true;
init_identification(endpoint);
{
// Use the lock instead of schedule lambda to ensure the callbacks are invoked before esp_matter::start() returns.
esp_matter::lock::ScopedChipStackLock lock(portMAX_DELAY);
invoke_init_callbacks_internal(endpoint);
// Mark the endpoint as dirty so that the data model provider will report the attribute changes.
MatterReportingAttributeChangeCallback(endpoint::get_id(endpoint));
report_parts_list_change_internal(endpoint);
}
return ESP_OK;
}
@@ -1660,6 +1726,30 @@ esp_err_t destroy(node_t *node, endpoint_t *endpoint)
}
VerifyOrReturnError(current_endpoint != NULL, ESP_FAIL, ESP_LOGE(TAG, "Could not find the endpoint to delete"));
{
esp_matter::lock::ScopedChipStackLock lock(portMAX_DELAY);
cluster_t *cluster = cluster::get_first(endpoint);
while (cluster) {
/* Shutdown callback */
cluster::shutdown_callback_t shutdown_callback = cluster::get_shutdown_callback(cluster);
if (shutdown_callback) {
shutdown_callback(endpoint::get_id(endpoint));
}
cluster = cluster::get_next(cluster);
/* Shutdown function */
uint8_t flags = cluster::get_flags(cluster);
if ((flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_SHUTDOWN_FUNCTION)) {
cluster::function_cluster_shutdown_t shutdown_function =
(cluster::function_cluster_shutdown_t)cluster::get_function(cluster, CLUSTER_FLAG_SHUTDOWN_FUNCTION);
if (shutdown_function) {
shutdown_function(endpoint::get_id(endpoint));
}
}
cluster = cluster::get_next(cluster);
}
}
/* Parse and delete all clusters */
_cluster_t *cluster = current_endpoint->cluster_list;
while (cluster) {
@@ -235,28 +235,6 @@ CHIP_ERROR provider::Startup(InteractionModelContext context)
{
ReturnErrorOnFailure(DataModel::Provider::Startup(context));
mContext.emplace(context);
esp_matter::cluster::add_bounds_callback_common();
esp_matter::cluster::plugin_init_callback_common();
endpoint_t *ep = endpoint::get_first(node::get());
while (ep) {
cluster_t *cluster = cluster::get_first(ep);
while (cluster) {
uint8_t flags = cluster::get_flags(cluster);
cluster::initialization_callback_t init_callback = cluster::get_init_callback(cluster);
if (init_callback) {
init_callback(endpoint::get_id(ep));
}
if ((flags & CLUSTER_FLAG_SERVER) && (flags & CLUSTER_FLAG_INIT_FUNCTION)) {
cluster::function_cluster_init_t init_function =
(cluster::function_cluster_init_t)cluster::get_function(cluster, CLUSTER_FLAG_INIT_FUNCTION);
if (init_function) {
init_function(endpoint::get_id(ep));
}
}
cluster = cluster::get_next(cluster);
}
ep = endpoint::get_next(ep);
}
if (GetAttributePersistenceProvider() == nullptr) {
gDefaultAttributePersistence.Init(&Server::GetInstance().GetPersistentStorage());
SetAttributePersistenceProvider(&gDefaultAttributePersistence);
@@ -605,9 +583,13 @@ CHIP_ERROR provider::Attributes(const ConcreteClusterPath &path, ReadOnlyBufferB
void provider::Temporary_ReportAttributeChanged(const AttributePathParams &path)
{
cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId);
VerifyOrReturn(cluster != nullptr);
VerifyOrReturn(cluster::increase_data_version(cluster) == ESP_OK);
VerifyOrReturn(!path.HasWildcardEndpointId());
// If the cluster is not wildcard, increase the data version
if (!path.HasWildcardClusterId()) {
cluster_t *cluster = cluster::get(path.mEndpointId, path.mClusterId);
VerifyOrReturn(cluster != nullptr);
VerifyOrReturn(cluster::increase_data_version(cluster) == ESP_OK);
}
mContext->dataModelChangeListener.MarkDirty(path);
}
@@ -225,8 +225,6 @@ static void esp_matter_chip_init_task(intptr_t context)
if (endpoint::enable_all() != ESP_OK) {
ESP_LOGE(TAG, "Enable all endpoints failure");
}
// Initialise clusters which have delegate implemented
esp_matter::cluster::delegate_init_callback_common();
#endif // CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
#if CHIP_CONFIG_ENABLE_ICD_SERVER
if (!icd::get_icd_server_enabled()) {