// Copyright 2021 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_attribute_impl.h"
#include "esp_matter_command_impl.h"
#include <esp_log.h>
#include <esp_matter.h>
#include <esp_matter_feature_impl.h>
#include <esp_matter_data_model_priv.h>

#include <app-common/zap-generated/cluster-enums.h>

static const char *TAG = "esp_matter_feature";

using namespace chip::app::Clusters;

namespace esp_matter {
namespace cluster {

static esp_err_t update_feature_map(cluster_t *cluster, uint32_t value)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));

    /* Get the attribute */
    attribute_t *attribute = attribute::get(cluster, Globals::Attributes::FeatureMap::Id);

    VerifyOrReturnError(attribute, ESP_ERR_INVALID_STATE, ESP_LOGE(TAG, "Feature map attribute cannot be null"));

    /* Update the value if the attribute already exists */
    esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    VerifyOrReturnError(attribute::get_val_internal(attribute, &val) == ESP_OK, ESP_FAIL);
    val.val.u32 |= value;
    /* Here we can't call attribute::update() since the chip stack would not have started yet, since we are
    still creating the data model. So, we are directly using attribute::set_val_internal(). */
    return attribute::set_val_internal(attribute, &val, false);
}

static uint32_t get_feature_map_value(cluster_t *cluster)
{
    esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    attribute_t *attribute = attribute::get(cluster, Globals::Attributes::FeatureMap::Id);

    VerifyOrReturnValue(attribute, 0, ESP_LOGE(TAG, "Feature map attribute cannot be null"));

    VerifyOrReturnValue(attribute::get_val_internal(attribute, &val) == ESP_OK, 0);
    return val.val.u32;
}

namespace descriptor {
namespace feature {
namespace tag_list {

uint32_t get_id()
{
    return (uint32_t)Descriptor::Feature::kTagList;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_tag_list(cluster, NULL, 0, 0);

    return ESP_OK;
}

} /* tag_list */

}
}

namespace access_control {
namespace feature {
namespace extension {

uint32_t get_id()
{
    return (uint32_t)AccessControl::Feature::kExtension;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_extension(cluster, NULL, 0, 0);

    event::create_access_control_extension_changed(cluster);

    return ESP_OK;
}
} /* extension */

namespace managed_device {

uint32_t get_id()
{
    return (uint32_t)AccessControl::Feature::kManagedDevice;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
    /* Attributes managed internally */
    attribute::create_commissioning_arl(cluster, NULL, 0, 0);
    attribute::create_arl(cluster, NULL, 0, 0);
#endif

    command::create_review_fabric_restrictions(cluster);
    command::create_review_fabric_restrictions_response(cluster);

    event::create_fabric_restriction_review_update(cluster);

    return ESP_OK;
}
} /* managed_device */

}
} /* access_control */

namespace bridged_device_basic_information {
namespace feature {
namespace bridged_icd_support {

uint32_t get_id()
{
    return (uint32_t)BridgedDeviceBasicInformation::Feature::kBridgedICDSupport;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    command::create_keep_active(cluster);
    event::create_active_changed(cluster);

    return ESP_OK;
}

} /* bridged_icd_support */

} /* feature */
} /* bridged_device_basic_information */

namespace administrator_commissioning {
namespace feature {
namespace basic {

uint32_t get_id()
{
    return (uint32_t)AdministratorCommissioning::Feature::kBasic;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    command::create_open_basic_commissioning_window(cluster);

    return ESP_OK;
}
} /* basic */

}
} /* administrator_commissioning */

namespace general_commissioning {
namespace feature {
namespace terms_and_conditions {

uint32_t get_id()
{
    return (uint32_t)GeneralCommissioning::Feature::kTermsAndConditions;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_tc_accepted_version(cluster, 0);
    attribute::create_tc_min_required_version(cluster, 0);
    attribute::create_tc_acknowledgements(cluster, 0);
    attribute::create_tc_acknowledgements_required(cluster, true);
    attribute::create_tc_update_deadline(cluster, 0);

    command::create_set_tc_acknowledgements(cluster);
    command::create_set_tc_acknowledgements_response(cluster);
    return ESP_OK;
}
} /* terms_and_conditions */

}
} /* general_commissioning */

