2727#include < lib/core/DataModelTypes.h>
2828#include < app/clusters/identify-server/identify-server.h>
2929#include < app/util/endpoint-config-api.h>
30- #include " app/server/Server.h"
31- #include " credentials/GroupDataProviderImpl.h"
3230
3331#define ESP_MATTER_MAX_DEVICE_TYPE_COUNT CONFIG_ESP_MATTER_MAX_DEVICE_TYPE_COUNT
3432
@@ -42,6 +40,13 @@ using chip::kInvalidCommandId;
4240using chip::kInvalidClusterId ;
4341using chip::kInvalidEndpointId ;
4442
43+ // This is the hack to preserve and defer setting the temperature unit in the endpoint::enable()
44+ // we have an exception for this in attribute::create() to cache for later use in endpoint::enable()
45+ #ifdef CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
46+ #include < app/clusters/unit-localization-server/unit-localization-server.h>
47+ uint8_t g_temperature_unit = 0 ;
48+ #endif // CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
49+
4550namespace esp_matter {
4651struct _attribute_base_t {
4752 uint16_t flags; // This struct is for attributes managed internally.
@@ -529,6 +534,24 @@ esp_err_t enable(endpoint_t *endpoint)
529534 }
530535 ESP_LOGI (TAG, " Dynamic endpoint %" PRIu16 " added" , current_endpoint->endpoint_id );
531536
537+
538+ #ifdef CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
539+ // set the temperature unit from unit localization cluster
540+ {
541+ using namespace ::chip::app::Clusters;
542+ attribute_t *temperature_unit_attr = attribute::get (current_endpoint->endpoint_id ,
543+ UnitLocalization::Id,
544+ UnitLocalization::Attributes::TemperatureUnit::Id);
545+ if (temperature_unit_attr) {
546+ auto temp_unit = static_cast <UnitLocalization::TempUnitEnum>(g_temperature_unit);
547+ CHIP_ERROR chip_err = UnitLocalization::UnitLocalizationServer::Instance ().SetTemperatureUnit (temp_unit);
548+ if (chip_err != CHIP_NO_ERROR) {
549+ ESP_LOGW (TAG, " Failed to set temperature unit, err:%" CHIP_ERROR_FORMAT, chip_err.Format ());
550+ }
551+ }
552+ }
553+ #endif // CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
554+
532555 return err;
533556
534557cleanup:
@@ -684,6 +707,15 @@ attribute_t *create(cluster_t *cluster, uint32_t attribute_id, uint16_t flags, e
684707
685708 /* Add */
686709 SinglyLinkedList<_attribute_base_t >::append (¤t_cluster->attribute_list , attribute);
710+
711+ // this is an exception to keep the sdk experience same as before v1.4.2 release
712+ #ifdef CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
713+ if (cluster::get_id (cluster) == chip::app::Clusters::UnitLocalization::Id &&
714+ attribute_id == chip::app::Clusters::UnitLocalization::Attributes::TemperatureUnit::Id) {
715+ g_temperature_unit = val.val .u8 ;
716+ }
717+ #endif // CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
718+
687719 return (attribute_t *)attribute;
688720}
689721
@@ -774,11 +806,131 @@ static void deferred_attribute_write(chip::System::Layer *layer, void *attribute
774806 current_attribute->val );
775807}
776808
809+ // This is pure hack to not-break the sdk experience with v1.4.2 release
810+ // Some attributes were moved from external storage to internal storage and the set_val/get_val APIs
811+ // silently broke the application layer. This is a hack to not-break the sdk experience with v1.4.2 release
812+ namespace {
813+
814+ using namespace ::chip::app::Clusters;
815+ using namespace ::chip::app::Clusters::UnitLocalization;
816+
817+ // Helper function to find the cluster_id and attribute_id for internally managed attributes
818+ esp_err_t find_cluster_and_endpoint_id_for_internally_managed_attribute (_attribute_base_t *attribute_base,
819+ uint16_t *endpoint_id, uint32_t *cluster_id)
820+ {
821+ _node_t *node = (_node_t *)node::get ();
822+ if (!node) {
823+ return ESP_ERR_INVALID_STATE;
824+ }
825+
826+ for (_endpoint_t *endpoint = node->endpoint_list ; endpoint != nullptr ; endpoint = endpoint->next ) {
827+ for (_cluster_t *cluster = endpoint->cluster_list ; cluster != nullptr ; cluster = cluster->next ) {
828+ for (_attribute_base_t *attr = cluster->attribute_list ; attr != nullptr ; attr = attr->next ) {
829+ if (attr == attribute_base) {
830+ *endpoint_id = endpoint->endpoint_id ;
831+ *cluster_id = cluster::get_id ((cluster_t *)cluster);
832+ return ESP_OK;
833+ }
834+ }
835+ }
836+ }
837+
838+ return ESP_ERR_NOT_FOUND;
839+ }
840+
841+ std::optional<esp_err_t > get_val_with_compatibility_exceptions (_attribute_t *attribute,
842+ esp_matter_attr_val_t *val)
843+ {
844+ uint32_t cluster_id = kInvalidClusterId ;
845+ uint16_t endpoint_id = kInvalidEndpointId ;
846+
847+ if (!(attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY)) {
848+ // For non-internally-managed attributes, we can get cluster_id and endpoint_id directly
849+ cluster_id = attribute->cluster_id ;
850+ endpoint_id = attribute->endpoint_id ;
851+ } else {
852+ esp_err_t err = find_cluster_and_endpoint_id_for_internally_managed_attribute (attribute, &endpoint_id, &cluster_id);
853+ VerifyOrReturnError (err == ESP_OK, err,
854+ ESP_LOGE (TAG, " Failed to find cluster_id and endpoint_id for internally managed attribute" ));
855+ }
856+
857+ switch (cluster_id) {
858+ #ifdef CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
859+ case UnitLocalization::Id: {
860+ switch (attribute->attribute_id ) {
861+ case Attributes::TemperatureUnit::Id: {
862+ lock::status_t lock_status = lock::chip_stack_lock (portMAX_DELAY);
863+ if (lock_status != lock::SUCCESS) {
864+ return ESP_ERR_INVALID_STATE;
865+ }
866+ auto temperature_unit = UnitLocalizationServer::Instance ().GetTemperatureUnit ();
867+ lock::chip_stack_unlock ();
868+ esp_matter_attr_val_t read_val = esp_matter_enum8 (static_cast <uint8_t >(temperature_unit));
869+ *val = read_val;
870+ return ESP_OK;
871+ }
872+ }
873+ }
874+ #endif // CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
875+ }
876+
877+ return std::nullopt ;
878+ }
879+
880+ std::optional<esp_err_t > set_val_with_compatibility_exceptions (_attribute_t *attribute,
881+ esp_matter_attr_val_t *val)
882+ {
883+ uint32_t cluster_id = kInvalidClusterId ;
884+ uint16_t endpoint_id = kInvalidEndpointId ;
885+
886+ if (!(attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY)) {
887+ // For non-internally-managed attributes, we can get cluster_id and endpoint_id directly
888+ cluster_id = attribute->cluster_id ;
889+ endpoint_id = attribute->endpoint_id ;
890+ } else {
891+ esp_err_t err = find_cluster_and_endpoint_id_for_internally_managed_attribute (attribute, &endpoint_id, &cluster_id);
892+ VerifyOrReturnError (err == ESP_OK, err,
893+ ESP_LOGE (TAG, " Failed to find cluster_id and endpoint_id for internally managed attribute" ));
894+ }
895+
896+ switch (cluster_id) {
897+ #ifdef CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
898+
899+ case UnitLocalization::Id: {
900+ switch (attribute->attribute_id ) {
901+ case Attributes::TemperatureUnit::Id: {
902+ auto temp_unit = static_cast <TempUnitEnum>(val->val .u8 );
903+ lock::status_t lock_status = lock::chip_stack_lock (portMAX_DELAY);
904+ if (lock_status != lock::SUCCESS) {
905+ return ESP_ERR_INVALID_STATE;
906+ }
907+ CHIP_ERROR chip_err = UnitLocalizationServer::Instance ().SetTemperatureUnit (temp_unit);
908+ lock::chip_stack_unlock ();
909+ if (chip_err != CHIP_NO_ERROR) {
910+ ESP_LOGE (TAG, " Failed to set temperature unit, err:%" CHIP_ERROR_FORMAT, chip_err.Format ());
911+ return ESP_FAIL;
912+ }
913+ return ESP_OK;
914+ }
915+ }
916+ }
917+ #endif // CONFIG_SUPPORT_UNIT_LOCALIZATION_CLUSTER
918+ }
919+
920+ return std::nullopt ;
921+ }
922+ } // anonymous namespace
923+
777924esp_err_t set_val (attribute_t *attribute, esp_matter_attr_val_t *val)
778925{
779926 VerifyOrReturnError (attribute, ESP_FAIL, ESP_LOGE (TAG, " Attribute cannot be NULL" ));
780927 _attribute_t *current_attribute = (_attribute_t *)attribute;
781928
929+ auto err = set_val_with_compatibility_exceptions (current_attribute, val);
930+ if (err.has_value ()) {
931+ return err.value ();
932+ }
933+
782934 ESP_RETURN_ON_FALSE (!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), ESP_ERR_NOT_SUPPORTED, TAG,
783935 " Attribute is not managed by esp matter data model" );
784936
@@ -825,6 +977,11 @@ esp_err_t get_val(attribute_t *attribute, esp_matter_attr_val_t *val)
825977 VerifyOrReturnError (attribute, ESP_ERR_INVALID_ARG, ESP_LOGE (TAG, " Attribute cannot be NULL" ));
826978 _attribute_t *current_attribute = (_attribute_t *)attribute;
827979
980+ auto err = get_val_with_compatibility_exceptions (current_attribute, val);
981+ if (err.has_value ()) {
982+ return err.value ();
983+ }
984+
828985 ESP_RETURN_ON_FALSE (!(current_attribute->flags & ATTRIBUTE_FLAG_MANAGED_INTERNALLY), ESP_ERR_NOT_SUPPORTED, TAG,
829986 " Attribute is not managed by esp matter data model" );
830987 memcpy ((void *)val, (void *)¤t_attribute->val , sizeof (esp_matter_attr_val_t ));
0 commit comments