@@ -331,6 +331,9 @@ @interface MTRDevice_Concrete ()
331
331
332
332
@property (nonatomic) NSDate * estimatedStartTimeFromGeneralDiagnosticsUpTime;
333
333
334
+ @property (nonatomic) NSDate * lastDeviceBecameActiveCallbackTime;
335
+ @property (nonatomic) BOOL throttlingDeviceBecameActiveCallbacks;
336
+
334
337
/**
335
338
* If currentReadClient is non-null, that means that we successfully
336
339
* called SendAutoResubscribeRequest on the ReadClient and have not yet gotten
@@ -470,6 +473,7 @@ - (instancetype)initWithNodeID:(NSNumber *)nodeID controller:(MTRDeviceControlle
470
473
_persistedClusters = [NSMutableSet set];
471
474
_highestObservedEventNumber = nil;
472
475
_matterCPPObjectsHolder = [[MTRDeviceMatterCPPObjectsHolder alloc] init];
476
+ _throttlingDeviceBecameActiveCallbacks = NO;
473
477
474
478
// If there is a data store, make sure we have an observer to monitor system clock changes, so
475
479
// NSDate-based write coalescing could be reset and not get into a bad state.
@@ -864,6 +868,7 @@ - (void)_setDSTOffsets:(NSArray<MTRTimeSynchronizationClusterDSTOffsetStruct *>
864
868
// subscription intervals are in seconds
865
869
#define MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MIN (10 * 60) // 10 minutes (for now)
866
870
#define MTR_DEVICE_SUBSCRIPTION_MAX_INTERVAL_MAX (60 * 60) // 60 minutes
871
+ #define MTR_DEVICE_MIN_SECONDS_BETWEEN_DEVICE_BECAME_ACTIVE_CALLBACKS (1 * 60) // 1 minute (for now)
867
872
868
873
- (BOOL)_subscriptionsAllowed
869
874
{
@@ -1634,12 +1639,29 @@ - (void)_handleUnsolicitedMessageFromPublisher
1634
1639
1635
1640
[self _changeState:MTRDeviceStateReachable];
1636
1641
1637
- [self _callDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
1638
- if ([delegate respondsToSelector:@selector(deviceBecameActive:)]) {
1639
- [delegate deviceBecameActive:self];
1642
+ // Given the framework requests a minimum subscription keep alive time of devices, this callback is not expected to happen more often than that
1643
+ BOOL shouldCallDelegate = NO;
1644
+ if (self.lastDeviceBecameActiveCallbackTime) {
1645
+ NSTimeInterval intervalSinceLastCallback = -[self.lastDeviceBecameActiveCallbackTime timeIntervalSinceNow];
1646
+ if (intervalSinceLastCallback > MTR_DEVICE_MIN_SECONDS_BETWEEN_DEVICE_BECAME_ACTIVE_CALLBACKS) {
1647
+ shouldCallDelegate = YES;
1640
1648
}
1641
- }];
1642
- [self _notifyDelegateOfPrivateInternalPropertiesChanges];
1649
+ } else {
1650
+ shouldCallDelegate = YES;
1651
+ }
1652
+
1653
+ if (shouldCallDelegate) {
1654
+ [self _callDelegatesWithBlock:^(id<MTRDeviceDelegate> delegate) {
1655
+ if ([delegate respondsToSelector:@selector(deviceBecameActive:)]) {
1656
+ [delegate deviceBecameActive:self];
1657
+ }
1658
+ }];
1659
+ self.lastDeviceBecameActiveCallbackTime = [NSDate now];
1660
+ self.throttlingDeviceBecameActiveCallbacks = NO;
1661
+ } else if (!self.throttlingDeviceBecameActiveCallbacks) {
1662
+ MTR_LOG("%@ throttling deviceBecameActive callbacks because report came in too soon after %@", self, self.lastDeviceBecameActiveCallbackTime);
1663
+ self.throttlingDeviceBecameActiveCallbacks = YES;
1664
+ }
1643
1665
1644
1666
// in case this is called during exponential back off of subscription
1645
1667
// reestablishment, this starts the attempt right away
0 commit comments