@@ -336,6 +336,9 @@ @interface MTRDevice_Concrete ()
336
336
@property (nonatomic) NSDate * lastDeviceBecameActiveCallbackTime;
337
337
@property (nonatomic) BOOL throttlingDeviceBecameActiveCallbacks;
338
338
339
+ // Keep track of the last time we received subscription related communication from the device
340
+ @property (nonatomic) NSDate * lastSubscriptionActiveTime;
341
+
339
342
/**
340
343
* If currentReadClient is non-null, that means that we successfully
341
344
* called SendAutoResubscribeRequest on the ReadClient and have not yet gotten
@@ -360,6 +363,7 @@ - (void)unitTestSubscriptionPoolWorkComplete:(MTRDevice *)device;
360
363
- (void)unitTestClusterDataPersisted:(MTRDevice *)device;
361
364
- (BOOL)unitTestSuppressTimeBasedReachabilityChanges:(MTRDevice *)device;
362
365
- (void)unitTestSubscriptionCallbackDeleteForDevice:(MTRDevice *)device;
366
+ - (void)unitTestSubscriptionResetForDevice:(MTRDevice *)device;
363
367
@end
364
368
#endif
365
369
@@ -1697,6 +1701,7 @@ - (void)_handleReportBegin
1697
1701
assertChipStackLockedByCurrentThread();
1698
1702
1699
1703
std::lock_guard lock(_lock);
1704
+ self.lastSubscriptionActiveTime = [NSDate now];
1700
1705
1701
1706
_receivingReport = YES;
1702
1707
if (_state != MTRDeviceStateReachable) {
@@ -2669,6 +2674,14 @@ - (void)_resetSubscription
2669
2674
[self.matterCPPObjectsHolder clearReadClientAndDeleteSubscriptionCallback];
2670
2675
2671
2676
[self _doHandleSubscriptionError:nil];
2677
+
2678
+ #ifdef DEBUG
2679
+ [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) {
2680
+ if ([testDelegate respondsToSelector:@selector(unitTestSubscriptionResetForDevice:)]) {
2681
+ [testDelegate unitTestSubscriptionResetForDevice:self];
2682
+ }
2683
+ }];
2684
+ #endif
2672
2685
}
2673
2686
2674
2687
#ifdef DEBUG
@@ -2774,6 +2787,10 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2774
2787
^(NSArray * value) {
2775
2788
mtr_strongify(self);
2776
2789
VerifyOrReturn(self, MTR_LOG_DEBUG("_setupSubscriptionWithReason subscription attribute report called back with nil MTRDevice"));
2790
+ {
2791
+ std::lock_guard lock(self->_lock);
2792
+ self.lastSubscriptionActiveTime = [NSDate now];
2793
+ }
2777
2794
2778
2795
MTR_LOG("%@ got attribute report (%p) %@", self, value, value);
2779
2796
dispatch_async(self.queue, ^{
@@ -2790,6 +2807,10 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2790
2807
^(NSArray * value) {
2791
2808
mtr_strongify(self);
2792
2809
VerifyOrReturn(self, MTR_LOG_DEBUG("_setupSubscriptionWithReason subscription event report called back with nil MTRDevice"));
2810
+ {
2811
+ std::lock_guard lock(self->_lock);
2812
+ self.lastSubscriptionActiveTime = [NSDate now];
2813
+ }
2793
2814
2794
2815
MTR_LOG("%@ got event report %@", self, value);
2795
2816
dispatch_async(self.queue, ^{
@@ -2822,6 +2843,7 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2822
2843
2823
2844
MTR_LOG("%@ got subscription established", self);
2824
2845
std::lock_guard lock(self->_lock);
2846
+ self.lastSubscriptionActiveTime = [NSDate now];
2825
2847
2826
2848
// First synchronously change state
2827
2849
if (HadSubscriptionEstablishedOnce(self->_internalDeviceState)) {
@@ -4723,8 +4745,21 @@ - (BOOL)_deviceHasActiveSubscription
4723
4745
return HaveSubscriptionEstablishedRightNow(_internalDeviceState);
4724
4746
}
4725
4747
4748
+ // TODO: make this configurable - for now use 500ms or 0.5 seconds
4749
+ #define MTRDEVICE_ACTIVE_COMMUNICATION_THRESHOLD_SECONDS (0.5)
4750
+
4726
4751
- (void)_deviceMayBeReachable
4727
4752
{
4753
+ // Ignore this call if actively receiving communication from this device
4754
+ {
4755
+ std::lock_guard lock(self->_lock);
4756
+ NSTimeInterval intervalSinceDeviceLastActive = -[self.lastSubscriptionActiveTime timeIntervalSinceNow];
4757
+ if (intervalSinceDeviceLastActive < MTRDEVICE_ACTIVE_COMMUNICATION_THRESHOLD_SECONDS) {
4758
+ MTR_LOG("%@ _deviceMayBeReachable called and ignored, because last received communication from device %.6lf seconds ago", self, intervalSinceDeviceLastActive);
4759
+ return;
4760
+ }
4761
+ }
4762
+
4728
4763
MTR_LOG("%@ _deviceMayBeReachable called, resetting subscription", self);
4729
4764
// TODO: This should only be allowed for thread devices
4730
4765
mtr_weakify(self);
0 commit comments