[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 <opecta@gmail.com>
This commit is contained in:
parent
9bbcb85f59
commit
c0d66da660
|
@ -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_GRANT_ERROR = "Provided Authorization Grant is invalid.";
|
||||||
public static final String AUTHENTICATION_OAUTH_INVALID_GRANT = "error.invalid.grant";
|
public static final String AUTHENTICATION_OAUTH_INVALID_GRANT = "error.invalid.grant";
|
||||||
public static final String OPENHAB_TOKEN = "openHAB token";
|
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 RECONCILIATION_TIME = 600;
|
||||||
|
public static final int LOGIN_LIMIT_TIME = 60;
|
||||||
|
public static final int MAX_ERRORS = 5;
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
public static final String COMMAND_MY = "my";
|
public static final String COMMAND_MY = "my";
|
||||||
|
|
|
@ -19,6 +19,7 @@ import java.net.InetAddress;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -139,6 +140,12 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
|
||||||
// Cloud fallback
|
// Cloud fallback
|
||||||
private boolean cloudFallback = false;
|
private boolean cloudFallback = false;
|
||||||
|
|
||||||
|
// Communication errors counter
|
||||||
|
private int errorsCounter = 0;
|
||||||
|
|
||||||
|
// Last login timestamp
|
||||||
|
private Instant lastLoginTimestamp = Instant.MIN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Our configuration
|
* Our configuration
|
||||||
*/
|
*/
|
||||||
|
@ -240,8 +247,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tooManyRequests) {
|
if (tooManyRequests || Instant.now().minusSeconds(LOGIN_LIMIT_TIME).isBefore(lastLoginTimestamp)) {
|
||||||
logger.debug("Skipping login due to too many requests");
|
logger.debug("Postponing login to avoid throttling");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,6 +284,8 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
|
||||||
SomfyTahomaLoginResponse data = gson.fromJson(response.getContentAsString(),
|
SomfyTahomaLoginResponse data = gson.fromJson(response.getContentAsString(),
|
||||||
SomfyTahomaLoginResponse.class);
|
SomfyTahomaLoginResponse.class);
|
||||||
|
|
||||||
|
lastLoginTimestamp = Instant.now();
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
|
||||||
"Received invalid data (login)");
|
"Received invalid data (login)");
|
||||||
|
@ -844,7 +853,7 @@ public class SomfyTahomaBridgeHandler extends BaseBridgeHandler {
|
||||||
|
|
||||||
private Request sendRequestBuilderLocal(String subUrl, HttpMethod method) {
|
private Request sendRequestBuilderLocal(String subUrl, HttpMethod method) {
|
||||||
return httpClient.newRequest(getApiFullUrl(subUrl)).method(method).accept("application/json")
|
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);
|
response = sendDeleteToTahomaWithCookie(url);
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
errorsCounter = 0;
|
||||||
return classOfT != null ? gson.fromJson(response, classOfT) : null;
|
return classOfT != null ? gson.fromJson(response, classOfT) : null;
|
||||||
} catch (JsonSyntaxException e) {
|
} catch (JsonSyntaxException e) {
|
||||||
logger.debug("Received data: {} is not JSON", response, 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");
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, "Temporarily banned");
|
||||||
setTooManyRequests();
|
setTooManyRequests();
|
||||||
} else if (isEventListenerTimeout(e)) {
|
} else if (isEventListenerTimeout(e)) {
|
||||||
|
logger.debug("Event listener timeout occurred", e);
|
||||||
reLogin();
|
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 {
|
} else {
|
||||||
logger.debug("Cannot call url: {} with params: {}!", getApiFullUrl(url), urlParameters, e);
|
logger.debug("Cannot call url: {} with params: {}!", getApiFullUrl(url), urlParameters, e);
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||||
}
|
}
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
|
errorsCounter++;
|
||||||
logger.debug("Timeout when calling url: {} with params: {}!", getApiFullUrl(url), urlParameters, e);
|
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) {
|
} catch (InterruptedException e) {
|
||||||
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR);
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
|
|
Loading…
Reference in New Issue