Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plugwiseha] Improve cache and timeout handling #12345

Merged
merged 9 commits into from
Feb 22, 2022
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ public class PlugwiseHAController {

// Private member variables/constants

private static final int MAX_AGE_MINUTES_REFRESH = 10;
private static final int MAX_AGE_MINUTES_FULL_REFRESH = 30;
private static final int MAX_AGE_MINUTES_FULL_REFRESH = 15;
private static final DateTimeFormatter FORMAT = DateTimeFormatter.RFC_1123_DATE_TIME; // default Date format that
// will be used in conversion

Expand All @@ -68,18 +67,20 @@ public class PlugwiseHAController {
private final int port;
private final String username;
private final String smileId;
private final int maxAgeSecondsRefresh;

private @Nullable ZonedDateTime gatewayUpdateDateTime;
private @Nullable ZonedDateTime gatewayFullUpdateDateTime;
private @Nullable DomainObjects domainObjects;

public PlugwiseHAController(HttpClient httpClient, String host, int port, String username, String smileId)
throws PlugwiseHAException {
public PlugwiseHAController(HttpClient httpClient, String host, int port, String username, String smileId,
int maxAgeSecondsRefresh) throws PlugwiseHAException {
this.httpClient = httpClient;
this.host = host;
this.port = port;
this.username = username;
this.smileId = smileId;
this.maxAgeSecondsRefresh = maxAgeSecondsRefresh;

this.xStream = new PlugwiseHAXStream();

Expand Down Expand Up @@ -165,8 +166,12 @@ public Appliances getAppliances(Boolean forceRefresh) throws PlugwiseHAException
}
}

public @Nullable Appliance getAppliance(String id, Boolean forceRefresh) throws PlugwiseHAException {
Appliances appliances = this.getAppliances(forceRefresh);
public @Nullable Appliance getAppliance(String id) throws PlugwiseHAException {
Appliances appliances = this.getAppliances(false);
if (!appliances.containsKey(id)) {
appliances = this.getAppliances(true);
}

if (!appliances.containsKey(id)) {
this.logger.debug("Plugwise Home Automation Appliance with id {} is not known", id);
return null;
Expand Down Expand Up @@ -203,8 +208,11 @@ public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
}
}

public @Nullable Location getLocation(String id, Boolean forceRefresh) throws PlugwiseHAException {
Locations locations = this.getLocations(forceRefresh);
public @Nullable Location getLocation(String id) throws PlugwiseHAException {
Locations locations = this.getLocations(false);
if (!locations.containsKey(id)) {
locations = this.getLocations(true);
}

if (!locations.containsKey(id)) {
this.logger.debug("Plugwise Home Automation Zone with {} is not known", id);
Expand All @@ -221,25 +229,28 @@ public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {

request.setPath("/core/domain_objects");
request.addPathParameter("@locale", "en-US");

DomainObjects domainObjects = executeRequest(request);
this.gatewayUpdateDateTime = ZonedDateTime.parse(request.getServerDateTime(), PlugwiseHAController.FORMAT);
this.gatewayFullUpdateDateTime = this.gatewayUpdateDateTime;

ZonedDateTime serverTime = ZonedDateTime.parse(request.getServerDateTime(), PlugwiseHAController.FORMAT);
this.gatewayUpdateDateTime = serverTime;
this.gatewayFullUpdateDateTime = serverTime;

return mergeDomainObjects(domainObjects);
}

public @Nullable DomainObjects getUpdatedDomainObjects() throws PlugwiseHAException {
ZonedDateTime localGatewayUpdateDateTime = this.gatewayUpdateDateTime;
ZonedDateTime localGatewayFullUpdateDateTime = this.gatewayFullUpdateDateTime;
if (localGatewayUpdateDateTime == null
|| localGatewayUpdateDateTime.isBefore(ZonedDateTime.now().minusMinutes(MAX_AGE_MINUTES_REFRESH))) {

if (localGatewayUpdateDateTime == null || localGatewayFullUpdateDateTime == null) {
return getDomainObjects();
} else if (localGatewayFullUpdateDateTime == null || localGatewayFullUpdateDateTime
} else if (localGatewayUpdateDateTime.isBefore(ZonedDateTime.now().minusSeconds(maxAgeSecondsRefresh))) {
return getUpdatedDomainObjects(localGatewayUpdateDateTime);
} else if (localGatewayFullUpdateDateTime
.isBefore(ZonedDateTime.now().minusMinutes(MAX_AGE_MINUTES_FULL_REFRESH))) {
return getDomainObjects();
} else {
return getUpdatedDomainObjects(localGatewayUpdateDateTime);
return null;
}
}

Expand Down Expand Up @@ -428,6 +439,7 @@ private <T> T executeRequest(PlugwiseHAControllerRequest<T> request) throws Plug
private DomainObjects mergeDomainObjects(@Nullable DomainObjects updatedDomainObjects) {
DomainObjects localDomainObjects = this.domainObjects;
if (localDomainObjects == null && updatedDomainObjects != null) {
this.domainObjects = updatedDomainObjects;
return updatedDomainObjects;
} else if (localDomainObjects != null && updatedDomainObjects == null) {
return localDomainObjects;
Expand All @@ -442,6 +454,7 @@ private DomainObjects mergeDomainObjects(@Nullable DomainObjects updatedDomainOb
if (locations != null) {
localDomainObjects.mergeLocations(locations);
}
this.domainObjects = localDomainObjects;
return localDomainObjects;
} else {
return new DomainObjects();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@
* PlugwiseHAController}.
*
* @author B. van Wetten - Initial contribution
* @author Leo Siepel - Adjustments to timeout logic
*/
@NonNullByDefault
public class PlugwiseHAControllerRequest<T> {

private static final String CONTENT_TYPE_TEXT_XML = MimeTypes.Type.TEXT_XML_8859_1.toString();
private static final long TIMEOUT_SECONDS = 5;
private static final int REQUEST_MAX_RETRY_COUNT = 3;

private final Logger logger = LoggerFactory.getLogger(PlugwiseHAControllerRequest.class);
private final XStream xStream;
Expand Down Expand Up @@ -191,14 +193,7 @@ private String transformXML(String xml) throws PlugwiseHAException {

private String getContent() throws PlugwiseHAException {
String content;
ContentResponse response;

try {
response = getContentResponse();
} catch (PlugwiseHATimeoutException e) {
// Retry
response = getContentResponse();
}
ContentResponse response = getContentResponse(REQUEST_MAX_RETRY_COUNT);

int status = response.getStatus();
switch (status) {
Expand All @@ -224,18 +219,25 @@ private String getContent() throws PlugwiseHAException {
return content;
}

private ContentResponse getContentResponse() throws PlugwiseHAException {
private ContentResponse getContentResponse(int retries) throws PlugwiseHAException {
Request request = newRequest();
ContentResponse response;

if (logger.isTraceEnabled()) {
logger.trace(">> {} {}", request.getMethod(), request.getURI());
}
this.logger.debug("Performing API request: {} {}", request.getMethod(), request.getURI());

try {
response = request.send();
} catch (TimeoutException | InterruptedException e) {
} catch (InterruptedException e) {
this.logger.trace("InterruptedException occured {} {}", e.getMessage(), e.getStackTrace());
lsiepel marked this conversation as resolved.
Show resolved Hide resolved
Thread.currentThread().interrupt();
throw new PlugwiseHATimeoutException(e);
} catch (TimeoutException e) {
if (retries > 0) {
this.logger.debug("TimeoutException occured, remaining retries {}", retries - 1);
return getContentResponse(retries - 1);
} else {
throw new PlugwiseHATimeoutException(e);
}
} catch (ExecutionException e) {
// Unwrap the cause and try to cleanly handle it
Throwable cause = e.getCause();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,6 @@ public void merge(Map<String, Location> locations) {
updatedPointLogs.merge(originalLocation.getPointLogs());
}

ActuatorFunctionalities updatedActuatorFunctionalities = location.getActuatorFunctionalities();
if (updatedActuatorFunctionalities != null) {
updatedActuatorFunctionalities.merge(originalLocation.getActuatorFunctionalities());
}

this.put(id, location);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ protected synchronized void initialize(PlugwiseHAThingConfig config, PlugwiseHAB
try {
PlugwiseHAController controller = bridgeHandler.getController();
if (controller != null) {
this.appliance = getEntity(controller, true);
this.appliance = getEntity(controller);
Appliance localAppliance = this.appliance;
if (localAppliance != null) {
if (localAppliance.isBatteryOperated()) {
Expand All @@ -117,10 +117,9 @@ protected synchronized void initialize(PlugwiseHAThingConfig config, PlugwiseHAB
}

@Override
protected @Nullable Appliance getEntity(PlugwiseHAController controller, Boolean forceRefresh)
throws PlugwiseHAException {
protected @Nullable Appliance getEntity(PlugwiseHAController controller) throws PlugwiseHAException {
PlugwiseHAThingConfig config = getPlugwiseThingConfig();
Appliance appliance = controller.getAppliance(config.getId(), forceRefresh);
Appliance appliance = controller.getAppliance(config.getId());

return appliance;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,8 @@ public PlugwiseHABaseHandler(Thing thing) {
* Get the Plugwise Entity that belongs to this ThingHandler
*
* @param controller the controller for this ThingHandler
* @param forceRefresh indicated if the entity should be refreshed from the Plugwise API
*/
protected abstract @Nullable E getEntity(PlugwiseHAController controller, Boolean forceRefresh)
throws PlugwiseHAException;
protected abstract @Nullable E getEntity(PlugwiseHAController controller) throws PlugwiseHAException;

/**
* Handles a {@link RefreshType} command for a given channel.
Expand Down Expand Up @@ -139,7 +137,7 @@ public final void handleCommand(ChannelUID channelUID, Command command) {
if (controller != null) {
try {
@Nullable
E entity = getEntity(controller, false);
E entity = getEntity(controller);
if (entity != null) {
if (this.isLinked(channelUID)) {
if (command instanceof RefreshType) {
Expand Down Expand Up @@ -225,7 +223,7 @@ protected final void refresh() {
@Nullable
E entity = null;
try {
entity = getEntity(controller, false);
entity = getEntity(controller);
} catch (PlugwiseHAException e) {
updateStatus(OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
setLinkedChannelsUndef();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ public void initialize() {
logger.debug("Initializing the Plugwise Home Automation bridge handler with config = {}", bridgeConfig);
try {
this.controller = new PlugwiseHAController(httpClient, bridgeConfig.getHost(), bridgeConfig.getPort(),
bridgeConfig.getUsername(), bridgeConfig.getsmileId());
bridgeConfig.getUsername(), bridgeConfig.getsmileId(), bridgeConfig.getRefresh());
scheduleRefreshJob(bridgeConfig);
} catch (PlugwiseHAException e) {
updateStatus(OFFLINE, CONFIGURATION_ERROR, e.getMessage());
Expand Down Expand Up @@ -163,7 +163,7 @@ private void scheduleRefreshJob(PlugwiseHABridgeThingConfig bridgeConfig) {

private void run() {
try {
logger.trace("Executing refresh job");
this.logger.trace("Executing refresh job");
refresh();

if (super.thing.getStatus() == ThingStatus.INITIALIZING) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ protected synchronized void initialize(PlugwiseHAThingConfig config, PlugwiseHAB
try {
PlugwiseHAController controller = bridgeHandler.getController();
if (controller != null) {
this.location = getEntity(controller, true);
this.location = getEntity(controller);
if (this.location != null) {
setLocationProperties();
updateStatus(ONLINE);
Expand All @@ -103,10 +103,9 @@ protected synchronized void initialize(PlugwiseHAThingConfig config, PlugwiseHAB
}

@Override
protected @Nullable Location getEntity(PlugwiseHAController controller, Boolean forceRefresh)
throws PlugwiseHAException {
protected @Nullable Location getEntity(PlugwiseHAController controller) throws PlugwiseHAException {
PlugwiseHAThingConfig config = getPlugwiseThingConfig();
Location location = controller.getLocation(config.getId(), forceRefresh);
Location location = controller.getLocation(config.getId());

return location;
}
Expand Down