[homeconnect] Catch exception when appropriate (#10929)

* [homeconnect] Catch exception when appropriate

Fix #10904

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2021-07-11 22:58:59 +02:00 committed by GitHub
parent fc9864f434
commit 64a418829f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 39 deletions

View File

@ -548,7 +548,7 @@ public class HomeConnectApiClient {
* Get active program of device. * Get active program of device.
* *
* @param haId home appliance id * @param haId home appliance id
* @return {@link Data} or null if there is no active program * @return {@link Program} or null if there is no active program
* @throws CommunicationException API communication exception * @throws CommunicationException API communication exception
* @throws AuthorizationException oAuth authorization exception * @throws AuthorizationException oAuth authorization exception
* @throws ApplianceOfflineException appliance is not connected to the cloud * @throws ApplianceOfflineException appliance is not connected to the cloud
@ -562,7 +562,7 @@ public class HomeConnectApiClient {
* Get selected program of device. * Get selected program of device.
* *
* @param haId home appliance id * @param haId home appliance id
* @return {@link Data} or null if there is no selected program * @return {@link Program} or null if there is no selected program
* @throws CommunicationException API communication exception * @throws CommunicationException API communication exception
* @throws AuthorizationException oAuth authorization exception * @throws AuthorizationException oAuth authorization exception
* @throws ApplianceOfflineException appliance is not connected to the cloud * @throws ApplianceOfflineException appliance is not connected to the cloud
@ -627,7 +627,17 @@ public class HomeConnectApiClient {
return getAvailablePrograms(haId, BASE_PATH + haId + "/programs/available"); return getAvailablePrograms(haId, BASE_PATH + haId + "/programs/available");
} }
public List<AvailableProgramOption> getProgramOptions(String haId, String programKey) /**
* Get the available options of a program.
*
* @param haId home appliance id
* @param programKey program id
* @return list of {@link AvailableProgramOption} or null if the program is unsupported by the API
* @throws CommunicationException API communication exception
* @throws AuthorizationException oAuth authorization exception
* @throws ApplianceOfflineException appliance is not connected to the cloud
*/
public @Nullable List<AvailableProgramOption> getProgramOptions(String haId, String programKey)
throws CommunicationException, AuthorizationException, ApplianceOfflineException { throws CommunicationException, AuthorizationException, ApplianceOfflineException {
Request request = createRequest(HttpMethod.GET, BASE_PATH + haId + "/programs/available/" + programKey); Request request = createRequest(HttpMethod.GET, BASE_PATH + haId + "/programs/available/" + programKey);
try { try {
@ -644,8 +654,7 @@ public class HomeConnectApiClient {
responseBody == null ? "" : responseBody); responseBody == null ? "" : responseBody);
} }
return response.getStatus() == HttpStatus.OK_200 ? mapToAvailableProgramOption(responseBody, haId) return response.getStatus() == HttpStatus.OK_200 ? mapToAvailableProgramOption(responseBody, haId) : null;
: List.of();
} catch (InterruptedException | TimeoutException | ExecutionException e) { } catch (InterruptedException | TimeoutException | ExecutionException e) {
logger.warn("Failed to get program options! haId={}, programKey={}, error={}", haId, programKey, logger.warn("Failed to get program options! haId={}, programKey={}, error={}", haId, programKey,
e.getMessage()); e.getMessage());

View File

@ -1026,7 +1026,6 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
updateState(channel.getUID(), UnDefType.UNDEF); updateState(channel.getUID(), UnDefType.UNDEF);
} }
}); });
} }
return OnOffType.from(enabled); return OnOffType.from(enabled);
} else { } else {
@ -1458,54 +1457,66 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
} }
protected void updateProgramOptionsStateDescriptions(String programKey) protected void updateProgramOptionsStateDescriptions(String programKey)
throws CommunicationException, AuthorizationException, ApplianceOfflineException { throws AuthorizationException, ApplianceOfflineException {
Optional<HomeConnectApiClient> apiClient = getApiClient(); Optional<HomeConnectApiClient> apiClient = getApiClient();
if (apiClient.isPresent()) { if (apiClient.isPresent()) {
boolean cacheToSet = false;
List<AvailableProgramOption> availableProgramOptions; List<AvailableProgramOption> availableProgramOptions;
if (availableProgramOptionsCache.containsKey(programKey)) { if (availableProgramOptionsCache.containsKey(programKey)) {
logger.debug("Returning cached options for '{}'.", programKey); logger.debug("Returning cached options for program '{}'.", programKey);
availableProgramOptions = availableProgramOptionsCache.get(programKey); availableProgramOptions = availableProgramOptionsCache.get(programKey);
availableProgramOptions = availableProgramOptions != null ? availableProgramOptions availableProgramOptions = availableProgramOptions != null ? availableProgramOptions
: Collections.emptyList(); : Collections.emptyList();
} else { } else {
// Depending on the current program operation state, the APi request could trigger a
// CommunicationException exception due to returned status code 409
try {
availableProgramOptions = apiClient.get().getProgramOptions(getThingHaId(), programKey); availableProgramOptions = apiClient.get().getProgramOptions(getThingHaId(), programKey);
if (availableProgramOptions == null) {
// Program is unsupported, save in cache an empty list of options to avoid calling again the API
// for this program
availableProgramOptions = emptyList();
logger.debug("Saving empty options in cache for unsupported program '{}'.", programKey);
availableProgramOptionsCache.put(programKey, availableProgramOptions); availableProgramOptionsCache.put(programKey, availableProgramOptions);
} else {
cacheToSet = true;
}
} catch (CommunicationException e) {
availableProgramOptions = emptyList();
}
} }
Optional<Channel> channelSpinSpeed = getThingChannel(CHANNEL_WASHER_SPIN_SPEED); Optional<Channel> channelSpinSpeed = getThingChannel(CHANNEL_WASHER_SPIN_SPEED);
Optional<Channel> channelTemperature = getThingChannel(CHANNEL_WASHER_TEMPERATURE); Optional<Channel> channelTemperature = getThingChannel(CHANNEL_WASHER_TEMPERATURE);
Optional<Channel> channelDryingTarget = getThingChannel(CHANNEL_DRYER_DRYING_TARGET); Optional<Channel> channelDryingTarget = getThingChannel(CHANNEL_DRYER_DRYING_TARGET);
if (availableProgramOptions.isEmpty()) { Optional<AvailableProgramOption> optionsSpinSpeed = availableProgramOptions.stream()
channelSpinSpeed.ifPresent( .filter(option -> OPTION_WASHER_SPIN_SPEED.equals(option.getKey())).findFirst();
channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())); Optional<AvailableProgramOption> optionsTemperature = availableProgramOptions.stream()
channelTemperature.ifPresent( .filter(option -> OPTION_WASHER_TEMPERATURE.equals(option.getKey())).findFirst();
channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())); Optional<AvailableProgramOption> optionsDryingTarget = availableProgramOptions.stream()
channelDryingTarget.ifPresent( .filter(option -> OPTION_DRYER_DRYING_TARGET.equals(option.getKey())).findFirst();
channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList()));
// Save options in cache only if we got options for all expected channels
if (cacheToSet && (!channelSpinSpeed.isPresent() || optionsSpinSpeed.isPresent())
&& (!channelTemperature.isPresent() || optionsTemperature.isPresent())
&& (!channelDryingTarget.isPresent() || optionsDryingTarget.isPresent())) {
logger.debug("Saving options in cache for program '{}'.", programKey);
availableProgramOptionsCache.put(programKey, availableProgramOptions);
} }
availableProgramOptions.forEach(option -> { channelSpinSpeed.ifPresent(channel -> optionsSpinSpeed.ifPresentOrElse(
switch (option.getKey()) { option -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
case OPTION_WASHER_SPIN_SPEED: { createStateOptions(option, this::convertWasherSpinSpeed)),
channelSpinSpeed () -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())));
.ifPresent(channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), channelTemperature.ifPresent(channel -> optionsTemperature.ifPresentOrElse(
createStateOptions(option, this::convertWasherSpinSpeed))); option -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
break; createStateOptions(option, this::convertWasherTemperature)),
} () -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())));
case OPTION_WASHER_TEMPERATURE: { channelDryingTarget.ifPresent(channel -> optionsDryingTarget.ifPresentOrElse(
channelTemperature option -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
.ifPresent(channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), createStateOptions(option, this::mapStringType)),
createStateOptions(option, this::convertWasherTemperature))); () -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())));
break;
}
case OPTION_DRYER_DRYING_TARGET: {
channelDryingTarget.ifPresent(channel -> dynamicStateDescriptionProvider
.setStateOptions(channel.getUID(), createStateOptions(option, this::mapStringType)));
break;
}
}
});
} }
} }

View File

@ -216,7 +216,7 @@ public class HomeConnectHoodHandler extends AbstractHomeConnectThingHandler {
try { try {
List<AvailableProgramOption> availableProgramOptions = apiClient.get() List<AvailableProgramOption> availableProgramOptions = apiClient.get()
.getProgramOptions(getThingHaId(), PROGRAM_HOOD_VENTING); .getProgramOptions(getThingHaId(), PROGRAM_HOOD_VENTING);
if (availableProgramOptions.isEmpty()) { if (availableProgramOptions == null || availableProgramOptions.isEmpty()) {
throw new CommunicationException("Program " + PROGRAM_HOOD_VENTING + " is unsupported"); throw new CommunicationException("Program " + PROGRAM_HOOD_VENTING + " is unsupported");
} }
availableProgramOptions.forEach(option -> { availableProgramOptions.forEach(option -> {