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 connection stability #17677

Merged
merged 6 commits into from
Nov 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,13 @@ public void start(Runnable callback) throws PlugwiseHAException {
callback.run();
}

/**
* Refreshes all changed objects. Will result in a call to the remote service.
*
* @throws PlugwiseHAException
*/
public void refresh() throws PlugwiseHAException {
synchronized (this) {
this.getUpdatedDomainObjects();
}
domainObjects = this.getUpdatedDomainObjects();
}

// Public API methods
Expand All @@ -113,7 +116,7 @@ public GatewayInfo getGatewayInfo() throws PlugwiseHAException {
return getGatewayInfo(false);
}

public GatewayInfo getGatewayInfo(Boolean forceRefresh) throws PlugwiseHAException {
private synchronized GatewayInfo getGatewayInfo(Boolean forceRefresh) throws PlugwiseHAException {
GatewayInfo gatewayInfo = null;
DomainObjects localDomainObjects = this.domainObjects;
if (localDomainObjects != null) {
Expand All @@ -133,12 +136,12 @@ public GatewayInfo getGatewayInfo(Boolean forceRefresh) throws PlugwiseHAExcepti

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

return mergeDomainObjects(domainObjects).getGatewayInfo();
domainObjects = mergeDomainObjects(domainObjects);
return domainObjects.getGatewayInfo();
}
}

public Appliances getAppliances(Boolean forceRefresh) throws PlugwiseHAException {
private synchronized Appliances getAppliances(Boolean forceRefresh) throws PlugwiseHAException {
Appliances appliances = null;
DomainObjects localDomainObjects = this.domainObjects;
if (localDomainObjects != null) {
Expand Down Expand Up @@ -167,6 +170,13 @@ public Appliances getAppliances(Boolean forceRefresh) throws PlugwiseHAException
}
}

/**
* Gets the appliance with the givven id. May result in a call to the remote service.
*
* @param id of the appliance
* @return Appliance may be null
* @throws PlugwiseHAException
*/
public @Nullable Appliance getAppliance(String id) throws PlugwiseHAException {
Appliances appliances = this.getAppliances(false);
if (!appliances.containsKey(id)) {
Expand All @@ -181,7 +191,7 @@ public Appliances getAppliances(Boolean forceRefresh) throws PlugwiseHAException
}
}

public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
private synchronized Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
Locations locations = null;
DomainObjects localDomainObjects = this.domainObjects;
if (localDomainObjects != null) {
Expand Down Expand Up @@ -209,6 +219,13 @@ public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
}
}

/**
* Gets the location with the givven id. May result in a call to the remote service.
*
* @param id of the location
* @return Location may be null
* @throws PlugwiseHAException
*/
public @Nullable Location getLocation(String id) throws PlugwiseHAException {
Locations locations = this.getLocations(false);
if (!locations.containsKey(id)) {
Expand All @@ -223,7 +240,13 @@ public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
}
}

public @Nullable DomainObjects getDomainObjects() throws PlugwiseHAException {
/**
* Gets and caches all objects from the remote service resulting in a call to the remote service.
*
* @return up to date DomainObjects may be null
* @throws PlugwiseHAException
*/
public synchronized @Nullable DomainObjects getAndMergeDomainObjects() throws PlugwiseHAException {
PlugwiseHAControllerRequest<DomainObjects> request;

request = newRequest(DomainObjects.class, this.domainObjectsTransformer);
Expand All @@ -239,27 +262,24 @@ public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
return mergeDomainObjects(domainObjects);
}

public @Nullable DomainObjects getUpdatedDomainObjects() throws PlugwiseHAException {
private @Nullable DomainObjects getUpdatedDomainObjects() throws PlugwiseHAException {
ZonedDateTime localGatewayUpdateDateTime = this.gatewayUpdateDateTime;
ZonedDateTime localGatewayFullUpdateDateTime = this.gatewayFullUpdateDateTime;

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

public @Nullable DomainObjects getUpdatedDomainObjects(ZonedDateTime since) throws PlugwiseHAException {
return getUpdatedDomainObjects(since.toEpochSecond());
}

public @Nullable DomainObjects getUpdatedDomainObjects(Long since) throws PlugwiseHAException {
private synchronized @Nullable DomainObjects getUpdatedAndMergeDomainObjects(Long since)
throws PlugwiseHAException {
PlugwiseHAControllerRequest<DomainObjects> request;

request = newRequest(DomainObjects.class, this.domainObjectsTransformer);
Expand All @@ -276,7 +296,7 @@ public Locations getLocations(Boolean forceRefresh) throws PlugwiseHAException {
return mergeDomainObjects(domainObjects);
}

public void setLocationThermostat(Location location, Double temperature) throws PlugwiseHAException {
public synchronized void setLocationThermostat(Location location, Double temperature) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);
Optional<ActuatorFunctionality> thermostat = location.getActuatorFunctionalities().getFunctionalityThermostat();

Expand All @@ -291,7 +311,7 @@ public void setLocationThermostat(Location location, Double temperature) throws
}
}

public void setThermostat(Appliance appliance, Double temperature) throws PlugwiseHAException {
public synchronized void setThermostat(Appliance appliance, Double temperature) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);
Optional<ActuatorFunctionality> thermostat = appliance.getActuatorFunctionalities()
.getFunctionalityThermostat();
Expand All @@ -307,7 +327,7 @@ public void setThermostat(Appliance appliance, Double temperature) throws Plugwi
}
}

public void setOffsetTemperature(Appliance appliance, Double temperature) throws PlugwiseHAException {
public synchronized void setOffsetTemperature(Appliance appliance, Double temperature) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);
Optional<ActuatorFunctionality> offsetTemperatureFunctionality = appliance.getActuatorFunctionalities()
.getFunctionalityOffsetTemperature();
Expand All @@ -323,7 +343,7 @@ public void setOffsetTemperature(Appliance appliance, Double temperature) throws
}
}

