]> git.basschouten.com Git - openhab-addons.git/commitdiff
[hydrawise] Handle API auth changes (#16221)
authorDan Cunningham <dan@digitaldan.com>
Sun, 7 Jan 2024 13:39:38 +0000 (05:39 -0800)
committerGitHub <noreply@github.com>
Sun, 7 Jan 2024 13:39:38 +0000 (14:39 +0100)
* Handles a new condition where the service rejects a request as unauthorized, but really we just need to refresh our token after 60 seconds.

Signed-off-by: Dan Cunningham <dan@digitaldan.com>
bundles/org.openhab.binding.hydrawise/src/main/java/org/openhab/binding/hydrawise/internal/api/graphql/HydrawiseGraphQLClient.java
bundles/org.openhab.binding.hydrawise/src/main/java/org/openhab/binding/hydrawise/internal/handler/HydrawiseAccountHandler.java

index 7a8ada52f4d435031937bbd073ec3736838a189e..381d78000ebe0056a5543526bec54a5fa910807c 100644 (file)
@@ -324,6 +324,8 @@ public class HydrawiseGraphQLClient {
         } catch (ExecutionException e) {
             // Hydrawise returns back a 40x status, but without a valid Realm , so jetty throws an exception,
             // this allows us to catch this in a callback and handle accordingly
+            logger.debug("ExecutionException", e);
+            logger.debug("ExecutionException {} {}", responseCode.get(), responseMessage);
             switch (responseCode.get()) {
                 case 401:
                 case 403:
index a846c892e2421b13dd67d41d43f22c2734df1f76..548efe5d0263b0e3219c3b649b473f73588dd467 100644 (file)
@@ -62,6 +62,7 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
      * Minimum amount of time we can poll for updates
      */
     private static final int MIN_REFRESH_SECONDS = 30;
+    private static final int TOKEN_REFRESH_SECONDS = 60;
     private static final String BASE_URL = "https://app.hydrawise.com/api/v2/";
     private static final String AUTH_URL = BASE_URL + "oauth/access-token";
     private static final String CLIENT_SECRET = "zn3CrjglwNV1";
@@ -74,6 +75,7 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
     private @Nullable OAuthClientService oAuthService;
     private @Nullable HydrawiseGraphQLClient apiClient;
     private @Nullable ScheduledFuture<?> pollFuture;
+    private @Nullable ScheduledFuture<?> tokenFuture;
     private @Nullable Customer lastData;
     private int refresh;
 
@@ -102,6 +104,7 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
     public void dispose() {
         logger.debug("Handler disposed.");
         clearPolling();
+        clearTokenRefresh();
         OAuthClientService oAuthService = this.oAuthService;
         if (oAuthService != null) {
             oAuthService.removeAccessTokenRefreshListener(this);
@@ -184,20 +187,40 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
         pollFuture = scheduler.scheduleWithFixedDelay(this::poll, initalDelay, refresh, TimeUnit.SECONDS);
     }
 
+    /**
+     * The API will randomly reject a request with a 401 not authorized, waiting a min and refreshing the token usually
+     * fixes it
+     */
+    private synchronized void retryToken() {
+        clearTokenRefresh();
+        tokenFuture = scheduler.schedule(() -> {
+            try {
+                OAuthClientService oAuthService = this.oAuthService;
+                if (oAuthService != null) {
+                    oAuthService.refreshToken();
+                    initPolling(0, MIN_REFRESH_SECONDS);
+                }
+            } catch (OAuthException | IOException | OAuthResponseException e) {
+                updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
+            }
+        }, TOKEN_REFRESH_SECONDS, TimeUnit.SECONDS);
+    }
+
     /**
      * Stops/clears this thing's polling future
      */
     private void clearPolling() {
-        ScheduledFuture<?> localFuture = pollFuture;
-        if (isFutureValid(localFuture)) {
-            if (localFuture != null) {
-                localFuture.cancel(false);
-            }
-        }
+        clearFuture(pollFuture);
     }
 
-    private boolean isFutureValid(@Nullable ScheduledFuture<?> future) {
-        return future != null && !future.isCancelled();
+    private void clearTokenRefresh() {
+        clearFuture(tokenFuture);
+    }
+
+    private void clearFuture(@Nullable final ScheduledFuture<?> future) {
+        if (future != null) {
+            future.cancel(true);
+        }
     }
 
     private void poll() {
@@ -232,8 +255,10 @@ public class HydrawiseAccountHandler extends BaseBridgeHandler implements Access
                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
             }
         } catch (HydrawiseAuthenticationException e) {
-            updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
+            logger.debug("Token has been rejected, will try to refresh token in {} secs: {}", TOKEN_REFRESH_SECONDS,
+                    e.getLocalizedMessage());
             clearPolling();
+            retryToken();
         }
     }
 }