diff --git a/src/darwin/Framework/CHIP/MTRDevice.mm b/src/darwin/Framework/CHIP/MTRDevice.mm index 5181b6ca5fdbfc..c176f7f80890ad 100644 --- a/src/darwin/Framework/CHIP/MTRDevice.mm +++ b/src/darwin/Framework/CHIP/MTRDevice.mm @@ -1163,12 +1163,16 @@ - (void)_reportAttributes:(NSArray *> *)attributes } } -- (void)_handleAttributeReport:(NSArray *> *)attributeReport -{ +- (void)_handleAttributeReport:(NSArray *> *)attributeReport fromSubscription:(BOOL)isFromSubscription { std::lock_guard lock(_lock); // _getAttributesToReportWithReportedValues will log attribute paths reported - [self _reportAttributes:[self _getAttributesToReportWithReportedValues:attributeReport]]; + [self _reportAttributes:[self _getAttributesToReportWithReportedValues:attributeReport fromSubscription:isFromSubscription]]; +} + +- (void)_handleAttributeReport:(NSArray *> *)attributeReport +{ + [self _handleAttributeReport:attributeReport fromSubscription:NO]; } #ifdef DEBUG @@ -1378,11 +1382,11 @@ - (MTRDeviceDataValueDictionary _Nullable)_cachedAttributeValueForPath:(MTRAttri return clusterData.attributes[path.attribute]; } -- (void)_setCachedAttributeValue:(MTRDeviceDataValueDictionary _Nullable)value forPath:(MTRAttributePath *)path +- (void)_setCachedAttributeValue:(MTRDeviceDataValueDictionary _Nullable)value forPath:(MTRAttributePath *)path fromSubscription:(BOOL)isFromSubscription { os_unfair_lock_assert_owner(&self->_lock); - // We need an actual MTRClusterPath, not a subsclass, to do _clusterDataForPath. + // We need an actual MTRClusterPath, not a subclass, to do _clusterDataForPath. auto * clusterPath = [MTRClusterPath clusterPathWithEndpointID:path.endpoint clusterID:path.cluster]; MTRDeviceClusterData * clusterData = [self _clusterDataForPath:clusterPath]; @@ -1396,6 +1400,16 @@ - (void)_setCachedAttributeValue:(MTRDeviceDataValueDictionary _Nullable)value f } [clusterData storeValue:value forAttribute:path.attribute]; + + if (value != nil + && isFromSubscription + && !_receivingPrimingReport + && AttributeHasChangesOmittedQuality(path)) { + // do not cache new values for Changes Omitted Quality attributes unless + // they're part of a Priming Report or from a read response. + // (removals are OK) + return; + } if (_clusterDataToPersist == nil) { _clusterDataToPersist = [NSMutableDictionary dictionary]; @@ -1521,7 +1535,7 @@ - (void)_setupSubscription MTR_LOG_INFO("%@ got attribute report %@", self, value); dispatch_async(self.queue, ^{ // OnAttributeData - [self _handleAttributeReport:value]; + [self _handleAttributeReport:value fromSubscription:YES]; #ifdef DEBUG self->_unitTestAttributesReportedSinceLastCheck += value.count; #endif @@ -2523,7 +2537,7 @@ - (BOOL)_attributeAffectsDeviceConfiguration:(MTRAttributePath *)attributePath } // assume lock is held -- (NSArray *)_getAttributesToReportWithReportedValues:(NSArray *> *)reportedAttributeValues +- (NSArray *)_getAttributesToReportWithReportedValues:(NSArray *> *)reportedAttributeValues fromSubscription:(BOOL)isFromSubscription { os_unfair_lock_assert_owner(&self->_lock); @@ -2557,7 +2571,7 @@ - (NSArray *)_getAttributesToReportWithReportedValues:(NSArray