namespace power_source {
namespace feature {
namespace wired {

uint32_t get_id()
{
    return (uint32_t)PowerSource::Feature::kWired;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t battery_feature_map = feature::battery::get_id();
    if ((get_feature_map_value(cluster) & battery_feature_map) == battery_feature_map) {
        ESP_LOGE(TAG, "Cluster already supports Battery feature");
        return ESP_ERR_NOT_SUPPORTED;
    }
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_wired_current_type(cluster, config->wired_current_type);

    return ESP_OK;
}

} /* wired */

namespace battery {

uint32_t get_id()
{
    return (uint32_t)PowerSource::Feature::kBattery;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t wired_feature_map = feature::wired::get_id();
    if ((get_feature_map_value(cluster) & wired_feature_map) == wired_feature_map) {
        ESP_LOGE(TAG, "Cluster already supports Wired feature");
        return ESP_ERR_NOT_SUPPORTED;
    }
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_bat_charge_level(cluster, config->bat_charge_level);
    attribute::create_bat_replacement_needed(cluster, config->bat_replacement_needed);
    attribute::create_bat_replaceability(cluster, config->bat_replaceability);

    return ESP_OK;
}

} /* battery */

namespace rechargeable {

uint32_t get_id()
{
    return (uint32_t)PowerSource::Feature::kRechargeable;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t battery_feature_map = feature::battery::get_id();
    if ((get_feature_map_value(cluster) & battery_feature_map) == battery_feature_map) {

        update_feature_map(cluster, get_id());

        /* Attributes not managed internally */
        attribute::create_bat_charge_state(cluster, config->bat_charge_state);
        attribute::create_bat_functional_while_charging(cluster, config->bat_functional_while_charging);
    } else {
        ESP_LOGE(TAG, "Cluster shall support Battery feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}

} /* rechargeable */

namespace replaceable {

uint32_t get_id()
{
    return (uint32_t)PowerSource::Feature::kReplaceable;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t battery_feature_map = feature::battery::get_id();
    if ((get_feature_map_value(cluster) & battery_feature_map) == battery_feature_map) {

        update_feature_map(cluster, get_id());

        /* Attributes not managed internally */
        attribute::create_bat_replacement_description(cluster, config->bat_replacement_description, strlen(config->bat_replacement_description));
        attribute::create_bat_quantity(cluster, config->bat_quantity, 0, 255);
    } else {
        ESP_LOGE(TAG, "Cluster shall support Battery feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}

} /* replaceable */
} /* feature */
} /* power_source */

namespace scenes_management {
namespace feature {
namespace scene_names {

uint32_t get_id()
{
    return (uint32_t)ScenesManagement::Feature::kSceneNames;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* scene_names */
} /* feature */
} /* scenes_management */

namespace icd_management {
namespace feature {
namespace check_in_protocol_support {

uint32_t get_id()
{
    return (uint32_t)IcdManagement::Feature::kCheckInProtocolSupport;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t long_idle_time_support_feature_map = feature::long_idle_time_support::get_id();
    VerifyOrReturnError((get_feature_map_value(cluster) & long_idle_time_support_feature_map) == long_idle_time_support_feature_map, ESP_ERR_INVALID_STATE, ESP_LOGE(TAG, "Long Idle Time Support feature should be added to this cluster"));

    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_registered_clients(cluster, NULL, 0, 0);
    attribute::create_icd_counter(cluster, 0);
    attribute::create_clients_supported_per_fabric(cluster, 0);
    attribute::create_maximum_check_in_backoff(cluster, 0);

    /* Commands */
    command::create_register_client(cluster);
    command::create_register_client_response(cluster);
    command::create_unregister_client(cluster);

    return ESP_OK;
}

} /* check_in_protocol_support */

namespace user_active_mode_trigger {

uint32_t get_id()
{
    return (uint32_t)IcdManagement::Feature::kUserActiveModeTrigger;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError((cluster && config), ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster and config cannot be NULL"));
    uint32_t long_idle_time_support_feature_map = feature::long_idle_time_support::get_id();
    VerifyOrReturnError((get_feature_map_value(cluster) & long_idle_time_support_feature_map) == long_idle_time_support_feature_map, ESP_ERR_INVALID_STATE, ESP_LOGE(TAG, "Long Idle Time Support feature should be added to this cluster"));

    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_user_active_mode_trigger_hint(cluster, config->user_active_mode_trigger_hint);
    attribute::create_user_active_mode_trigger_instruction(cluster, config->user_active_mode_trigger_instruction,
                                                           strlen(config->user_active_mode_trigger_instruction));

    return ESP_OK;
}

} /* user_active_mode_trigger */

namespace long_idle_time_support {

uint32_t get_id()
{
    return (uint32_t)IcdManagement::Feature::kLongIdleTimeSupport;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_operating_mode(cluster, 0);

    /* commands */
    command::create_stay_active_request(cluster);
    command::create_stay_active_response(cluster);
    return ESP_OK;
}

} /* long_idle_time_support */

namespace dynamic_sit_lit_support {

uint32_t get_id()
{
    return (uint32_t)IcdManagement::Feature::kDynamicSitLitSupport;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* dynamic_sit_lit_support */
} /* feature */
} /* icd_management */

namespace on_off {
namespace feature {
namespace lighting {

uint32_t get_id()
{
    return (uint32_t)OnOff::Feature::kLighting;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_global_scene_control(cluster, config->global_scene_control);
    attribute::create_on_time(cluster, config->on_time);
    attribute::create_off_wait_time(cluster, config->off_wait_time);
    attribute::create_start_up_on_off(cluster, config->start_up_on_off);

    /* Commands */
    command::create_off_with_effect(cluster);
    command::create_on_with_recall_global_scene(cluster);
    command::create_on_with_timed_off(cluster);

    return ESP_OK;
}

} /* lighting */

namespace dead_front_behavior {

uint32_t get_id()
{
    return (uint32_t)OnOff::Feature::kDeadFrontBehavior;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* dead_front_behavior */

namespace off_only {

uint32_t get_id()
{
    return (uint32_t)OnOff::Feature::kOffOnly;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    command_t *on_command = esp_matter::command::get(cluster, OnOff::Commands::On::Id, COMMAND_FLAG_ACCEPTED);
    if (on_command) {
        esp_matter::command::destroy(cluster, on_command);
    }
    command_t *toggle_command = esp_matter::command::get(cluster, OnOff::Commands::Toggle::Id, COMMAND_FLAG_ACCEPTED);
    if (toggle_command) {
        esp_matter::command::destroy(cluster, toggle_command);
    }

    return ESP_OK;
}

} /* off_only */
} /* feature */
} /* on_off */

namespace level_control {
namespace feature {
namespace on_off {

uint32_t get_id()
{
    return (uint32_t)LevelControl::Feature::kOnOff;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* on_off */

namespace lighting {

uint32_t get_id()
{
    return (uint32_t)LevelControl::Feature::kLighting;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_remaining_time(cluster, config->remaining_time);
    attribute::create_start_up_current_level(cluster, config->start_up_current_level);

    return ESP_OK;
}

} /* lighting */

namespace frequency {

uint32_t get_id()
{
    return (uint32_t)LevelControl::Feature::kFrequency;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_current_frequency(cluster, config->current_frequency);
    attribute::create_min_frequency(cluster, config->min_frequency);
    attribute::create_max_frequency(cluster, config->max_frequency);

    /* Commands */
    command::create_move_to_closest_frequency(cluster);

    return ESP_OK;
}
} /* frequency */
} /* feature */
} /* level_control */

namespace color_control {
namespace feature {

static esp_err_t update_color_capability(cluster_t *cluster, uint16_t value)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));

    /* Get the attribute */
    attribute_t *attribute = esp_matter::attribute::get(cluster, ColorControl::Attributes::ColorCapabilities::Id);

    /* Print error log if it does not exist */
    VerifyOrReturnError(attribute, ESP_FAIL, ESP_LOGE(TAG, "The color capability attribute is NULL"));

    /* Update the value if the attribute already exists */
    esp_matter_attr_val_t val = esp_matter_invalid(NULL);
    VerifyOrReturnError(esp_matter::attribute::get_val_internal(attribute, &val) == ESP_OK, ESP_FAIL);
    val.val.u16 |= value;
    /* Here we can't call attribute::update() since the chip stack would not have started yet, since we are
    still creating the data model. So, we are directly using attribute::set_val_internal(). */
    return esp_matter::attribute::set_val_internal(attribute, &val, false);
}

namespace hue_saturation {

uint32_t get_id()
{
    return (uint32_t)ColorControl::ColorCapabilitiesBitmap::kHueSaturation;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    update_color_capability(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_current_hue(cluster, config->current_hue);
    attribute::create_current_saturation(cluster, config->current_saturation);

    /* Commands */
    command::create_move_to_hue(cluster);
    command::create_move_hue(cluster);
    command::create_step_hue(cluster);
    command::create_move_to_saturation(cluster);
    command::create_move_saturation(cluster);
    command::create_step_saturation(cluster);
    command::create_move_to_hue_and_saturation(cluster);

    return ESP_OK;
}

} /* hue_saturation */

namespace color_temperature {

uint32_t get_id()
{
    return (uint32_t)ColorControl::ColorCapabilitiesBitmap::kColorTemperature;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    update_color_capability(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_color_temperature_mireds(cluster, config->color_temperature_mireds);
    attribute::create_color_temp_physical_min_mireds(cluster, config->color_temp_physical_min_mireds);
    attribute::create_color_temp_physical_max_mireds(cluster, config->color_temp_physical_max_mireds);
    attribute::create_couple_color_temp_to_level_min_mireds(cluster, config->couple_color_temp_to_level_min_mireds);
    attribute::create_start_up_color_temperature_mireds(cluster, config->start_up_color_temperature_mireds);

    /* Commands */
    command::create_move_to_color_temperature(cluster);
    command::create_move_color_temperature(cluster);
    command::create_step_color_temperature(cluster);

    return ESP_OK;
}

} /* color_temperature */

namespace xy {

uint32_t get_id()
{
    return (uint32_t)ColorControl::ColorCapabilitiesBitmap::kXy;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    update_color_capability(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_current_x(cluster, config->current_x);
    attribute::create_current_y(cluster, config->current_y);

    /* Commands */
    command::create_move_to_color(cluster);
    command::create_move_color(cluster);
    command::create_step_color(cluster);

    return ESP_OK;
}

} /* xy */

namespace enhanced_hue {

uint32_t get_id()
{
    return (uint32_t)chip::app::Clusters::ColorControl::ColorCapabilitiesBitmap::kEnhancedHue;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t hs_feature_map = feature::hue_saturation::get_id();
    if ((get_feature_map_value(cluster) & hs_feature_map) == hs_feature_map) {
        update_feature_map(cluster, get_id());
        update_color_capability(cluster, get_id());

        /* Attributes not managed internally */
        attribute::create_enhanced_current_hue(cluster, config->enhanced_current_hue);

        /* Commands */
        command::create_enhanced_move_to_hue(cluster);
        command::create_enhanced_move_hue(cluster);
        command::create_enhanced_step_hue(cluster);
        command::create_enhanced_move_to_hue_and_saturation(cluster);

    } else {
        ESP_LOGE(TAG, "Cluster shall support hue_saturation feature");
        return ESP_ERR_NOT_SUPPORTED;
    }
    return ESP_OK;
}
} /* enhanced_hue */

namespace color_loop {
uint32_t get_id()
{
    return (uint32_t)chip::app::Clusters::ColorControl::ColorCapabilitiesBitmap::kColorLoop;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t eh_feature_map = feature::enhanced_hue::get_id();
    if ((get_feature_map_value(cluster) & eh_feature_map) == eh_feature_map) {
        update_feature_map(cluster, get_id());
        update_color_capability(cluster, get_id());

        /* Attributes not managed internally */
        attribute::create_color_loop_active(cluster, config->color_loop_active);
        attribute::create_color_loop_direction(cluster, config->color_loop_direction);
        attribute::create_color_loop_time(cluster, config->color_loop_time);
        attribute::create_color_loop_start_enhanced_hue(cluster, config->color_loop_start_enhanced_hue);
        attribute::create_color_loop_stored_enhanced_hue(cluster, config->color_loop_stored_enhanced_hue);

        /* Commands */
        command::create_color_loop_set(cluster);
    } else {
        ESP_LOGE(TAG, "Cluster shall support enhanced_hue feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* color_loop */
} /* feature */
} /* color_control */

namespace window_covering {
namespace feature {
namespace lift {

uint32_t get_id()
{
    return (uint32_t)WindowCovering::Feature::kLift;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* lift */

namespace tilt {

uint32_t get_id()
{
    return (uint32_t)WindowCovering::Feature::kTilt;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* tilt */

namespace position_aware_lift {

uint32_t get_id()
{
    return (uint32_t)WindowCovering::Feature::kPositionAwareLift;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t lift_feature_map = feature::lift::get_id();
    if ((get_feature_map_value(cluster) & lift_feature_map) == lift_feature_map) {
        update_feature_map(cluster, get_id());

        attribute::create_target_position_lift_percent_100ths(cluster, config->target_position_lift_percent_100ths);
        attribute::create_current_position_lift_percent_100ths(cluster, config->current_position_lift_percent_100ths);

        command::create_go_to_lift_percentage(cluster);

        // We should update config_status attribute as position_aware_lift feature is added
        uint8_t set_third_bit = 1 << 3;
        attribute_t *attribute = esp_matter::attribute::get(cluster, WindowCovering::Attributes::ConfigStatus::Id);
        esp_matter_attr_val_t val = esp_matter_invalid(NULL);
        VerifyOrReturnError(esp_matter::attribute::get_val_internal(attribute, &val) == ESP_OK, ESP_FAIL);
        val.val.u8 = val.val.u8 | set_third_bit;
        return esp_matter::attribute::set_val_internal(attribute, &val, false);
    }

    ESP_LOGE(TAG, "Cluster shall support Lift feature");
    return ESP_ERR_NOT_SUPPORTED;
}
} /* position_aware_lift */

namespace position_aware_tilt {

uint32_t get_id()
{
    return (uint32_t)WindowCovering::Feature::kPositionAwareTilt;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t tilt_feature_map = feature::tilt::get_id();
    if ((get_feature_map_value(cluster) & tilt_feature_map) == tilt_feature_map) {

        update_feature_map(cluster, get_id());

        attribute::create_target_position_tilt_percent_100ths(cluster, config->target_position_tilt_percent_100ths);
        attribute::create_current_position_tilt_percent_100ths(cluster, config->current_position_tilt_percent_100ths);

        command::create_go_to_tilt_percentage(cluster);

        // We should update config_status attribute as position_aware_tilt feature is added
        uint8_t set_fourth_bit = 1 << 4;
        attribute_t *attribute = esp_matter::attribute::get(cluster, WindowCovering::Attributes::ConfigStatus::Id);
        esp_matter_attr_val_t val = esp_matter_invalid(NULL);
        VerifyOrReturnError(esp_matter::attribute::get_val_internal(attribute, &val) == ESP_OK, ESP_FAIL);
        val.val.u8 = val.val.u8 | set_fourth_bit;
        return esp_matter::attribute::set_val_internal(attribute, &val, false);
    }

    ESP_LOGE(TAG, "Cluster shall support Tilt feature");
    return ESP_ERR_NOT_SUPPORTED;
}

} /* position_aware_tilt */
} /* feature */
} /* window_covering */

namespace wifi_network_diagnostics {
namespace feature {

namespace packet_counts {

uint32_t get_id()
{
    // The WiFiNetworkDiagnosticsFeature enum class is not added in the upstream code.
    // Return the code according to the SPEC
    return 0x01;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_beacon_rx_count(cluster, 0);
    attribute::create_packet_multicast_rx_count(cluster, 0);
    attribute::create_packet_multicast_tx_count(cluster, 0);
    attribute::create_packet_unicast_rx_count(cluster, 0);
    attribute::create_packet_unicast_tx_count(cluster, 0);

    return ESP_OK;
}

} /* packet_counts */

namespace error_counts {

uint32_t get_id()
{
    // The WiFiNetworkDiagnosticsFeature enum class is not added in the upstream code.
    // Return the code according to the SPEC
    return 0x02;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_beacon_lost_count(cluster, 0);
    attribute::create_overrun_count(cluster, 0);

    /* Commands */
    command::create_reset_counts(cluster);

    return ESP_OK;
}

} /* error_counts */

} /* feature */
} /* wifi_network_diagnostics */

namespace thread_network_diagnostics {
namespace feature {

namespace packet_counts {

uint32_t get_id()
{
    return chip::to_underlying(ThreadNetworkDiagnostics::Feature::kPacketCounts);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* packet_counts */

namespace error_counts {

uint32_t get_id()
{
    return chip::to_underlying(ThreadNetworkDiagnostics::Feature::kErrorCounts);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attribute managed internally */
    attribute::create_overrun_count(cluster, 0);

    /* Command */
    command::create_reset_counts(cluster);
    return ESP_OK;
}

} /* error_counts */

namespace mle_counts {

uint32_t get_id()
{
    return chip::to_underlying(ThreadNetworkDiagnostics::Feature::kMLECounts);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* mle_counts */

namespace mac_counts {

uint32_t get_id()
{
    return chip::to_underlying(ThreadNetworkDiagnostics::Feature::kMACCounts);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* mac_counts */

} /* feature */
} /* thread_network_diagnostics */

namespace ethernet_network_diagnostics {
namespace feature {

namespace packet_counts {

uint32_t get_id()
{
    return (uint32_t)EthernetNetworkDiagnostics::Feature::kPacketCounts;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_packet_rx_count(cluster, 0);
    attribute::create_packet_tx_count(cluster, 0);

    return ESP_OK;
}

} /* packet_counts */

namespace error_counts {

uint32_t get_id()
{
    return (uint32_t)EthernetNetworkDiagnostics::Feature::kErrorCounts;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_tx_err_count(cluster, 0);
    attribute::create_collision_count(cluster, 0);
    attribute::create_overrun_count(cluster, 0);

    return ESP_OK;
}

} /* error_counts */

} /* feature */
} /* ethernet_network_diagnostics */

namespace air_quality {
namespace feature {

namespace fair {

uint32_t get_id()
{
    return (uint32_t)AirQuality::Feature::kFair;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* fair */

namespace moderate {

uint32_t get_id()
{
    return (uint32_t)AirQuality::Feature::kModerate;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* moderate */

namespace very_poor {

uint32_t get_id()
{
    return (uint32_t)AirQuality::Feature::kVeryPoor;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* very_poor */

namespace extremely_poor {

uint32_t get_id()
{
    return (uint32_t)AirQuality::Feature::kExtremelyPoor;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* extremely_poor */

} /* feature */
} /* air_quality */

namespace concentration_measurement {
namespace feature {

namespace numeric_measurement {

uint32_t get_id()
{
    return (uint32_t)CarbonMonoxideConcentrationMeasurement::Feature::kNumericMeasurement;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_measured_value(cluster, config->measured_value);
    attribute::create_min_measured_value(cluster, config->min_measured_value);
    attribute::create_max_measured_value(cluster, config->max_measured_value);
    attribute::create_measurement_unit(cluster, config->measurement_unit);

    return ESP_OK;
}

} /* numeric_measurement */

namespace level_indication {

uint32_t get_id()
{
    return (uint32_t)CarbonMonoxideConcentrationMeasurement::Feature::kLevelIndication;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_level_value(cluster, config->level_value);

    return ESP_OK;
}

} /* level_indication */

namespace medium_level {

uint32_t get_id()
{
    return (uint32_t)CarbonMonoxideConcentrationMeasurement::Feature::kMediumLevel;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    bool has_level_indication = get_feature_map_value(cluster) & feature::level_indication::get_id();
    VerifyOrReturnError(has_level_indication, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Level indication feature is not supported."));

    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* medium_level */

namespace critical_level {

uint32_t get_id()
{
    return (uint32_t)CarbonMonoxideConcentrationMeasurement::Feature::kCriticalLevel;

}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    bool has_level_indication = get_feature_map_value(cluster) & feature::level_indication::get_id();
    VerifyOrReturnError(has_level_indication, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Level indication feature is not supported."));

    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* critical_level */

namespace peak_measurement {

uint32_t get_id()
{
    return (uint32_t)CarbonMonoxideConcentrationMeasurement::Feature::kPeakMeasurement;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));

    bool has_numeric_measurement = get_feature_map_value(cluster) & feature::numeric_measurement::get_id();
    VerifyOrReturnError(has_numeric_measurement, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Numeric measurement feature is not supported."));

    update_feature_map(cluster, get_id());

    attribute::create_peak_measured_value(cluster, config->peak_measured_value);
    attribute::create_peak_measured_value_window(cluster, config->peak_measured_value_window);

    return ESP_OK;
}

} /* peak_measurement */

namespace average_measurement {

uint32_t get_id()
{
    return (uint32_t)CarbonMonoxideConcentrationMeasurement::Feature::kAverageMeasurement;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    bool has_numeric_measurement = get_feature_map_value(cluster) & feature::numeric_measurement::get_id();
    VerifyOrReturnError(has_numeric_measurement, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Numeric measurement feature is not supported."));

    update_feature_map(cluster, get_id());

    attribute::create_average_measured_value(cluster, config->average_measured_value);
    attribute::create_average_measured_value_window(cluster, config->average_measured_value_window);

    return ESP_OK;
}

} /* average_measurement */

} /* feature */
} /* concentration_measurement */

namespace resource_monitoring {
namespace feature {

namespace condition {

uint32_t get_id()
{
    return (uint32_t)HepaFilterMonitoring::Feature::kCondition;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_condition(cluster, config->condition);
    attribute::create_degradation_direction(cluster, config->degradation_direction);

    return ESP_OK;
}

} /* condition */

namespace warning {

uint32_t get_id()
{
    return (uint32_t)HepaFilterMonitoring::Feature::kWarning;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* warning */

namespace replacement_product_list {

uint32_t get_id()
{
    return (uint32_t)HepaFilterMonitoring::Feature::kReplacementProductList;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_replacement_product_list(cluster, NULL, 0, 0);

    return ESP_OK;
}

} /* replacement_product_list */

} /* feature */
} /* resource_monitoring */

namespace laundry_washer_controls {
namespace feature {

namespace spin {

uint32_t get_id()
{
    return (uint32_t)LaundryWasherControls::Feature::kSpin;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));

    update_feature_map(cluster, get_id());

    attribute::create_spin_speeds(cluster, NULL, 0, 0);
    attribute::create_spin_speed_current(cluster, config->spin_speed_current);

    return ESP_OK;
}

} /* spin */

namespace rinse {

uint32_t get_id()
{
    return (uint32_t)LaundryWasherControls::Feature::kRinse;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));

    update_feature_map(cluster, get_id());

    attribute::create_number_of_rinses(cluster, config->number_of_rinses);
    attribute::create_supported_rinses(cluster, NULL, 0, 0);

    return ESP_OK;
}

} /* rinse */

} /* feature */
} /* laundry_washer_controls */

namespace smoke_co_alarm {
namespace feature {

namespace smoke_alarm {

uint32_t get_id()
{
    return (uint32_t)SmokeCoAlarm::Feature::kSmokeAlarm;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_smoke_state(cluster, 0);

    event::create_smoke_alarm(cluster);

    return ESP_OK;
}

} /* smoke_alarm */

namespace co_alarm {

uint32_t get_id()
{
    return (uint32_t)SmokeCoAlarm::Feature::kCoAlarm;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_co_state(cluster, 0);

    event::create_co_alarm(cluster);

    return ESP_OK;
}

} /* co_alarm */

} /* feature */
} /* smoke_co_alarm */

namespace thermostat {
namespace feature {

namespace heating {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kHeating;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_occupied_heating_setpoint(cluster, config->occupied_heating_setpoint);

    return ESP_OK;
}

} /* heating */

namespace cooling {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kCooling;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_occupied_cooling_setpoint(cluster, config->occupied_cooling_setpoint);

    return ESP_OK;
}
} /* cooling */

namespace occupancy {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kOccupancy;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_occupancy(cluster, config->occupancy);

    uint32_t occ_and_cool_feature_map = get_id() | feature::cooling::get_id();
    uint32_t occ_and_heat_feature_map = get_id() | feature::heating::get_id();
    uint32_t occ_and_sb_feature_map = get_id() | feature::setback::get_id();

    if ((get_feature_map_value(cluster) & occ_and_cool_feature_map) == occ_and_cool_feature_map) {
        attribute::create_unoccupied_cooling_setpoint(cluster, config->unoccupied_cooling_setpoint);
    }

    if ((get_feature_map_value(cluster) & occ_and_heat_feature_map) == occ_and_heat_feature_map) {
        attribute::create_unoccupied_heating_setpoint(cluster, config->unoccupied_heating_setpoint);
    }

    if ((get_feature_map_value(cluster) & occ_and_sb_feature_map) == occ_and_sb_feature_map) {

        attribute::create_unoccupied_setback(cluster, config->unoccupied_setback);
        attribute::create_unoccupied_setback_min(cluster, config->unoccupied_setback_min);
        attribute::create_unoccupied_setback_max(cluster, config->unoccupied_setback_max);
    }

    return ESP_OK;
}
} /* occupancy */

namespace setback {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kSetback;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_occupied_setback(cluster, config->occupied_setback);
    attribute::create_occupied_setback_min(cluster, config->occupied_setback_min);
    attribute::create_occupied_setback_max(cluster, config->occupied_setback_max);

    return ESP_OK;
}
} /* setback */

namespace auto_mode {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kAutoMode;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_min_setpoint_dead_band(cluster, config->min_setpoint_dead_band);

    return ESP_OK;
}
} /* auto_mode */

namespace local_temperature_not_exposed {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kLocalTemperatureNotExposed;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* local_temperature_not_exposed */

namespace matter_schedule_configuration {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kMatterScheduleConfiguration;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_schedule_types(cluster, NULL, 0, 0);
    attribute::create_number_of_schedules(cluster, config->number_of_schedules);
    attribute::create_number_of_schedule_transitions(cluster, config->number_of_schedule_transitions);
    attribute::create_number_of_schedule_transition_per_day(cluster, config->number_of_schedule_transition_per_day);
    attribute::create_active_schedule_handle(cluster, config->active_schedule_handle, sizeof(config->active_schedule_handle));
    attribute::create_schedules(cluster, NULL, 0, 0);

    command::create_set_active_schedule_request(cluster);
    return ESP_OK;
}
} /* matter_schedule_configuration */

namespace presets {

uint32_t get_id()
{
    return (uint32_t)Thermostat::Feature::kPresets;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_preset_types(cluster, NULL, 0, 0);
    attribute::create_number_of_presets(cluster, 0);
    attribute::create_active_preset_handle(cluster, NULL, 0);
    attribute::create_presets(cluster, NULL, 0, 0);

    command::create_set_active_preset_request(cluster);
    return ESP_OK;
}
} /* presets */

} /* feature */
} /* thermostat */

namespace switch_cluster {
namespace feature {
namespace latching_switch {

uint32_t get_id()
{
    return (uint32_t)Switch::Feature::kLatchingSwitch;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError((get_feature_map_value(cluster) & feature::momentary_switch::get_id()) != feature::momentary_switch::get_id(), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Latching switch is not supported because momentary switch is present"));
    update_feature_map(cluster, get_id());

    event::create_switch_latched(cluster);
    return ESP_OK;
}

} /* latching_switch */

namespace momentary_switch {

uint32_t get_id()
{
    return (uint32_t)Switch::Feature::kMomentarySwitch;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError((get_feature_map_value(cluster) & feature::latching_switch::get_id()) != feature::latching_switch::get_id(), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch is not supported because latching switch is present"));
    update_feature_map(cluster, get_id());

    event::create_initial_press(cluster);
    return ESP_OK;
}

} /* momentary_switch */

namespace momentary_switch_release {

uint32_t get_id()
{
    return (uint32_t)Switch::Feature::kMomentarySwitchRelease;
}

esp_err_t add(cluster_t *cluster)
{
    uint32_t as_feature_map = feature::action_switch::get_id();
    uint32_t ms_feature_map = feature::momentary_switch::get_id();
    uint32_t feature_map = get_feature_map_value(cluster);
    VerifyOrReturnError(((feature_map & ms_feature_map) == ms_feature_map) && ((feature_map & as_feature_map) != as_feature_map), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch release is not supported."));
    update_feature_map(cluster, get_id());

    event::create_short_release(cluster);
    return ESP_OK;
}

} /* momentary_switch_release */

namespace momentary_switch_long_press {

uint32_t get_id()
{
    return (uint32_t)Switch::Feature::kMomentarySwitchLongPress;
}

esp_err_t add(cluster_t *cluster)
{
    uint32_t msr_feature_map = feature::momentary_switch_release::get_id();
    uint32_t as_feature_map = feature::action_switch::get_id();
    uint32_t ms_feature_map = feature::momentary_switch::get_id();
    uint32_t feature_map = get_feature_map_value(cluster);
    VerifyOrReturnError((feature_map & ms_feature_map) == ms_feature_map, ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch long press is not supported."));
    VerifyOrReturnError(((feature_map & msr_feature_map) == msr_feature_map) || ((feature_map & as_feature_map) == as_feature_map), ESP_ERR_NOT_SUPPORTED, ESP_LOGE(TAG, "Momentary switch long press is not supported."));
    update_feature_map(cluster, get_id());

    event::create_long_press(cluster);
    event::create_long_release(cluster);
    return ESP_OK;
}

} /* momentary_switch_long_press */

namespace momentary_switch_multi_press {

uint32_t get_id()
{
    return (uint32_t)Switch::Feature::kMomentarySwitchMultiPress;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    uint32_t as_feature_map = feature::action_switch::get_id();
    uint32_t ms_feature_map = feature::momentary_switch::get_id();
    uint32_t msr_feature_map = feature::momentary_switch_release::get_id();
    uint32_t ms_and_msr = ms_feature_map | msr_feature_map;
    if ((get_feature_map_value(cluster) & as_feature_map) != as_feature_map) {
        if ((get_feature_map_value(cluster) & ms_and_msr) != ms_and_msr) {
            ESP_LOGE(TAG, "Momentary switch multi press is not supported.");
            return ESP_ERR_NOT_SUPPORTED;
        }
        event::create_multi_press_ongoing(cluster);
    }
    update_feature_map(cluster, get_id());

    attribute::create_multi_press_max(cluster, config->multi_press_max);

    event::create_multi_press_complete(cluster);
    return ESP_OK;
}

} /* momentary_switch_multi_press */

namespace action_switch {

uint32_t get_id()
{
    return (uint32_t)Switch::Feature::kActionSwitch;
}

esp_err_t add(cluster_t *cluster)
{
    if ((get_feature_map_value(cluster) & feature::momentary_switch::get_id()) != feature::momentary_switch::get_id()) {
        ESP_LOGE(TAG, "Momentary switch is present");
        return ESP_ERR_NOT_SUPPORTED;
    }
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* action_switch */

} /* feature */
} /* switch_cluster */

namespace unit_localization {
namespace feature {

namespace temperature_unit {

uint32_t get_id()
{
    return (uint32_t)UnitLocalization::Feature::kTemperatureUnit;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_temperature_unit(cluster, 0);
    attribute::create_supported_temperature_units(cluster, NULL, 0, 0);

    return ESP_OK;
}

} /* temperature_unit */

} /* feature */
} /* unit_localization */

namespace time_format_localization {
namespace feature {

namespace calendar_format {

uint32_t get_id()
{
    // enum class for CalendarFormat is not present in the upstream code.
    // Return the code according to the SPEC
    return 0x01;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_active_calendar_type(cluster, config->active_calendar_type);

    /* Attributes managed internally */
    attribute::create_supported_calendar_types(cluster, NULL, 0, 0);

    return ESP_OK;
}

} /* calendar_format */

} /* feature */
} /* time_format_localization */

namespace mode_select {
namespace feature {

namespace on_off {

uint32_t get_id()
{
    return (uint32_t)ModeSelect::Feature::kOnOff;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_on_mode(cluster, config->on_mode);

    return ESP_OK;
}
} /* on_off */

} /* feature */
} /* mode_select */

namespace pressure_measurement {
namespace feature {

namespace extended {

uint32_t get_id()
{
    return (uint32_t)PressureMeasurement::Feature::kExtended;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_scaled_value(cluster, config->scaled_value);
    attribute::create_min_scaled_value(cluster, config->min_scaled_value);
    attribute::create_max_scaled_value(cluster, config->max_scaled_value);
    attribute::create_scale(cluster, config->scale);

    return ESP_OK;
}

} /* extended */

} /* feature */
} /* pressure_measurement */

namespace general_diagnostics {
namespace feature {

namespace data_model_test {

uint32_t get_id()
{
    return (uint32_t)GeneralDiagnostics::Feature::kDataModelTest;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    update_feature_map(cluster, get_id());
    command::create_payload_test_request(cluster);
    command::create_payload_test_response(cluster);
    return ESP_OK;
}
} /* data_model_test */
} /* feature */
} /* general diagnostics */
namespace software_diagnostics {
namespace feature {

namespace watermarks {

uint32_t get_id()
{
    // enum class for SoftwareDiagnosticsFeature is not present in the upstream code.
    // Return the code according to the SPEC
    return 0x01;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_current_heap_high_watermark(cluster, 0);

    /* commands */
    command::create_reset_watermarks(cluster);

    return ESP_OK;
}
} /* watermarks */

} /* feature */
} /* software_diagnostics */

namespace temperature_control {
namespace feature {
namespace temperature_number {

uint32_t get_id()
{
    return (uint32_t)TemperatureControl::Feature::kTemperatureNumber;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t temp_level_feature_map = feature::temperature_level::get_id();
    if ((get_feature_map_value(cluster) & temp_level_feature_map) != temp_level_feature_map) {
        update_feature_map(cluster, get_id());

        /* Attributes not managed internally */
        attribute::create_temperature_setpoint(cluster, config->temp_setpoint);
        attribute::create_min_temperature(cluster, config->min_temperature);
        attribute::create_max_temperature(cluster, config->max_temperature);
    } else {
        ESP_LOGE(TAG, "Cluster shall support either TemperatureNumber or TemperatureLevel feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* temperature_number */

namespace temperature_level {

uint32_t get_id()
{
    return (uint32_t)TemperatureControl::Feature::kTemperatureLevel;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t temp_number_feature_map = feature::temperature_number::get_id();
    if ((get_feature_map_value(cluster) & temp_number_feature_map) != temp_number_feature_map) {
        update_feature_map(cluster, get_id());

        /* Attributes managed internally */
        attribute::create_supported_temperature_levels(cluster, NULL, 0, 0);

        /* Attributes not managed internally */
        attribute::create_selected_temperature_level(cluster, config->selected_temp_level);
    } else {
        ESP_LOGE(TAG, "Cluster shall support either TemperatureLevel or TemperatureNumber feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* temperature_level */

namespace temperature_step {

uint32_t get_id()
{
    return (uint32_t)TemperatureControl::Feature::kTemperatureStep;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t temp_number_feature_map = feature::temperature_number::get_id();
    if ((get_feature_map_value(cluster) & temp_number_feature_map) == temp_number_feature_map) {
        update_feature_map(cluster, get_id());

        /* Attributes not managed internally */
        attribute::create_step(cluster, config->step);
    } else {
        ESP_LOGE(TAG, "Cluster shall support TemperatureNumber feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* temperature_step */

} /* feature */
} /* temperature_control */

namespace fan_control {
namespace feature {

namespace multi_speed {

uint32_t get_id()
{
    return (uint32_t)FanControl::Feature::kMultiSpeed;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_speed_max(cluster, config->speed_max);
    attribute::create_speed_setting(cluster, config->speed_setting);
    attribute::create_speed_current(cluster, config->speed_current);

    return ESP_OK;
}
} /* multi_speed */

namespace fan_auto {

uint32_t get_id()
{
    return (uint32_t)FanControl::Feature::kAuto;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* fan_auto */

namespace rocking {

uint32_t get_id()
{
    return (uint32_t)FanControl::Feature::kRocking;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_rock_support(cluster, config->rock_support);
    attribute::create_rock_setting(cluster, config->rock_setting);

    return ESP_OK;
}
} /* rocking */

namespace wind {

uint32_t get_id()
{
    return (uint32_t)FanControl::Feature::kWind;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_wind_support(cluster, config->wind_support);
    attribute::create_wind_setting(cluster, config->wind_setting);

    return ESP_OK;
}
} /* wind */

namespace step {

uint32_t get_id()
{
    return (uint32_t)FanControl::Feature::kStep;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    command::create_step(cluster);

    return ESP_OK;
}
} /* step */

namespace airflow_direction {

uint32_t get_id()
{
    return (uint32_t)FanControl::Feature::kAirflowDirection;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_airflow_direction(cluster, config->airflow_direction);

    return ESP_OK;
}
} /* airflow_direction */

} /* feature */
} /* fan_control */

namespace keypad_input {
namespace feature {

namespace navigation_key_codes {

uint32_t get_id()
{
    return (uint32_t)KeypadInput::Feature::kNavigationKeyCodes;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* navigation_key_codes */

namespace location_keys {

uint32_t get_id()
{
    return (uint32_t)KeypadInput::Feature::kLocationKeys;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* location_keys */

namespace number_keys {

uint32_t get_id()
{
    return (uint32_t)KeypadInput::Feature::kNumberKeys;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* number_keys */

} /* feature */
} /* keypad_input */

namespace boolean_state_configuration {
namespace feature {

namespace visual {

uint32_t get_id()
{
    return (uint32_t)BooleanStateConfiguration::Feature::kVisual;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_alarms_active(cluster, config->alarms_active);
    attribute::create_alarms_supported(cluster, config->alarms_supported);

    command::create_enable_disable_alarm(cluster);

    event::create_alarms_state_changed(cluster);
    return ESP_OK;
}
} /* visual */

namespace audible {

uint32_t get_id()
{
    return (uint32_t)BooleanStateConfiguration::Feature::kAudible;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_alarms_active(cluster, config->alarms_active);
    attribute::create_alarms_supported(cluster, config->alarms_supported);

    command::create_enable_disable_alarm(cluster);

    event::create_alarms_state_changed(cluster);
    return ESP_OK;
}
} /* audible */

namespace alarm_suppress {

uint32_t get_id()
{
    return (uint32_t)BooleanStateConfiguration::Feature::kAlarmSuppress;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t visual_feature_map = feature::visual::get_id();
    uint32_t audible_feature_map = feature::audible::get_id();
    if ((get_feature_map_value(cluster) & visual_feature_map) == visual_feature_map ||
            (get_feature_map_value(cluster) & audible_feature_map) == audible_feature_map) {
        update_feature_map(cluster, get_id());

        attribute::create_alarms_suppressed(cluster, config->alarms_suppressed);

        command::create_suppress_alarm(cluster);
    } else {
        ESP_LOGE(TAG, "Cluster shall support either visual or audio feature");
        return ESP_ERR_NOT_SUPPORTED;
    }
    return ESP_OK;
}
} /* alarm_suppress */

namespace sensitivity_level {

uint32_t get_id()
{
    return (uint32_t)BooleanStateConfiguration::Feature::kSensitivityLevel;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_current_sensitivity_level(cluster, 0);
    attribute::create_supported_sensitivity_levels(cluster, config->supported_sensitivity_levels);
    return ESP_OK;
}
} /* sensitivity_level */

} /* feature */
} /* boolean_state_configuration */

namespace power_topology {
namespace feature {

namespace node_topology {

uint32_t get_id()
{
    return (uint32_t)PowerTopology::Feature::kNodeTopology;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* node_topology */

namespace tree_topology {

uint32_t get_id()
{
    return (uint32_t)PowerTopology::Feature::kTreeTopology;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* tree_topology */

namespace set_topology {

uint32_t get_id()
{
    return (uint32_t)PowerTopology::Feature::kSetTopology;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_available_endpoints(cluster, NULL, 0, 0);
    return ESP_OK;
}
} /* set_topology */

namespace dynamic_power_flow {

uint32_t get_id()
{
    return (uint32_t)PowerTopology::Feature::kDynamicPowerFlow;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t set_topology_feature_map = feature::set_topology::get_id();
    if ((get_feature_map_value(cluster) & set_topology_feature_map) == set_topology_feature_map) {

        update_feature_map(cluster, get_id());

        attribute::create_active_endpoints(cluster, NULL, 0, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall support Set Topology feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* dynamic_power_flow */

} /* feature */
} /* power_topology */

namespace electrical_power_measurement {
namespace feature {

namespace direct_current {

uint32_t get_id()
{
    return (uint32_t)ElectricalPowerMeasurement::Feature::kDirectCurrent;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* direct_current */

namespace alternating_current {

uint32_t get_id()
{
    return (uint32_t)ElectricalPowerMeasurement::Feature::kAlternatingCurrent;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* alternating_current */

namespace polyphase_power {

uint32_t get_id()
{
    return (uint32_t)ElectricalPowerMeasurement::Feature::kPolyphasePower;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t ac_feature_map = feature::alternating_current::get_id();
    if ((get_feature_map_value(cluster) & ac_feature_map) == ac_feature_map) {

        update_feature_map(cluster, get_id());

    } else {
        ESP_LOGE(TAG, "Cluster shall support Alternating Current feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* polyphase_power */

namespace harmonics {

uint32_t get_id()
{
    return (uint32_t)ElectricalPowerMeasurement::Feature::kHarmonics;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t ac_feature_map = feature::alternating_current::get_id();
    if ((get_feature_map_value(cluster) & ac_feature_map) == ac_feature_map) {

        update_feature_map(cluster, get_id());

        attribute::create_harmonic_currents(cluster, NULL, 0, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall support Alternating Current feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* harmonics */

namespace power_quality {

uint32_t get_id()
{
    return (uint32_t)ElectricalPowerMeasurement::Feature::kPowerQuality;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t ac_feature_map = feature::alternating_current::get_id();
    if ((get_feature_map_value(cluster) & ac_feature_map) == ac_feature_map) {

        update_feature_map(cluster, get_id());

        attribute::create_harmonic_phases(cluster, NULL, 0, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall support Alternating Current feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* power_quality */

} /* feature */
} /* electrical_power_measurement */

namespace electrical_energy_measurement {
namespace feature {

namespace imported_energy {

uint32_t get_id()
{
    return (uint32_t)ElectricalEnergyMeasurement::Feature::kImportedEnergy;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* imported_energy */

namespace exported_energy {

uint32_t get_id()
{
    return (uint32_t)ElectricalEnergyMeasurement::Feature::kExportedEnergy;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* exported_energy */

namespace cumulative_energy {

uint32_t get_id()
{
    return (uint32_t)ElectricalEnergyMeasurement::Feature::kCumulativeEnergy;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    uint32_t imported_feature_map = feature::imported_energy::get_id();
    uint32_t exported_feature_map = feature::exported_energy::get_id();
    if ((get_feature_map_value(cluster) & imported_feature_map) == imported_feature_map) {
        attribute::create_cumulative_energy_imported(cluster, NULL, 0, 0);
    }
    if ((get_feature_map_value(cluster) & exported_feature_map) == exported_feature_map) {
        attribute::create_cumulative_energy_exported(cluster, NULL, 0, 0);
    }

    event::create_cumulative_energy_measured(cluster);
    return ESP_OK;
}
} /* cumulative_energy */

namespace periodic_energy {

uint32_t get_id()
{
    return (uint32_t)ElectricalEnergyMeasurement::Feature::kPeriodicEnergy;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    uint32_t imported_feature_map = feature::imported_energy::get_id();
    uint32_t exported_feature_map = feature::exported_energy::get_id();
    if ((get_feature_map_value(cluster) & imported_feature_map) == imported_feature_map) {
        attribute::create_periodic_energy_imported(cluster, NULL, 0, 0);
    }
    if ((get_feature_map_value(cluster) & exported_feature_map) == exported_feature_map) {
        attribute::create_periodic_energy_exported(cluster, NULL, 0, 0);
    }

    event::create_periodic_energy_measured(cluster);
    return ESP_OK;
}
} /* periodic_energy */

} /* feature */
} /* electrical_energy_measurement */

namespace door_lock {
namespace feature {

namespace pin_credential {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kPinCredential;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_number_of_pin_users_supported(cluster, config->number_pin_users_supported);
    attribute::create_max_pin_code_length(cluster, config->max_pin_code_length);
    attribute::create_min_pin_code_length(cluster, config->min_pin_code_length);
    attribute::create_wrong_code_entry_limit(cluster, config->wrong_code_entry_limit);
    attribute::create_user_code_temporary_disable_time(cluster, config->user_code_temporary_disable_time);

    uint32_t cota_feature_map = feature::credential_over_the_air_access::get_id();
    if (get_feature_map_value(cluster) & cota_feature_map) {
        attribute::create_require_pin_for_remote_operation(cluster, config->require_pin_for_remote_operation);
    }

    uint32_t usr_feature_map = feature::user::get_id();
    if (!(get_feature_map_value(cluster) & usr_feature_map)) {
        /* todo: some commands for !USR & PIN feature not define in the
        connectedhomeip/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h
        will update when added*/
    }

    return ESP_OK;
}
} /* pin_credential */

namespace rfid_credential {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kRfidCredential;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_number_of_rfid_users_supported(cluster, config->number_rfid_users_supported);
    attribute::create_max_rfid_code_length(cluster, config->max_rfid_code_length);
    attribute::create_min_rfid_code_length(cluster, config->min_rfid_code_length);
    attribute::create_wrong_code_entry_limit(cluster, config->wrong_code_entry_limit);
    attribute::create_user_code_temporary_disable_time(cluster, config->user_code_temporary_disable_time);

    uint32_t usr_feature_map = feature::user::get_id();
    if (!(get_feature_map_value(cluster) & usr_feature_map)) {
        /* todo: some commands for !USR & RID feature not define in the
        connectedhomeip/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h
        will update when added*/
    }

    return ESP_OK;
}

} /* rfid_credential */

namespace finger_credentials {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kFingerCredentials;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    uint32_t usr_feature_map = feature::user::get_id();
    if (!(get_feature_map_value(cluster) & usr_feature_map)) {
        /* todo: some commands for !USR & FGP feature not define in the
        connectedhomeip/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h
        will update when added*/
    }

    return ESP_OK;
}

} /* finger_credentials */

namespace logging {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kLogging;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* todo: all attributes for LOG feature not define in the
    connectedhomeip/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/ids/Attributes.h
    will update when added*/

    /* todo: all commands for LOG feature not define in the
    connectedhomeip/connectedhomeip/zzz_generated/app-common/app-common/zap-generated/ids/Commands.h
    will update when added*/

    return ESP_OK;
}

} /* logging */

namespace weekday_access_schedules {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kWeekDayAccessSchedules;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_number_of_weekday_schedules_supported_per_user(cluster, 1);
    /* Commands */
    command::create_set_weekday_schedule(cluster);
    command::create_get_weekday_schedule(cluster);
    command::create_get_weekday_schedule_response(cluster);
    command::create_clear_weekday_schedule(cluster);

    return ESP_OK;
}

} /* weekday_access_schedules */

namespace door_position_sensor {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kDoorPositionSensor;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_door_state(cluster, 0);

    /* events */
    event::create_door_state_change(cluster);

    return ESP_OK;
}

} /* door_position_sensor */

namespace face_credentials {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kFaceCredentials;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* face_credentials */

namespace credential_over_the_air_access {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kCredentialsOverTheAirAccess;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    uint32_t pin_credential_feature_map = feature::pin_credential::get_id();
    if (get_feature_map_value(cluster) & pin_credential_feature_map) {
        attribute::create_require_pin_for_remote_operation(cluster, config->require_pin_for_remote_operation);
    }

    return ESP_OK;
}

} /* credential_over_the_air_access */

namespace user {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kUser;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t pin = feature::pin_credential::get_id();
    uint32_t rid = feature::rfid_credential::get_id();
    uint32_t fgp = feature::finger_credentials::get_id();
    uint32_t face = feature::face_credentials::get_id();
    uint32_t feature = get_feature_map_value(cluster);
    VerifyOrReturnError((feature & (pin | rid | fgp | face)) != 0, ESP_FAIL, ESP_LOGE(TAG, "Should add at least one of PIN, RID, FGP and FACE feature before add USR feature"));

    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_number_of_total_users_supported(cluster, config->number_of_total_user_supported);
    attribute::create_credential_rules_support(cluster, config->credential_rules_supported);
    attribute::create_number_of_credentials_supported_per_user(cluster, config->number_of_credentials_supported_per_user);

    /* Commands */
    command::create_set_user(cluster);
    command::create_get_user(cluster);
    command::create_get_user_response(cluster);
    command::create_clear_user(cluster);
    command::create_set_credential(cluster);
    command::create_set_credential_response(cluster);
    command::create_get_credential_status(cluster);
    command::create_get_credential_status_response(cluster);
    command::create_clear_credential(cluster);

    /* Events */
    event::create_lock_user_change(cluster);

    return ESP_OK;
}

} /* user */

namespace notification {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kNotification;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* notification */

namespace year_day_access_schedules {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kYearDayAccessSchedules;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_number_of_year_day_schedules_supported_per_user(cluster, config->number_of_year_day_schedules_supported_per_user);

    /* Commands */
    command::create_set_year_day_schedule(cluster);
    command::create_get_year_day_schedule(cluster);
    command::create_get_year_day_schedule_response(cluster);
    command::create_clear_year_day_schedule(cluster);

    return ESP_OK;
}

} /* year_day_access_schedules */

namespace holiday_schedules {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kHolidaySchedules;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes not managed internally */
    attribute::create_number_of_holiday_schedules_supported(cluster, config->number_of_holiday_schedules_supported);

    /* Commands */
    command::create_set_holiday_schedule(cluster);
    command::create_get_holiday_schedule(cluster);
    command::create_get_holiday_schedule_response(cluster);
    command::create_clear_holiday_schedule(cluster);

    return ESP_OK;
}

} /* holiday_schedules */

namespace unbolting {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kUnbolt;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Commands */
    command::create_unbolt_door(cluster);

    return ESP_OK;
}

} /* unbolting */

namespace aliro_provisioning {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kAliroProvisioning;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_aliro_reader_verification_key(cluster, NULL, 0);
    attribute::create_aliro_reader_group_identifier(cluster, NULL, 0);
    attribute::create_aliro_reader_group_sub_identifier(cluster, NULL, 0);
    attribute::create_aliro_expedited_transaction_supported_protocol_versions(cluster, NULL, 0, 0);
    attribute::create_number_of_aliro_credential_issuer_keys_supported(cluster, 0);
    attribute::create_number_of_aliro_endpoint_keys_supported(cluster, 0);

    /* Commands */
    command::create_set_aliro_reader_config(cluster);
    command::create_clear_aliro_reader_config(cluster);
    return ESP_OK;
}

} /* aliro_provisioning */

namespace aliro_bleuwb {

uint32_t get_id()
{
    return (uint32_t)DoorLock::Feature::kAliroBLEUWB;
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_aliro_group_resolving_key(cluster, NULL, 0);
    attribute::create_aliro_supported_bleuwb_protocol_versions(cluster, NULL, 0, 0);
    attribute::create_aliro_ble_advertising_version(cluster, 0);
    return ESP_OK;
}

} /* aliro_bleuwb */

} /* feature */
} /* door_lock */

namespace energy_evse {
namespace feature {
namespace charging_preferences {

uint32_t get_id()
{
    return (uint32_t)EnergyEvse::Feature::kChargingPreferences;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_next_charge_start_time(cluster, 0);
    attribute::create_next_charge_target_time(cluster, 0);
    attribute::create_next_charge_required_energy(cluster, 0);
    attribute::create_next_charge_target_soc(cluster, 0);

    /* Commands */
    command::create_set_targets(cluster);
    command::create_get_targets(cluster);
    command::create_clear_targets(cluster);
    command::create_get_targets_response(cluster);
    return ESP_OK;
}

} /* charging_preferences */

namespace soc_reporting {

uint32_t get_id()
{
    return (uint32_t)EnergyEvse::Feature::kSoCReporting;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_state_of_charge(cluster, 0);
    attribute::create_battery_capacity(cluster, 0);

    return ESP_OK;
}

} /* soc_reporting */

namespace plug_and_charge {

uint32_t get_id()
{
    return (uint32_t)EnergyEvse::Feature::kPlugAndCharge;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_vehicle_id(cluster, NULL, 0);

    return ESP_OK;
}

} /* plug_and_charge */

namespace rfid {

uint32_t get_id()
{
    return (uint32_t)EnergyEvse::Feature::kRfid;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    return ESP_OK;
}

} /* rfid */

namespace v2x {

uint32_t get_id()
{
    return (uint32_t)EnergyEvse::Feature::kV2x;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* Attributes managed internally */
    attribute::create_discharging_enabled_until(cluster, 0);
    attribute::create_maximum_discharge_current(cluster, 0);
    attribute::create_session_energy_discharged(cluster, 0);

    /* Commands */
    command::create_enable_discharging(cluster);
    return ESP_OK;
}

} /* v2x*/

} /* feature */
} /* energy_evse */

namespace microwave_oven_control {
namespace feature {

namespace power_as_number {

uint32_t get_id()
{
    return (uint32_t)MicrowaveOvenControl::Feature::kPowerAsNumber;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t power_in_watts_feature_map = feature::power_in_watts::get_id();
    if ((get_feature_map_value(cluster) & power_in_watts_feature_map) != power_in_watts_feature_map) {
        update_feature_map(cluster, get_id());
        /* Attributes managed internally */
        attribute::create_power_setting(cluster, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall support either PowerAsNumber or PowerInWatts feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* power_as_number */

namespace power_in_watts {

uint32_t get_id()
{
    return (uint32_t)MicrowaveOvenControl::Feature::kPowerInWatts;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t power_as_number_feature_map = feature::power_as_number::get_id();
    if ((get_feature_map_value(cluster) & power_as_number_feature_map) != power_as_number_feature_map) {
        update_feature_map(cluster, get_id());
        /* Attributes managed internally */
        attribute::create_supported_watts(cluster, NULL, 0, 0);
        attribute::create_selected_watt_index(cluster, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall support either PowerInWatts or PowerAsNumber feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* power_in_watts */

namespace power_number_limits {

uint32_t get_id()
{
    return (uint32_t)MicrowaveOvenControl::Feature::kPowerNumberLimits;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t power_as_number_feature_map = feature::power_as_number::get_id();
    if ((get_feature_map_value(cluster) & power_as_number_feature_map) != power_as_number_feature_map) {
        update_feature_map(cluster, get_id());
        /* Attributes managed internally */
        attribute::create_min_power(cluster, 0);
        attribute::create_max_power(cluster, 0);
        attribute::create_power_step(cluster, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall support PowerAsNumber feature.");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* power_number_limits */

} /* feature */
} /* microwave_oven_control */

namespace valve_configuration_and_control {
namespace feature {

namespace time_sync {

uint32_t get_id()
{
    return (uint32_t)ValveConfigurationAndControl::Feature::kTimeSync;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_auto_close_time(cluster, config->auto_close_time);

    return ESP_OK;
}
} /* time_sync */

namespace level {

uint32_t get_id()
{
    return (uint32_t)ValveConfigurationAndControl::Feature::kLevel;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute::create_current_level(cluster, config->current_level);
    attribute::create_target_level(cluster, config->target_level);

    return ESP_OK;
}
} /* level */

} /* feature */
} /* valve_configuration_and_control */

namespace device_energy_management {
namespace feature {

namespace power_adjustment {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kPowerAdjustment;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    attribute::create_power_adjustment_capability(cluster, NULL, 0, 0);
    attribute::create_opt_out_state(cluster, 0);

    /* Commands */
    command::create_power_adjust_request(cluster);
    command::create_cancel_power_adjust_request(cluster);

    /* Events */
    event::create_power_adjust_start(cluster);
    event::create_power_adjust_end(cluster);

    return ESP_OK;
}
} /* power_adjustment */

namespace power_forecast_reporting {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kPowerForecastReporting;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    attribute::create_forecast(cluster, NULL, 0, 0);

    return ESP_OK;
}
} /* power_forecast_reporting */

namespace state_forecast_reporting {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kStateForecastReporting;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    uint32_t power_adjustment_id            = feature::power_adjustment::get_id();
    uint32_t power_forecast_reporting       = feature::power_forecast_reporting::get_id();
    uint32_t start_time_adjustment_id       = feature::start_time_adjustment::get_id();
    uint32_t pausable_id                    = feature::pausable::get_id();
    uint32_t forecast_adjustment_id         = feature::forecast_adjustment::get_id();
    uint32_t constraint_based_adjustment_id = feature::constraint_based_adjustment::get_id();
    uint32_t feature_map_value              = get_feature_map_value(cluster);
    if ((((feature_map_value & power_adjustment_id)              != power_adjustment_id) ||
            ((feature_map_value & start_time_adjustment_id)         == start_time_adjustment_id) ||
            ((feature_map_value & pausable_id)                      == pausable_id) ||
            ((feature_map_value & forecast_adjustment_id)           == forecast_adjustment_id) ||
            ((feature_map_value & constraint_based_adjustment_id)   == constraint_based_adjustment_id)) &&
            ((feature_map_value & power_forecast_reporting)         != power_forecast_reporting)) {
        update_feature_map(cluster, get_id());
        attribute::create_forecast(cluster, NULL, 0, 0);
    } else {
        ESP_LOGE(TAG, "Cluster shall satisfy condition (STA|PAU|FA|CON|!PA)&!PFR of feature");
        return ESP_ERR_NOT_SUPPORTED;
    }

    return ESP_OK;
}
} /* state_forecast_reporting */

namespace start_time_adjustment {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kStartTimeAdjustment;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    attribute::create_opt_out_state(cluster, 0);

    /* Commands */
    command::create_start_time_adjust_request(cluster);
    command::create_cancel_request(cluster);

    return ESP_OK;
}
} /* start_time_adjustment */

namespace pausable {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kPausable;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    attribute::create_opt_out_state(cluster, 0);

    /* Commands */
    command::create_pause_request(cluster);
    command::create_resume_request(cluster);

    /* Events */
    event::create_paused(cluster);
    event::create_resumed(cluster);

    return ESP_OK;
}
} /* pausable */

namespace forecast_adjustment {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kForecastAdjustment;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    attribute::create_opt_out_state(cluster, 0);

    /* Commands */
    command::create_modify_forecast_request(cluster);
    command::create_cancel_request(cluster);

    return ESP_OK;
}
} /* forecast_adjustment */

namespace constraint_based_adjustment {

uint32_t get_id()
{
    return (uint32_t)DeviceEnergyManagement::Feature::kConstraintBasedAdjustment;
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    attribute::create_opt_out_state(cluster, 0);

    /* Commands */
    command::create_request_constraint_based_forecast(cluster);
    command::create_cancel_request(cluster);

    return ESP_OK;
}
} /* constraint_based_adjustment */

} /* feature */
} /* device_energy_management */

namespace thread_border_router_management {
namespace feature {

namespace pan_change {

uint32_t get_id()
{
    return static_cast<uint32_t>(ThreadBorderRouterManagement::Feature::kPANChange);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    /* command */
    command::create_set_pending_dataset_request(cluster);
    return ESP_OK;
}

} /* pan_change */

} /* feature */
} /* thread_border_router_management */

namespace service_area {
namespace feature {

namespace select_while_running {

uint32_t get_id()
{
    return static_cast<uint32_t>(ServiceArea::Feature::kSelectWhileRunning);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* select_while_running */

namespace progress_reporting {

uint32_t get_id()
{
    return static_cast<uint32_t>(ServiceArea::Feature::kProgressReporting);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_progress(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* progress_reporting */

namespace maps {

uint32_t get_id()
{
    return static_cast<uint32_t>(ServiceArea::Feature::kMaps);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_supported_maps(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* maps */

} /* feature */
} /* service_area */

namespace water_heater_management {
namespace feature {

namespace energy_management {

uint32_t get_id()
{
    return static_cast<uint32_t>(WaterHeaterManagement::Feature::kEnergyManagement);
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    /* attribute */
    attribute::create_tank_volume(cluster, 0);
    attribute::create_estimated_heat_required(cluster, 0);

    return ESP_OK;
}

} /* energy_management */

namespace tank_percent {

uint32_t get_id()
{
    return static_cast<uint32_t>(WaterHeaterManagement::Feature::kEnergyManagement);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    /* attribute */
    attribute::create_tank_percentage(cluster, 0);

    return ESP_OK;
}

} /* tank_percent */

} /* feature */
} /* water_heater_management */

namespace energy_preference {
namespace feature {

namespace energy_balance {

uint32_t get_id()
{
    return (uint32_t)EnergyPreference::Feature::kEnergyBalance;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    attribute::create_energy_balances(cluster, NULL, 0, 0);
    attribute::create_current_energy_balance(cluster, config->current_energy_balance);
    attribute::create_energy_priorities(cluster, NULL, 0, 0);

    return ESP_OK;
}
} /* energy_balance */

namespace low_power_mode_sensitivity {

uint32_t get_id()
{
    return (uint32_t)EnergyPreference::Feature::kLowPowerModeSensitivity;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_low_power_mode_sensitivities(cluster, NULL, 0, 0);
    attribute::create_current_low_power_mode_sensitivity(cluster, config->current_low_power_mode_sensitivity);

    return ESP_OK;
}
} /* low_power_mode_sensitivity */

} /* feature */
} /* energy_preference */

namespace occupancy_sensing {
namespace feature {

namespace other {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kOther);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* other */

namespace passive_infrared {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kPassiveInfrared);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* passive_infrared */

namespace ultrasonic {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kUltrasonic);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* ultrasonic */

namespace physical_contact {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kPhysicalContact);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* physical_contact */

namespace active_infrared {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kActiveInfrared);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* active_infrared */

namespace radar {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kRadar);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* radar */

namespace rf_sensing {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kRFSensing);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* rf_sensing */

namespace vision {

uint32_t get_id()
{
    return static_cast<uint32_t>(OccupancySensing::Feature::kVision);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* vision */

} /* feature */
} /* occupancy_sensing */

namespace pump_configuration_and_control {
namespace feature {
namespace constant_pressure {

uint32_t get_id()
{
    return (uint32_t)PumpConfigurationAndControl::Feature::kConstantPressure;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_min_const_pressure(cluster, config->min_const_pressure);
    attribute::create_max_const_pressure(cluster, config->max_const_pressure);

    return ESP_OK;
}
} /* constant_pressure */

namespace compensated_pressure {

uint32_t get_id()
{
    return (uint32_t)PumpConfigurationAndControl::Feature::kCompensatedPressure;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_min_comp_pressure(cluster, config->min_comp_pressure);
    attribute::create_max_comp_pressure(cluster, config->max_comp_pressure);

    return ESP_OK;
}
} /* compensated_pressure */

namespace constant_flow {

uint32_t get_id()
{
    return (uint32_t)PumpConfigurationAndControl::Feature::kConstantFlow;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_min_const_flow(cluster, config->min_const_flow);
    attribute::create_max_const_flow(cluster, config->max_const_flow);

    return ESP_OK;
}
} /* constant_flow */

namespace constant_speed {

uint32_t get_id()
{
    return (uint32_t)PumpConfigurationAndControl::Feature::kConstantSpeed;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_min_const_speed(cluster, config->min_const_speed);
    attribute::create_max_const_speed(cluster, config->max_const_speed);

    return ESP_OK;
}
} /* constant_speed */

namespace constant_temperature {

uint32_t get_id()
{
    return (uint32_t)PumpConfigurationAndControl::Feature::kConstantTemperature;
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    attribute::create_min_const_temp(cluster, config->min_const_temp);
    attribute::create_max_const_temp(cluster, config->max_const_temp);

    return ESP_OK;
}
} /* constant_temperature */

namespace automatic {

uint32_t get_id()
{
    return static_cast<uint32_t>(PumpConfigurationAndControl::Feature::kAutomatic);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    return ESP_OK;
}
} /* automatic */

namespace local_operation {

uint32_t get_id()
{
    return static_cast<uint32_t>(PumpConfigurationAndControl::Feature::kLocalOperation);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());
    return ESP_OK;
}
} /* local_operation */

} /* feature */
} /* pump_configuration_and_control */

namespace time_synchronization {
namespace feature {

namespace time_zone {
uint32_t get_id()
{
    return static_cast<uint32_t>(TimeSynchronization::Feature::kTimeZone);
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster || !config) {
        ESP_LOGE(TAG, "Cluster or config cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    // Attributes managed internally
    attribute::create_time_zone(cluster, nullptr, 0, 0);
    attribute::create_dst_offset(cluster, nullptr, 0, 0);
    attribute::create_local_time(cluster, nullable<uint64_t>());
    attribute::create_time_zone_list_max_size(cluster, 0);
    attribute::create_dst_offset_list_max_size(cluster, 0);

    // Attributes not managed internally
    attribute::create_time_zone_database(cluster, config->time_zone_database);

    // Commands
    command::create_set_time_zone(cluster);
    command::create_set_dst_offset(cluster);
    command::create_set_time_zone_response(cluster);

    // Events
    event::create_dst_table_empty(cluster);
    event::create_dst_status(cluster);
    event::create_time_zone_status(cluster);

    return ESP_OK;
}
} /* time_zone */

namespace ntp_client {
uint32_t get_id()
{
    return static_cast<uint32_t>(TimeSynchronization::Feature::kNTPClient);
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster || !config) {
        ESP_LOGE(TAG, "Cluster or config cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    // Attributes managed internally
    attribute::create_default_ntp(cluster, nullptr, 0);

    // Attributes not managed internally
    attribute::create_supports_dns_resolve(cluster, config->supports_dns_resolve);

    // Commands
    command::create_set_default_ntp(cluster);

    return ESP_OK;
}
} /* ntp_client */

namespace ntp_server {

uint32_t get_id()
{
    return static_cast<uint32_t>(TimeSynchronization::Feature::kNTPServer);
}

esp_err_t add(cluster_t *cluster, config_t *config)
{
    if (!cluster || !config) {
        ESP_LOGE(TAG, "Cluster or config cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    // Attributes not managed internally
    attribute::create_ntp_server_available(cluster, config->ntp_server_available);

    return ESP_OK;
}
} /* ntp_server */

namespace time_sync_client {
uint32_t get_id()
{
    return static_cast<uint32_t>(TimeSynchronization::Feature::kTimeSyncClient);
}

esp_err_t add(cluster_t *cluster)
{
    if (!cluster) {
        ESP_LOGE(TAG, "Cluster cannot be NULL");
        return ESP_ERR_INVALID_ARG;
    }
    update_feature_map(cluster, get_id());

    // Attributes managed internally
    attribute::create_trusted_time_source(cluster, nullptr, 0, 0);

    // Commands
    command::create_set_trusted_time_source(cluster);

    // Events
    event::create_missing_trusted_time_source(cluster);

    return ESP_OK;
}
} /* time_sync_client */

} /* feature */
} /* time_synchronization */

namespace camera_av_stream_management {

namespace feature {
namespace audio {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kAudio);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());

    attribute::create_microphone_capabilities(cluster, NULL, 0, 0);
    attribute::create_allocated_audio_streams(cluster, NULL, 0, 0);
    attribute::create_microphone_muted(cluster, 0);
    attribute::create_microphone_volume_level(cluster, 0);
    attribute::create_microphone_max_level(cluster, 0);
    attribute::create_microphone_min_level(cluster, 0);

    command::create_audio_stream_allocate(cluster);
    command::create_audio_stream_allocate_response(cluster);
    command::create_audio_stream_deallocate(cluster);

    return ESP_OK;
}

} /* audio */

namespace video {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kVideo);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    attribute::create_max_concurrent_encoders(cluster, 0);
    attribute::create_max_encoded_pixel_rate(cluster, 0);
    attribute::create_video_sensor_params(cluster, NULL, 0, 0);
    attribute::create_min_viewport_resolution(cluster, NULL, 0, 0);
    attribute::create_rate_distortion_trade_off_points(cluster, NULL, 0, 0);
    attribute::create_current_frame_rate(cluster, 0);
    attribute::create_allocated_video_streams(cluster, NULL, 0, 0);

    attribute::create_viewport(cluster, NULL, 0, 0);

    command::create_video_stream_allocate(cluster);
    command::create_video_stream_allocate_response(cluster);
    command::create_video_stream_deallocate(cluster);

    return ESP_OK;
}

} /* video */

namespace snapshot {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kSnapshot);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());

    attribute::create_snapshot_capabilities(cluster, NULL, 0, 0);
    attribute::create_allocated_snapshot_streams(cluster, NULL, 0, 0);
    attribute::create_local_snapshot_recording_enabled(cluster, 0);

    command::create_snapshot_stream_allocate(cluster);
    command::create_snapshot_stream_allocate_response(cluster);
    command::create_snapshot_stream_deallocate(cluster);
    command::create_capture_snapshot(cluster);
    command::create_capture_snapshot_response(cluster);

    return ESP_OK;
}

} /* snapshot */

namespace privacy {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kPrivacy);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    attribute::create_soft_recording_privacy_mode_enabled(cluster, 0);
    attribute::create_soft_livestream_privacy_mode_enabled(cluster, 0);

    return ESP_OK;
}

} /* privacy */

namespace speaker {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kSpeaker);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    attribute::create_speaker_capabilities(cluster, NULL, 0, 0);
    attribute::create_two_way_talk_support(cluster, 0);
    attribute::create_speaker_muted(cluster, 0);
    attribute::create_speaker_volume_level(cluster, 0);
    attribute::create_speaker_max_level(cluster, 0);
    attribute::create_speaker_min_level(cluster, 0);

    return ESP_OK;
}

} /* speaker */

namespace image_control {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kImageControl);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* image_control */

namespace watermark {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kWatermark);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    command::create_video_stream_modify(cluster);

    return ESP_OK;
}

} /* watermark */

namespace on_screen_display {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kOnScreenDisplay);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    command::create_video_stream_modify(cluster);
    return ESP_OK;
}
} /* on_screen_display */

namespace local_storage {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kLocalStorage);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    attribute::create_local_video_recording_enabled(cluster, 0);
    attribute::create_local_snapshot_recording_enabled(cluster, 0);

    return ESP_OK;
}

} /* local_storage */

namespace high_dynamic_range {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kHighDynamicRange);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    attribute::create_hdr_mode_enabled(cluster, 0);

    return ESP_OK;
}
} /* high_dynamic_range */

namespace night_vision {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvStreamManagement::Feature::kNightVision);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG);
    esp_matter::cluster::update_feature_map(cluster, get_id());
    attribute::create_night_vision_uses_infrared(cluster, 0);
    attribute::create_night_vision(cluster, 0);

    return ESP_OK;
}

} /* night_vision */

} /* feature */
} /* Camera AV Stream Management*/

namespace webrtc_transport_provider {
}/*webrtc_transport_provider*/

namespace webrtc_transport_requestor {
}/*webrtc_transport_requestor*/

namespace closure_control {
namespace feature {
namespace positioning {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kPositioning);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* positioning */

namespace motion_latching {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kMotionLatching);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    /* Attributes managed internally */
    attribute::create_latch_control_modes(cluster, 0);
    return ESP_OK;
}

} /* motion_latching */

namespace instantaneous {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kInstantaneous);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    command_t *stop_command = esp_matter::command::get(cluster, ClosureControl::Commands::Stop::Id, COMMAND_FLAG_ACCEPTED);
    if (stop_command) {
        esp_matter::command::destroy(cluster, stop_command);
    }
    event_t *movement_completed = esp_matter::event::get(cluster, ClosureControl::Events::MovementCompleted::Id);
    if (movement_completed) {
        esp_matter::event::destroy(cluster, movement_completed);
    }
    return ESP_OK;
}

} /* instantaneous */

namespace speed {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kSpeed);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* speed */

namespace ventilation {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kVentilation);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* ventilation */

namespace pedestrian {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kPedestrian);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* pedestrian */

namespace calibration {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kCalibration);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    command::create_calibrate(cluster);
    return ESP_OK;
}

} /* calibration */

namespace protection {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kProtection);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* protection */

namespace manually_operable {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureControl::Feature::kManuallyOperable);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Events
    event::create_engage_state_changed(cluster);
    return ESP_OK;
}

} /* manually_operable */

} /* feature */
} /* closure_control */

namespace closure_dimension {
namespace feature {
namespace positioning {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kPositioning);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_resolution(cluster, 0);
    attribute::create_step_value(cluster, 0);
    // Commands
    command::create_step(cluster);
    return ESP_OK;
}

} /* positioning */

namespace motion_latching {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kMotionLatching);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_latch_control_modes(cluster, 0);
    return ESP_OK;
}

} /* motion_latching */

namespace unit {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kUnit);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_unit(cluster, 0);
    attribute::create_unit_range(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* unit */

namespace limitation {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kLimitation);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_limit_range(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* limitation */

namespace speed {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kSpeed);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* speed */

namespace translation {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kTranslation);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_translation_direction(cluster, 0);
    return ESP_OK;
}

} /* translation */

namespace rotation {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kRotation);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_rotation_axis(cluster, 0);
    attribute::create_overflow(cluster, 0);
    return ESP_OK;
}

} /* rotation */

namespace modulation {

uint32_t get_id()
{
    return static_cast<uint32_t>(ClosureDimension::Feature::kModulation);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_modulation_type(cluster, 0);
    return ESP_OK;
}

} /* modulation */

} /* feature */
} /* closure_dimension */

namespace camera_av_settings_user_level_management {
namespace feature {
namespace digital_ptz {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvSettingsUserLevelManagement::Feature::kDigitalPTZ);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_dptz_streams(cluster, NULL, 0, 0);
    // Commands
    command::create_dptz_set_viewport(cluster);
    return ESP_OK;
}

} /* digital_ptz */

namespace mechanical_pan {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvSettingsUserLevelManagement::Feature::kMechanicalPan);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_mptz_position(cluster, NULL, 0, 0);
    attribute::create_pan_min(cluster, 0);
    attribute::create_pan_max(cluster, 0);
    attribute::create_movement_state(cluster, 0);
    // Commands
    command::create_mptz_set_position(cluster);
    command::create_mptz_relative_move(cluster);
    return ESP_OK;
}

} /* mechanical_pan */

namespace mechanical_tilt {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvSettingsUserLevelManagement::Feature::kMechanicalTilt);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_mptz_position(cluster, NULL, 0, 0);
    attribute::create_tilt_min(cluster, 0);
    attribute::create_tilt_max(cluster, 0);
    attribute::create_movement_state(cluster, 0);
    // Commands
    command::create_mptz_set_position(cluster);
    command::create_mptz_relative_move(cluster);
    return ESP_OK;
}

} /* mechanical_tilt */

namespace mechanical_zoom {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvSettingsUserLevelManagement::Feature::kMechanicalZoom);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_mptz_position(cluster, NULL, 0, 0);
    attribute::create_zoom_max(cluster, 0);
    attribute::create_movement_state(cluster, 0);
    // Commands
    command::create_mptz_set_position(cluster);
    command::create_mptz_relative_move(cluster);
    return ESP_OK;
}

} /* mechanical_zoom */

namespace mechanical_presets {

uint32_t get_id()
{
    return static_cast<uint32_t>(CameraAvSettingsUserLevelManagement::Feature::kMechanicalPresets);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_max_presets(cluster, 0);
    attribute::create_mptz_presets(cluster, NULL, 0, 0);
    // Commands
    command::create_mptz_move_to_preset(cluster);
    command::create_mptz_save_preset(cluster);
    command::create_mptz_remove_preset(cluster);
    return ESP_OK;
}

} /* mechanical_presets */

} /* feature */
} /* camera_av_settings_user_level_management */

namespace push_av_stream_transport {
namespace feature {
namespace per_zone_sensitivity {

uint32_t get_id()
{
    return static_cast<uint32_t>(PushAvStreamTransport::Feature::kPerZoneSensitivity);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* per_zone_sensitivity */

namespace metadata {

uint32_t get_id()
{
    return static_cast<uint32_t>(PushAvStreamTransport::Feature::kMetadata);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

}

} /* feature */
} /* push_av_stream_transport */

namespace commodity_tariff {
namespace feature {
namespace pricing {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityTariff::Feature::kPricing);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* pricing */

namespace friendly_credit {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityTariff::Feature::kFriendlyCredit);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* friendly_credit */

namespace auxiliary_load {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityTariff::Feature::kAuxiliaryLoad);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* auxiliary_load */

namespace peak_period {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityTariff::Feature::kPeakPeriod);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* peak_period */

namespace power_threshold {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityTariff::Feature::kPowerThreshold);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* power_threshold */

namespace randomization {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityTariff::Feature::kRandomization);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_default_randomization_offset(cluster, 0);
    attribute::create_default_randomization_type(cluster, 0);
    return ESP_OK;
}

} /* randomization */

} /* feature */
} /* commodity_tariff */

namespace commodity_price {
namespace feature {
namespace forecasting {

uint32_t get_id()
{
    return static_cast<uint32_t>(CommodityPrice::Feature::kForecasting);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_price_forecast(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* forecasting */

} /* feature */
} /* commodity_price */

namespace electrical_grid_conditions {
namespace feature {
namespace forecasting {

uint32_t get_id()
{
    return static_cast<uint32_t>(ElectricalGridConditions::Feature::kForecasting);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_forecast_conditions(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* forecasting */

} /* feature */
} /* electrical_grid_conditions */

namespace meter_identification {
namespace feature {
namespace power_threshold {

uint32_t get_id()
{
    return static_cast<uint32_t>(MeterIdentification::Feature::kPowerThreshold);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_power_threshold(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* power_threshold */

} /* feature */
} /* meter_identification */

namespace zone_management {
namespace feature {
namespace two_dimensional_cartesian_zone {

uint32_t get_id()
{
    return static_cast<uint32_t>(ZoneManagement::Feature::kTwoDimensionalCartesianZone);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_two_d_cartesian_max(cluster, NULL, 0, 0);
    return ESP_OK;
}

} /* two_dimensional_cartesian_zone */

namespace per_zone_sensitivity {

uint32_t get_id()
{
    return static_cast<uint32_t>(ZoneManagement::Feature::kPerZoneSensitivity);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());

    attribute_t *sensitivity = esp_matter::attribute::get(cluster, ZoneManagement::Attributes::Sensitivity::Id);
    if (sensitivity) {
        esp_matter::attribute::destroy(cluster, sensitivity);
    }
    return ESP_OK;
}

} /* per_zone_sensitivity */

namespace user_defined {

uint32_t get_id()
{
    return static_cast<uint32_t>(ZoneManagement::Feature::kUserDefined);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    // Attributes
    attribute::create_max_user_defined_zones(cluster, 0);
    // Commands
    command::create_remove_zone(cluster);
    if (get_feature_map_value(cluster) & feature::two_dimensional_cartesian_zone::get_id()) {
        command::create_two_d_cartesian_zone(cluster);
        command::create_two_d_cartesian_zone_response(cluster);
        command::create_update_two_d_cartesian_zone(cluster);
    }
    return ESP_OK;
}

} /* user_defined */

namespace focus_zones {

uint32_t get_id()
{
    return static_cast<uint32_t>(ZoneManagement::Feature::kFocusZones);
}

esp_err_t add(cluster_t *cluster)
{
    VerifyOrReturnError(cluster, ESP_ERR_INVALID_ARG, ESP_LOGE(TAG, "Cluster cannot be NULL"));
    update_feature_map(cluster, get_id());
    return ESP_OK;
}

} /* focus_zones */

} /* feature */
} /* zone_management */

} /* cluster */
} /* esp_matter */
