@@ -43,6 +43,7 @@ public abstract class BaseDevice<@NonNull T extends DeviceAddress, @NonNull S ex
43
43
implements Device {
44
44
private static final int DIRECT_ACK_TIMEOUT = 6000 ; // in milliseconds
45
45
private static final int REQUEST_QUEUE_TIMEOUT = 30000 ; // in milliseconds
46
+ private static final int FAILED_REQUEST_THRESHOLD = 5 ;
46
47
47
48
protected static enum DeviceStatus {
48
49
INITIALIZED ,
@@ -63,6 +64,7 @@ protected static enum DeviceStatus {
63
64
private Map <Msg , DeviceRequest > requestQueueHash = new HashMap <>();
64
65
private @ Nullable DeviceFeature featureQueried ;
65
66
private long pollInterval = -1L ; // in milliseconds
67
+ private volatile int failedRequestCount = 0 ;
66
68
private volatile long lastRequestQueued = 0L ;
67
69
private volatile long lastRequestSent = 0L ;
68
70
@@ -145,6 +147,10 @@ public boolean getFlag(String key, boolean def) {
145
147
}
146
148
}
147
149
150
+ public boolean isResponding () {
151
+ return failedRequestCount < FAILED_REQUEST_THRESHOLD ;
152
+ }
153
+
148
154
public void setModem (@ Nullable InsteonModem modem ) {
149
155
this .modem = modem ;
150
156
}
@@ -403,10 +409,8 @@ public void resetFeaturesQueryStatus() {
403
409
public void handleMessage (Msg msg ) {
404
410
getFeatures ().stream ().filter (feature -> feature .handleMessage (msg )).findFirst ().ifPresent (feature -> {
405
411
logger .trace ("handled reply of direct for {}" , feature .getName ());
406
- // mark feature queried as processed and answered
407
- setFeatureQueried (null );
408
- feature .setQueryMessage (null );
409
- feature .setQueryStatus (QueryStatus .QUERY_ANSWERED );
412
+ // notify feature queried was answered
413
+ featureQueriedAnswered (feature );
410
414
});
411
415
}
412
416
@@ -527,9 +531,8 @@ private long checkFeatureQueried(long now) {
527
531
return now + 1000L ; // retry in 1000 ms
528
532
}
529
533
logger .debug ("gave up waiting for {} query to be sent to {}" , feature .getName (), address );
530
- // reset feature queried as never queried
531
- feature .setQueryMessage (null );
532
- feature .setQueryStatus (QueryStatus .NEVER_QUERIED );
534
+ // notify feature queried failed
535
+ featureQueriedFailed (feature );
533
536
break ;
534
537
case QUERY_SENT :
535
538
case QUERY_ACKED :
@@ -541,20 +544,61 @@ private long checkFeatureQueried(long now) {
541
544
return now + 500L ; // retry in 500 ms
542
545
}
543
546
logger .debug ("gave up waiting for {} query reply from {}" , feature .getName (), address );
544
- // reset feature queried as never queried
545
- feature .setQueryMessage (null );
546
- feature .setQueryStatus (QueryStatus .NEVER_QUERIED );
547
+ // notify feature queried failed
548
+ featureQueriedFailed (feature );
547
549
break ;
548
550
default :
549
551
logger .debug ("unexpected feature {} query status {} for {}" , feature .getName (), queryStatus ,
550
552
address );
553
+ // reset feature queried
554
+ setFeatureQueried (null );
551
555
}
552
- // reset feature queried otheriwse
553
- setFeatureQueried (null );
554
556
}
555
557
return 0L ;
556
558
}
557
559
560
+ /**
561
+ * Notifies that the feature queried was answered
562
+ *
563
+ * @param feature the feature queried
564
+ */
565
+ protected void featureQueriedAnswered (DeviceFeature feature ) {
566
+ // store current failed request count
567
+ int prevCount = failedRequestCount ;
568
+ // reset failed request count
569
+ failedRequestCount = 0 ;
570
+ // mark feature queried as processed and answered
571
+ setFeatureQueried (null );
572
+ feature .setQueryMessage (null );
573
+ feature .setQueryStatus (QueryStatus .QUERY_ANSWERED );
574
+ // notify status changed if failed request count was above threshold
575
+ if (prevCount >= FAILED_REQUEST_THRESHOLD ) {
576
+ statusChanged ();
577
+ }
578
+ }
579
+
580
+ /**
581
+ * Notifies that the feature queried failed
582
+ *
583
+ * @param feature the feature queried
584
+ */
585
+ protected void featureQueriedFailed (DeviceFeature feature ) {
586
+ // increase failed request count
587
+ failedRequestCount ++;
588
+ // mark feature queried as processed and never queried
589
+ setFeatureQueried (null );
590
+ feature .setQueryMessage (null );
591
+ feature .setQueryStatus (QueryStatus .NEVER_QUERIED );
592
+ // poll feature again if device is responding
593
+ if (isResponding ()) {
594
+ feature .doPoll (0L );
595
+ }
596
+ // notify status changed if failed request count at threshold
597
+ if (failedRequestCount == FAILED_REQUEST_THRESHOLD ) {
598
+ statusChanged ();
599
+ }
600
+ }
601
+
558
602
/**
559
603
* Notifies that a message request was replied for this device
560
604
*
@@ -564,10 +608,17 @@ private long checkFeatureQueried(long now) {
564
608
public void requestReplied (Msg msg ) {
565
609
DeviceFeature feature = getFeatureQueried ();
566
610
if (feature != null && feature .isMyReply (msg )) {
567
- // mark feature queried as processed and answered
568
- setFeatureQueried (null );
569
- feature .setQueryMessage (null );
570
- feature .setQueryStatus (QueryStatus .QUERY_ANSWERED );
611
+ if (msg .isReplyNack ()) {
612
+ logger .debug ("got a reply nack msg: {}" , msg );
613
+ // notify feature queried failed
614
+ featureQueriedFailed (feature );
615
+ } else if (!msg .isInsteon ()) {
616
+ // notify feature queried was answered
617
+ featureQueriedAnswered (feature );
618
+ } else {
619
+ // mark feature queried as acked
620
+ feature .setQueryStatus (QueryStatus .QUERY_ACKED );
621
+ }
571
622
}
572
623
}
573
624
@@ -588,6 +639,18 @@ public void requestSent(Msg msg, long time) {
588
639
}
589
640
}
590
641
642
+ /**
643
+ * Notifies that the status has changed for this device
644
+ */
645
+ public void statusChanged () {
646
+ logger .trace ("status for {} has changed" , address );
647
+ @ Nullable
648
+ S handler = getHandler ();
649
+ if (handler != null ) {
650
+ handler .updateStatus ();
651
+ }
652
+ }
653
+
591
654
/**
592
655
* Refreshes this device
593
656
*/
0 commit comments