From c0d66da660554f72337ec1a316907b223c0c73d4 Mon Sep 17 00:00:00 2001 From: Ondrej Pecta Date: Sat, 9 Sep 2023 12:43:08 +0200 Subject: [PATCH] [somfytahoma] Improvements to avoid cloud login throttling (#15489) * [somfytahoma] Improvements to avoid cloud login throttling * [somfytahoma] add custom message to status display --------- Signed-off-by: Ondrej Pecta --- .../internal/SomfyTahomaBindingConstants.java | 4 ++- .../handler/SomfyTahomaBridgeHandler.java | 31 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java index 81b36595f..30edae823 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/SomfyTahomaBindingConstants.java @@ -390,8 +390,10 @@ public class SomfyTahomaBindingConstants { public static final String AUTHENTICATION_OAUTH_GRANT_ERROR = "Provided Authorization Grant is invalid."; public static final String AUTHENTICATION_OAUTH_INVALID_GRANT = "error.invalid.grant"; public static final String OPENHAB_TOKEN = "openHAB token"; - public static final int SUSPEND_TIME = 120; + public static final int SUSPEND_TIME = 300; public static final int RECONCILIATION_TIME = 600; + public static final int LOGIN_LIMIT_TIME = 60; + public static final int MAX_ERRORS = 5; // Commands public static final String COMMAND_MY = "my"; diff --git a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java index 5c032aee6..664530bf9 100644 --- a/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java +++ b/bundles/org.openhab.binding.somfytahoma/src/main/java/org/openhab/binding/somfytahoma/internal/handler/SomfyTahomaBridgeHandler.java @@ -19,6 +19,7 @@ import java.net.InetAddress; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Duration; +import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -139,6 +140,12 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler { // Cloud fallback private boolean cloudFallback = false; + // Communication errors counter + private int errorsCounter = 0; + + // Last login timestamp + private Instant lastLoginTimestamp = Instant.MIN; + /** * Our configuration */ @@ -240,8 +247,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler { return; } - if (tooManyRequests) { - logger.debug("Skipping login due to too many requests"); + if (tooManyRequests || Instant.now().minusSeconds(LOGIN_LIMIT_TIME).isBefore(lastLoginTimestamp)) { + logger.debug("Postponing login to avoid throttling"); return; } @@ -277,6 +284,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler { SomfyTahomaLoginResponse data = gson.fromJson(response.getContentAsString(), SomfyTahomaLoginResponse.class); + lastLoginTimestamp = Instant.now(); + if (data == null) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Received invalid data (login)"); @@ -844,7 +853,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler { private Request sendRequestBuilderLocal(String subUrl, HttpMethod method) { return httpClient.newRequest(getApiFullUrl(subUrl)).method(method).accept("application/json") - .header(HttpHeader.AUTHORIZATION, "Bearer " + localToken); + .timeout(TAHOMA_TIMEOUT, TimeUnit.SECONDS).header(HttpHeader.AUTHORIZATION, "Bearer " + localToken); } /** @@ -1123,6 +1132,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler { response = sendDeleteToTahomaWithCookie(url); default: } + errorsCounter = 0; return classOfT != null ? gson.fromJson(response, classOfT) : null; } catch (JsonSyntaxException e) { logger.debug("Received data: {} is not JSON", response, e); @@ -1132,14 +1142,27 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Temporarily banned"); setTooManyRequests(); } else if (isEventListenerTimeout(e)) { + logger.debug("Event listener timeout occurred", e); reLogin(); + } else if (isDevModeReady()) { + // the local gateway is unreachable + errorsCounter++; + logger.debug("Local gateway communication error", e); + discoverGateway(); + if (errorsCounter > MAX_ERRORS) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, + "Too many communication errors"); + } } else { logger.debug("Cannot call url: {} with params: {}!", getApiFullUrl(url), urlParameters, e); updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); } } catch (TimeoutException e) { + errorsCounter++; logger.debug("Timeout when calling url: {} with params: {}!", getApiFullUrl(url), urlParameters, e); - updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); + if (errorsCounter > MAX_ERRORS) { + updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Too many timeouts"); + } } catch (InterruptedException e) { updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR); Thread.currentThread().interrupt();