Skip to content

Commit 498a96b

Browse files
committed
Merge branch 'compat-fixes-1-4-2' into 'release/v1.4.2'
[v1.4.2] compatibility fixes for air quality and temperature unit attributes See merge request app-frameworks/esp-matter!1276
2 parents 694c19b + 0fea830 commit 498a96b

File tree

5 files changed

+197
-7
lines changed

5 files changed

+197
-7
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# List of attributes where we did not add the ATTRIBUTE_FLAG_MANAGED_INTERNALLY.
2+
# These are mostly the cases where AAI is not registered for the cluster and
3+
# attribute is of primitive type.
4+
AttributesWithOverridenManagedInternallyFlag:
5+
0x005B:
6+
name: AirQuality
7+
attributes:
8+
0x0000: AirQuality
9+
0x0201:
10+
name: Thermostat
11+
attributes:
12+
0x0000: LocalTemperature
13+
0x001A: RemoteSensing
14+
15+
# List of attributes that have get_val/set_val extentions which reads the attributes
16+
# using the connectedhomeip APIs and populate the esp_matter_attr_val_t.
17+
AttributesWithSetterGetterAPIExceptions:
18+
0x002D:
19+
name: UnitLocalization
20+
attributes:
21+
0x0000: TemperatureUnit

components/esp_matter/data_model/esp_matter_attribute.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1946,7 +1946,7 @@ namespace attribute {
19461946

19471947
attribute_t *create_local_temperature(cluster_t *cluster, nullable<int16_t> value)
19481948
{
1949-
return esp_matter::attribute::create(cluster, Thermostat::Attributes::LocalTemperature::Id, ATTRIBUTE_FLAG_NULLABLE | ATTRIBUTE_FLAG_MANAGED_INTERNALLY,
1949+
return esp_matter::attribute::create(cluster, Thermostat::Attributes::LocalTemperature::Id, ATTRIBUTE_FLAG_NULLABLE,
19501950
esp_matter_nullable_int16(value));
19511951
}
19521952

@@ -2067,7 +2067,7 @@ attribute_t *create_min_setpoint_dead_band(cluster_t *cluster, int8_t value)
20672067
attribute_t *create_remote_sensing(cluster_t *cluster, uint8_t value)
20682068
{
20692069
return esp_matter::attribute::create(cluster, Thermostat::Attributes::RemoteSensing::Id,
2070-
ATTRIBUTE_FLAG_NONVOLATILE | ATTRIBUTE_FLAG_WRITABLE | ATTRIBUTE_FLAG_MANAGED_INTERNALLY, esp_matter_bitmap8(value));
2070+
ATTRIBUTE_FLAG_NONVOLATILE | ATTRIBUTE_FLAG_WRITABLE, esp_matter_bitmap8(value));
20712071
}
20722072

20732073
attribute_t *create_control_sequence_of_operation(cluster_t *cluster, uint8_t value)
@@ -2347,7 +2347,13 @@ namespace attribute {
23472347

23482348
attribute_t *create_air_quality(cluster_t *cluster, uint8_t value)
23492349
{
2350-
return esp_matter::attribute::create(cluster, AirQuality::Attributes::AirQuality::Id, ATTRIBUTE_FLAG_MANAGED_INTERNALLY,
2350+
// Storage of this attribute was moved from esp-matter to connectedhomeip during the v1.4.2 release by
2351+
// implementing the AAI in connectedhomeip.
2352+
// For most clusters, AAI registration occurs in the cluster-init callback, but for this cluster,
2353+
// it is delegated to the application layer. So, in the esp-matter's workflow, no one registers the AAI.
2354+
// And, as this attribute is of primitive type, we can discard the ATTRIBUTE_FLAG_MANAGED_INTERNALLY flag
2355+
// and storage can be managed by esp-matter.
2356+
return esp_matter::attribute::create(cluster, AirQuality::Attributes::AirQuality::Id, ATTRIBUTE_FLAG_NONE,
23512357
esp_matter_enum8(value));
23522358
}
23532359

components/esp_matter/data_model/esp_matter_cluster.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,9 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags)
784784
VerifyOrReturnValue(cluster, NULL, ESP_LOGE(TAG, "Could not create cluster. cluster_id: 0x%08" PRIX32, UnitLocalization::Id));
785785

786786
if (flags & CLUSTER_FLAG_SERVER) {
787+
788+
static const auto plugin_server_init_cb = CALL_ONCE(MatterUnitLocalizationPluginServerInitCallback);
789+
set_plugin_server_init_callback(cluster, plugin_server_init_cb);
787790
add_function_list(cluster, function_list, function_flags);
788791

789792
/* Attributes managed internally */
@@ -1403,7 +1406,7 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags)
14031406
/* Attributes managed internally */
14041407
global::attribute::create_feature_map(cluster, 0);
14051408

1406-
attribute::create_air_quality(cluster, 0);
1409+
attribute::create_air_quality(cluster, config->air_quality);
14071410

14081411
/* Attributes not managed internally */
14091412
global::attribute::create_cluster_revision(cluster, cluster_revision);

components/esp_matter/data_model/esp_matter_cluster.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,10 @@ cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags);
354354
} /* thermostat_user_interface_configuration */
355355

356356
namespace air_quality {
357-
using config_t = common::config_t;
357+
typedef struct config {
358+
uint8_t air_quality;
359+
config() : air_quality(0) {}
360+
} config_t;
358361

359362
cluster_t *create(endpoint_t *endpoint, config_t *config, uint8_t flags);
360363
} /* air_quality */

components/esp_matter/data_model/esp_matter_data_model.cpp

Lines changed: 159 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,6 @@
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;
4240
using chip::kInvalidClusterId;
4341
using 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+
4550
namespace esp_matter {
4651
struct _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

534557
cleanup:
@@ -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(&current_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+
777924
esp_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 *)&current_attribute->val, sizeof(esp_matter_attr_val_t));

0 commit comments

Comments
 (0)