@@ -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, nullable) 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
@@ -2669,6 +2673,14 @@ - (void)_resetSubscription
2669
2673
[self.matterCPPObjectsHolder clearReadClientAndDeleteSubscriptionCallback];
2670
2674
2671
2675
[self _doHandleSubscriptionError:nil];
2676
+
2677
+ #ifdef DEBUG
2678
+ [self _callFirstDelegateSynchronouslyWithBlock:^(id testDelegate) {
2679
+ if ([testDelegate respondsToSelector:@selector(unitTestSubscriptionResetForDevice:)]) {
2680
+ [testDelegate unitTestSubscriptionResetForDevice:self];
2681
+ }
2682
+ }];
2683
+ #endif
2672
2684
}
2673
2685
2674
2686
#ifdef DEBUG
@@ -2774,6 +2786,10 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2774
2786
^(NSArray * value) {
2775
2787
mtr_strongify(self);
2776
2788
VerifyOrReturn(self, MTR_LOG_DEBUG("_setupSubscriptionWithReason subscription attribute report called back with nil MTRDevice"));
2789
+ {
2790
+ std::lock_guard lock(self->_lock);
2791
+ self.lastSubscriptionActiveTime = [NSDate now];
2792
+ }
2777
2793
2778
2794
MTR_LOG("%@ got attribute report (%p) %@", self, value, value);
2779
2795
dispatch_async(self.queue, ^{
@@ -2790,6 +2806,10 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2790
2806
^(NSArray * value) {
2791
2807
mtr_strongify(self);
2792
2808
VerifyOrReturn(self, MTR_LOG_DEBUG("_setupSubscriptionWithReason subscription event report called back with nil MTRDevice"));
2809
+ {
2810
+ std::lock_guard lock(self->_lock);
2811
+ self.lastSubscriptionActiveTime = [NSDate now];
2812
+ }
2793
2813
2794
2814
MTR_LOG("%@ got event report %@", self, value);
2795
2815
dispatch_async(self.queue, ^{
@@ -2822,6 +2842,7 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2822
2842
2823
2843
MTR_LOG("%@ got subscription established", self);
2824
2844
std::lock_guard lock(self->_lock);
2845
+ self.lastSubscriptionActiveTime = [NSDate now];
2825
2846
2826
2847
// First synchronously change state
2827
2848
if (HadSubscriptionEstablishedOnce(self->_internalDeviceState)) {
@@ -2866,6 +2887,10 @@ - (void)_setupSubscriptionWithReason:(NSString *)reason
2866
2887
^(void) {
2867
2888
mtr_strongify(self);
2868
2889
VerifyOrReturn(self, MTR_LOG_DEBUG("_setupSubscriptionWithReason subscription report begin called back with nil MTRDevice"));
2890
+ {
2891
+ std::lock_guard lock(self->_lock);
2892
+ self.lastSubscriptionActiveTime = [NSDate now];
2893
+ }
2869
2894
2870
2895
MTR_LOG("%@ got report begin", self);
2871
2896
[self _handleReportBegin];
@@ -4723,8 +4748,23 @@ - (BOOL)_deviceHasActiveSubscription
4723
4748
return HaveSubscriptionEstablishedRightNow(_internalDeviceState);
4724
4749
}
4725
4750
4751
+ // TODO: make this configurable - for now use 1.5 second
4752
+ #define MTRDEVICE_ACTIVE_COMMUNICATION_THRESHOLD_SECONDS (1.5)
4753
+
4726
4754
- (void)_deviceMayBeReachable
4727
4755
{
4756
+ // Ignore this call if actively receiving communication from this device
4757
+ {
4758
+ std::lock_guard lock(self->_lock);
4759
+ if (self.lastSubscriptionActiveTime) {
4760
+ NSTimeInterval intervalSinceDeviceLastActive = -[self.lastSubscriptionActiveTime timeIntervalSinceNow];
4761
+ if (intervalSinceDeviceLastActive < MTRDEVICE_ACTIVE_COMMUNICATION_THRESHOLD_SECONDS) {
4762
+ MTR_LOG("%@ _deviceMayBeReachable called and ignored, because last received communication from device %.6lf seconds ago", self, intervalSinceDeviceLastActive);
4763
+ return;
4764
+ }
4765
+ }
4766
+ }
4767
+
4728
4768
MTR_LOG("%@ _deviceMayBeReachable called, resetting subscription", self);
4729
4769
// TODO: This should only be allowed for thread devices
4730
4770
mtr_weakify(self);
0 commit comments