From 7138fd3867891f02aea8a812f9df14a2432ab311 Mon Sep 17 00:00:00 2001 From: Rohit Date: Mon, 14 Jul 2025 16:50:54 +0530 Subject: [PATCH] components/esp_matter: Support to get optional bits while initialisation of delegates. Fixes: https://github.com/espressif/esp-matter/issues/1471 --- .../data_model/esp_matter_data_model.cpp | 12 ++ .../data_model/esp_matter_data_model.h | 23 ++++ .../esp_matter_delegate_callbacks.cpp | 126 ++++++++++++++++-- .../electrical_measurement.cpp | 9 ++ .../electrical_measurement.h | 29 +++- .../main/esp_matter_console_helpers.cpp | 4 +- 6 files changed, 193 insertions(+), 10 deletions(-) diff --git a/components/esp_matter/data_model/esp_matter_data_model.cpp b/components/esp_matter/data_model/esp_matter_data_model.cpp index 5e7f7de13..754f85b21 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.cpp +++ b/components/esp_matter/data_model/esp_matter_data_model.cpp @@ -609,6 +609,18 @@ esp_err_t enable_all() } return ESP_OK; } + +bool is_attribute_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id) +{ + attribute_t *attr = attribute::get(endpoint_id, cluster_id, attribute_id); + return (attr != nullptr); +} + +bool is_command_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t command_id) +{ + command_t *cmd = command::get(endpoint_id, cluster_id, command_id); + return (cmd != nullptr); +} } /* endpoint */ namespace attribute { diff --git a/components/esp_matter/data_model/esp_matter_data_model.h b/components/esp_matter/data_model/esp_matter_data_model.h index 23dda252e..6917ad345 100644 --- a/components/esp_matter/data_model/esp_matter_data_model.h +++ b/components/esp_matter/data_model/esp_matter_data_model.h @@ -380,6 +380,29 @@ esp_err_t set_identify(uint16_t endpoint_id, void *identify); */ esp_err_t enable(endpoint_t *endpoint); +/** Check if attribute is enabled + * + * Check if the attribute of a cluster is enabled on an endpoint. + * + * @param[in] endpoint_id Endpoint id. + * @param[in] cluster_id Cluster id. + * @param[in] attribute_id Attribute id. + * + * @return true if an attribute is enabled otherwise false. + */ +bool is_attribute_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id); + +/** Check if command is enabled + * + * Check if the command of a cluster is enabled on an endpoint. + * + * @param[in] endpoint_id Endpoint id. + * @param[in] cluster_id Cluster id. + * @param[in] command_id Command id. + * + * @return true if a command is enabled otherwise false. + */ +bool is_command_enabled(uint16_t endpoint_id, uint32_t cluster_id, uint32_t command_id); } /* endpoint */ namespace cluster { diff --git a/components/esp_matter/data_model/esp_matter_delegate_callbacks.cpp b/components/esp_matter/data_model/esp_matter_delegate_callbacks.cpp index b2b27b355..beb0201f0 100644 --- a/components/esp_matter/data_model/esp_matter_delegate_callbacks.cpp +++ b/components/esp_matter/data_model/esp_matter_delegate_callbacks.cpp @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include @@ -60,11 +60,118 @@ static uint32_t get_feature_map_value(uint16_t endpoint_id, uint32_t cluster_id) uint32_t attribute_id = Globals::Attributes::FeatureMap::Id; attribute_t *attribute = attribute::get(endpoint_id, cluster_id, attribute_id); - esp_matter_attr_val_t val = esp_matter_invalid(NULL); + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); attribute::get_val(attribute, &val); return val.val.u32; } +// Cluster-specific optional attributes handlers +chip::BitMask get_energy_evse_enabled_optional_attributes(uint16_t endpoint_id) +{ + chip::BitMask optional_attrs = 0; + + if (endpoint::is_attribute_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Attributes::UserMaximumChargeCurrent::Id)) { + optional_attrs.Set(EnergyEvse::OptionalAttributes::kSupportsUserMaximumChargingCurrent); + } + + if (endpoint::is_attribute_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Attributes::RandomizationDelayWindow::Id)) { + optional_attrs.Set(EnergyEvse::OptionalAttributes::kSupportsRandomizationWindow); + } + + if (endpoint::is_attribute_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Attributes::ApproximateEVEfficiency::Id)) { + optional_attrs.Set(EnergyEvse::OptionalAttributes::kSupportsApproximateEvEfficiency); + } + + return optional_attrs; +} + +chip::BitMask get_power_topology_enabled_optional_attributes(uint16_t endpoint_id) +{ + chip::BitMask optional_attrs = 0; + + if (endpoint::is_attribute_enabled(endpoint_id, PowerTopology::Id, PowerTopology::Attributes::AvailableEndpoints::Id)) { + optional_attrs.Set(PowerTopology::OptionalAttributes::kOptionalAttributeAvailableEndpoints); + } + + if (endpoint::is_attribute_enabled(endpoint_id, PowerTopology::Id, PowerTopology::Attributes::ActiveEndpoints::Id)) { + optional_attrs.Set(PowerTopology::OptionalAttributes::kOptionalAttributeActiveEndpoints); + } + + return optional_attrs; +} + +chip::BitMask get_electrical_power_measurement_enabled_optional_attributes(uint16_t endpoint_id) +{ + chip::BitMask optional_attrs = 0; + + // Check for various optional attributes + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::Ranges::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRanges); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::Voltage::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeVoltage); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ActiveCurrent::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeActiveCurrent); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ReactiveCurrent::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactiveCurrent); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ApparentCurrent::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentCurrent); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ReactivePower::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeReactivePower); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::ApparentPower::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeApparentPower); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::RMSVoltage::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSVoltage); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::RMSCurrent::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSCurrent); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::RMSPower::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeRMSPower); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::Frequency::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeFrequency); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::PowerFactor::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributePowerFactor); + } + + if (endpoint::is_attribute_enabled(endpoint_id, ElectricalPowerMeasurement::Id, ElectricalPowerMeasurement::Attributes::NeutralCurrent::Id)) { + optional_attrs.Set(ElectricalPowerMeasurement::OptionalAttributes::kOptionalAttributeNeutralCurrent); + } + + return optional_attrs; +} + +// Cluster-specific optional commands handlers +chip::BitMask get_energy_evse_enabled_optional_commands(uint16_t endpoint_id) +{ + chip::BitMask optional_cmds = 0; + + if (endpoint::is_command_enabled(endpoint_id, EnergyEvse::Id, EnergyEvse::Commands::StartDiagnostics::Id)) { + optional_cmds.Set(EnergyEvse::OptionalCommands::kSupportsStartDiagnostics); + } + + return optional_cmds; +} + namespace delegate_cb { void InitModeDelegate(void *delegate, uint16_t endpoint_id, uint32_t cluster_id) @@ -140,8 +247,10 @@ void EnergyEvseDelegateInitCB(void *delegate, uint16_t endpoint_id) static EnergyEvse::Instance * energyEvseInstance = nullptr; EnergyEvse::Delegate *energy_evse_delegate = static_cast(delegate); uint32_t feature_map = get_feature_map_value(endpoint_id, EnergyEvse::Id); + chip::BitMask optional_attrs = get_energy_evse_enabled_optional_attributes(endpoint_id); + chip::BitMask optional_cmds = get_energy_evse_enabled_optional_commands(endpoint_id); energyEvseInstance = new EnergyEvse::Instance(endpoint_id, *energy_evse_delegate, chip::BitMask(feature_map), - chip::BitMask(), chip::BitMask()); + optional_attrs, optional_cmds); energyEvseInstance->Init(); } @@ -287,8 +396,9 @@ void PowerTopologyDelegateInitCB(void *delegate, uint16_t endpoint_id) static PowerTopology::Instance * powerTopologyInstance = nullptr; PowerTopology::Delegate *power_topology_delegate = static_cast(delegate); uint32_t feature_map = get_feature_map_value(endpoint_id, PowerTopology::Id); + chip::BitMask optional_attrs = get_power_topology_enabled_optional_attributes(endpoint_id); powerTopologyInstance = new PowerTopology::Instance(endpoint_id, *power_topology_delegate, chip::BitMask(feature_map), chip::BitMask(0)); + uint32_t>(feature_map), optional_attrs); powerTopologyInstance->Init(); } @@ -298,9 +408,9 @@ void ElectricalPowerMeasurementDelegateInitCB(void *delegate, uint16_t endpoint_ static ElectricalPowerMeasurement::Instance * electricalPowerMeasurementInstance = nullptr; ElectricalPowerMeasurement::Delegate *electrical_power_measurement_delegate = static_cast(delegate); uint32_t feature_map = get_feature_map_value(endpoint_id, ElectricalPowerMeasurement::Id); + chip::BitMask optional_attrs = get_electrical_power_measurement_enabled_optional_attributes(endpoint_id); electricalPowerMeasurementInstance = new ElectricalPowerMeasurement::Instance(endpoint_id, *electrical_power_measurement_delegate, - chip::BitMask(feature_map), - chip::BitMask(0)); + chip::BitMask(feature_map), optional_attrs); electricalPowerMeasurementInstance->Init(); } @@ -346,7 +456,7 @@ void ThreadBorderRouterManagementDelegateInitCB(void *delegate, uint16_t endpoin attribute_t *attribute = attribute::get(endpoint_id, ThreadBorderRouterManagement::Id, Globals::Attributes::FeatureMap::Id); assert(attribute != nullptr); /* Update the value if the attribute already exists */ - esp_matter_attr_val_t val = esp_matter_invalid(NULL); + esp_matter_attr_val_t val = esp_matter_invalid(nullptr); attribute::get_val(attribute, &val); bool pan_change_supported = (val.val.u32 & thread_border_router_management::feature::pan_change::get_id()) ? true : false; ThreadBorderRouterManagement::Delegate *thread_br_delegate = static_cast(delegate); @@ -358,7 +468,7 @@ void ThreadBorderRouterManagementDelegateInitCB(void *delegate, uint16_t endpoin void ServiceAreaDelegateInitCB(void *delegate, uint16_t endpoint_id) { - // TODO: This cluster have two delegates we need to update exsiting delegate logic to accomodate multiple delegates. + // TODO: This cluster has two delegates. We need to update existing delegate logic to accommodate multiple delegates. } void WaterHeaterManagementDelegateInitCB(void *delegate, uint16_t endpoint_id) diff --git a/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.cpp b/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.cpp index b6bf07b46..9e52a4c83 100644 --- a/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.cpp +++ b/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.cpp @@ -39,6 +39,15 @@ static std::unique_ptr gEPMDelegate; // Global pointer to our ElectricalPowerMeasurementInstance static std::unique_ptr gEPMInstance; +CHIP_ERROR PowerTopology::PowerTopologyDelegate::GetAvailableEndpointAtIndex(size_t index, EndpointId & endpointId) +{ + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; +} + +CHIP_ERROR PowerTopology::PowerTopologyDelegate::GetActiveEndpointAtIndex(size_t index, EndpointId & endpointId) +{ + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; +} // Example of how to create and send energy measurement events esp_err_t send_energy_measurement_events(uint16_t endpoint_id) { diff --git a/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.h b/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.h index ea1227a1a..a16004f1a 100644 --- a/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.h +++ b/examples/all_device_types_app/main/electrical_measurement/electrical_measurement.h @@ -45,6 +45,33 @@ esp_err_t send_energy_measurement_events(uint16_t endpoint_id); } #endif +#include + +using namespace chip; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::PowerTopology; + +namespace chip { +namespace app { +namespace Clusters { +namespace PowerTopology { + +class PowerTopologyDelegate : public Delegate +{ +public: + ~PowerTopologyDelegate() = default; + + CHIP_ERROR GetAvailableEndpointAtIndex(size_t index, EndpointId & endpointId) override; + CHIP_ERROR GetActiveEndpointAtIndex(size_t index, EndpointId & endpointId) override; +}; + + + +} // namespace PowerTopology +} // namespace Clusters +} // namespace app +} // namespace chip + /** * Electrical Power Measurement Delegate implementation */ @@ -162,4 +189,4 @@ private: } // namespace ElectricalPowerMeasurement } // namespace Clusters } // namespace app -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/examples/all_device_types_app/main/esp_matter_console_helpers.cpp b/examples/all_device_types_app/main/esp_matter_console_helpers.cpp index 2121cf494..1d11d6d9a 100644 --- a/examples/all_device_types_app/main/esp_matter_console_helpers.cpp +++ b/examples/all_device_types_app/main/esp_matter_console_helpers.cpp @@ -168,6 +168,7 @@ static void initialize_console(void) namespace esp_matter { +static chip::app::Clusters::PowerTopology::PowerTopologyDelegate powerTopologyDelegate; namespace data_model { int create(uint8_t device_type_index) @@ -454,7 +455,8 @@ int create(uint8_t device_type_index) } case ESP_MATTER_ELECTRICAL_SENSOR: { esp_matter::endpoint::electrical_sensor::config_t electrical_sensor_config; - electrical_sensor_config.power_topology.feature_flags = esp_matter::cluster::power_topology::feature::node_topology::get_id(); + electrical_sensor_config.power_topology.feature_flags = esp_matter::cluster::power_topology::feature::set_topology::get_id(); + electrical_sensor_config.power_topology.delegate = &powerTopologyDelegate; electrical_sensor_config.electrical_power_measurement.feature_flags = esp_matter::cluster::electrical_power_measurement::feature::direct_current::get_id() | esp_matter::cluster::electrical_power_measurement::feature::alternating_current::get_id();