public void setPreHeating(Location location, Boolean state) throws PlugwiseHAException {
public synchronized void setPreHeating(Location location, Boolean state) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);
Optional<ActuatorFunctionality> thermostat = location.getActuatorFunctionalities().getFunctionalityThermostat();

Expand All @@ -335,7 +355,7 @@ public void setPreHeating(Location location, Boolean state) throws PlugwiseHAExc
executeRequest(request);
}

public void setAllowCooling(Location location, Boolean state) throws PlugwiseHAException {
public synchronized void setAllowCooling(Location location, Boolean state) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);
Optional<ActuatorFunctionality> thermostat = location.getActuatorFunctionalities().getFunctionalityThermostat();

Expand All @@ -347,7 +367,7 @@ public void setAllowCooling(Location location, Boolean state) throws PlugwiseHAE
executeRequest(request);
}

public void setRegulationControl(Location location, String state) throws PlugwiseHAException {
public synchronized void setRegulationControl(Location location, String state) throws PlugwiseHAException {
List<String> allowStates = Arrays.asList("active", "passive", "off");
if (!allowStates.contains(state.toLowerCase())) {
this.logger.warn("Trying to set the regulation control to an invalid state");
Expand All @@ -365,7 +385,7 @@ public void setRegulationControl(Location location, String state) throws Plugwis
executeRequest(request);
}

public void setRelay(Appliance appliance, Boolean state) throws PlugwiseHAException {
public synchronized void setRelay(Appliance appliance, Boolean state) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);

request.setPath("/core/appliances");
Expand All @@ -375,7 +395,7 @@ public void setRelay(Appliance appliance, Boolean state) throws PlugwiseHAExcept
executeRequest(request);
}

public void setRelayLock(Appliance appliance, Boolean state) throws PlugwiseHAException {
public synchronized void setRelayLock(Appliance appliance, Boolean state) throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request = newRequest(Void.class);

request.setPath("/core/appliances");
Expand All @@ -385,7 +405,7 @@ public void setRelayLock(Appliance appliance, Boolean state) throws PlugwiseHAEx
executeRequest(request);
}

public void setPresetScene(Location location, String state) throws PlugwiseHAException {
public synchronized void setPresetScene(Location location, String state) throws PlugwiseHAException {
List<String> allowStates = Arrays.asList("home", "asleep", "away", "vacation", "no_frost");
if (!allowStates.contains(state.toLowerCase())) {
this.logger.warn("Trying to set the preset scene to an invalid state");
Expand All @@ -409,19 +429,6 @@ public void setPresetScene(Location location, String state) throws PlugwiseHAExc
executeRequest(request);
}

public ZonedDateTime ping() throws PlugwiseHAException {
PlugwiseHAControllerRequest<Void> request;

request = newRequest(Void.class, null);

request.setPath("/cache/gateways");
request.addPathParameter("ping");

executeRequest(request);

return ZonedDateTime.parse(request.getServerDateTime(), PlugwiseHAController.FORMAT);
}

// Protected and private methods

private static Transformer setXSLT(StreamSource xsltSource) throws PlugwiseHAException {
Expand All @@ -444,16 +451,13 @@ private <T> PlugwiseHAControllerRequest<T> newRequest(Class<T> responseType) {

@SuppressWarnings("null")
private <T> T executeRequest(PlugwiseHAControllerRequest<T> request) throws PlugwiseHAException {
T result;
result = request.execute();
return result;
return request.execute();
}

private DomainObjects mergeDomainObjects(@Nullable DomainObjects updatedDomainObjects) {
DomainObjects localDomainObjects = this.domainObjects;
if (localDomainObjects == null && updatedDomainObjects != null) {
this.domainObjects = updatedDomainObjects;
return updatedDomainObjects;
return this.domainObjects = updatedDomainObjects;
} else if (localDomainObjects != null && updatedDomainObjects == null) {
return localDomainObjects;
} else if (localDomainObjects != null && updatedDomainObjects != null) {
Expand All @@ -467,7 +471,6 @@ 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 @@ -72,6 +72,7 @@ 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 static final int RETRY_DELAY_TIMOUT = 3000;

private final Logger logger = LoggerFactory.getLogger(PlugwiseHAControllerRequest.class);
private final XStream xStream;
Expand Down Expand Up @@ -252,6 +253,12 @@ private ContentResponse getContentResponse(int retries) throws PlugwiseHAExcepti
} catch (TimeoutException e) {
if (retries > 0) {
this.logger.debug("TimeoutException occured, remaining retries {}", retries - 1);
try {
Thread.sleep(RETRY_DELAY_TIMOUT);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new PlugwiseHATimeoutException(ie);
}
return getContentResponse(retries - 1);
} else {
throw new PlugwiseHATimeoutException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ public class DateTimeConverter extends AbstractSingleValueConverter {

@Override
public boolean canConvert(@Nullable @SuppressWarnings("rawtypes") Class type) {
if (type == null) {
return false;
}
return ZonedDateTime.class.isAssignableFrom(type);
return (type == null) ? false : ZonedDateTime.class.isAssignableFrom(type);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,12 @@ public class ActuatorFunctionalityThermostat extends ActuatorFunctionality {
@SuppressWarnings("unused")
private Double setpoint;

@SuppressWarnings("unused")
@XStreamAlias("preheating_allowed")
private Boolean preheatingAllowed;

@SuppressWarnings("unused")
@XStreamAlias("cooling_allowed")
private Boolean coolingAllowed;

@SuppressWarnings("unused")
@XStreamAlias("regulation_control")
private String regulationControl;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public class DomainObjects {
@XStreamImplicit(itemFieldName = "location", keyFieldName = "id")
private Locations locations = new Locations();

@SuppressWarnings("unused")
@XStreamImplicit(itemFieldName = "module", keyFieldName = "id")
private Modules modules = new Modules();

Expand All @@ -47,15 +46,19 @@ public Locations getLocations() {
}

public Appliances mergeAppliances(Appliances updatedAppliances) {
if (updatedAppliances != null) {
if (appliances == null) {
this.appliances = updatedAppliances;
} else if (updatedAppliances != null) {
this.appliances.merge(updatedAppliances);
}

return this.appliances;
}

public Locations mergeLocations(Locations updatedLocations) {
if (updatedLocations != null) {
if (locations == null) {
this.locations = updatedLocations;
} else if (updatedLocations != null) {
this.locations.merge(updatedLocations);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ public Optional<Double> getMeasurementAsDouble() {
}

public Optional<String> getMeasurementUnit() {
return Optional.ofNullable(unit);
return Optional.ofNullable(unit != null && !unit.isBlank() ? unit : null);
}

public ZonedDateTime getMeasurementDate() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
@XStreamAlias("module")
public class Module extends PlugwiseBaseModel implements PlugwiseComparableDate<Module> {

@SuppressWarnings("unused")
@XStreamImplicit(itemFieldName = "service", keyFieldName = "id")
private Services services;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,9 @@
@XStreamAlias("service")
public class Service extends PlugwiseBaseModel {

@SuppressWarnings("unused")
@XStreamAlias("log_type")
private String logType;

@SuppressWarnings("unused")
@XStreamAlias("point_log")
private String pointLogId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ private void discoverDomainObjects() throws PlugwiseHAException {
PlugwiseHAController controller = thingHandler.getController();

if (controller != null) {
DomainObjects domainObjects = controller.getDomainObjects();
DomainObjects domainObjects = controller.getAndMergeDomainObjects();

if (domainObjects != null) {
for (Location location : domainObjects.getLocations().values()) {
Expand Down
Loading