]> git.basschouten.com Git - openhab-addons.git/commitdiff
[homeconnect] Catch exception when appropriate (#10929)
authorlolodomo <lg.hc@free.fr>
Sun, 11 Jul 2021 20:58:59 +0000 (22:58 +0200)
committerGitHub <noreply@github.com>
Sun, 11 Jul 2021 20:58:59 +0000 (22:58 +0200)
* [homeconnect] Catch exception when appropriate

Fix #10904

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/client/HomeConnectApiClient.java
bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/handler/AbstractHomeConnectThingHandler.java
bundles/org.openhab.binding.homeconnect/src/main/java/org/openhab/binding/homeconnect/internal/handler/HomeConnectHoodHandler.java

index feba2087b4fa090abea35d82b0c93c40eea42cd5..0b1e4473d0c3020fa083e963ed1f0993e97788c0 100644 (file)
@@ -548,7 +548,7 @@ public class HomeConnectApiClient {
      * Get active program of device.
      *
      * @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 AuthorizationException oAuth authorization exception
      * @throws ApplianceOfflineException appliance is not connected to the cloud
@@ -562,7 +562,7 @@ public class HomeConnectApiClient {
      * Get selected program of device.
      *
      * @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 AuthorizationException oAuth authorization exception
      * @throws ApplianceOfflineException appliance is not connected to the cloud
@@ -627,7 +627,17 @@ public class HomeConnectApiClient {
         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 {
         Request request = createRequest(HttpMethod.GET, BASE_PATH + haId + "/programs/available/" + programKey);
         try {
@@ -644,8 +654,7 @@ public class HomeConnectApiClient {
                         responseBody == null ? "" : responseBody);
             }
 
-            return response.getStatus() == HttpStatus.OK_200 ? mapToAvailableProgramOption(responseBody, haId)
-                    : List.of();
+            return response.getStatus() == HttpStatus.OK_200 ? mapToAvailableProgramOption(responseBody, haId) : null;
         } catch (InterruptedException | TimeoutException | ExecutionException e) {
             logger.warn("Failed to get program options! haId={}, programKey={}, error={}", haId, programKey,
                     e.getMessage());
index 9db0f0dd3e3b0303627ec52bea128da235a36170..906d9d721e7c13107ccde7ddaad88c18aa4bd46b 100644 (file)
@@ -1026,7 +1026,6 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
                                 updateState(channel.getUID(), UnDefType.UNDEF);
                             }
                         });
-
                     }
                     return OnOffType.from(enabled);
                 } else {
@@ -1458,54 +1457,66 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
     }
 
     protected void updateProgramOptionsStateDescriptions(String programKey)
-            throws CommunicationException, AuthorizationException, ApplianceOfflineException {
+            throws AuthorizationException, ApplianceOfflineException {
         Optional<HomeConnectApiClient> apiClient = getApiClient();
         if (apiClient.isPresent()) {
+            boolean cacheToSet = false;
             List<AvailableProgramOption> availableProgramOptions;
             if (availableProgramOptionsCache.containsKey(programKey)) {
-                logger.debug("Returning cached options for '{}'.", programKey);
+                logger.debug("Returning cached options for program '{}'.", programKey);
                 availableProgramOptions = availableProgramOptionsCache.get(programKey);
                 availableProgramOptions = availableProgramOptions != null ? availableProgramOptions
                         : Collections.emptyList();
             } else {
-                availableProgramOptions = apiClient.get().getProgramOptions(getThingHaId(), programKey);
-                availableProgramOptionsCache.put(programKey, availableProgramOptions);
+                // 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);
+                    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);
+                    } else {
+                        cacheToSet = true;
+                    }
+                } catch (CommunicationException e) {
+                    availableProgramOptions = emptyList();
+                }
             }
 
             Optional<Channel> channelSpinSpeed = getThingChannel(CHANNEL_WASHER_SPIN_SPEED);
             Optional<Channel> channelTemperature = getThingChannel(CHANNEL_WASHER_TEMPERATURE);
             Optional<Channel> channelDryingTarget = getThingChannel(CHANNEL_DRYER_DRYING_TARGET);
 
-            if (availableProgramOptions.isEmpty()) {
-                channelSpinSpeed.ifPresent(
-                        channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList()));
-                channelTemperature.ifPresent(
-                        channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList()));
-                channelDryingTarget.ifPresent(
-                        channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList()));
+            Optional<AvailableProgramOption> optionsSpinSpeed = availableProgramOptions.stream()
+                    .filter(option -> OPTION_WASHER_SPIN_SPEED.equals(option.getKey())).findFirst();
+            Optional<AvailableProgramOption> optionsTemperature = availableProgramOptions.stream()
+                    .filter(option -> OPTION_WASHER_TEMPERATURE.equals(option.getKey())).findFirst();
+            Optional<AvailableProgramOption> optionsDryingTarget = availableProgramOptions.stream()
+                    .filter(option -> OPTION_DRYER_DRYING_TARGET.equals(option.getKey())).findFirst();
+
+            // 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 -> {
-                switch (option.getKey()) {
-                    case OPTION_WASHER_SPIN_SPEED: {
-                        channelSpinSpeed
-                                .ifPresent(channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
-                                        createStateOptions(option, this::convertWasherSpinSpeed)));
-                        break;
-                    }
-                    case OPTION_WASHER_TEMPERATURE: {
-                        channelTemperature
-                                .ifPresent(channel -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
-                                        createStateOptions(option, this::convertWasherTemperature)));
-                        break;
-                    }
-                    case OPTION_DRYER_DRYING_TARGET: {
-                        channelDryingTarget.ifPresent(channel -> dynamicStateDescriptionProvider
-                                .setStateOptions(channel.getUID(), createStateOptions(option, this::mapStringType)));
-                        break;
-                    }
-                }
-            });
+            channelSpinSpeed.ifPresent(channel -> optionsSpinSpeed.ifPresentOrElse(
+                    option -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
+                            createStateOptions(option, this::convertWasherSpinSpeed)),
+                    () -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())));
+            channelTemperature.ifPresent(channel -> optionsTemperature.ifPresentOrElse(
+                    option -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
+                            createStateOptions(option, this::convertWasherTemperature)),
+                    () -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())));
+            channelDryingTarget.ifPresent(channel -> optionsDryingTarget.ifPresentOrElse(
+                    option -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(),
+                            createStateOptions(option, this::mapStringType)),
+                    () -> dynamicStateDescriptionProvider.setStateOptions(channel.getUID(), emptyList())));
         }
     }
 
index 85bae7756cd2acd1238e743225336d306ff7a044..f9fc735eacef9430106d3026238684eb4d04298a 100644 (file)
@@ -216,7 +216,7 @@ public class HomeConnectHoodHandler extends AbstractHomeConnectThingHandler {
                         try {
                             List<AvailableProgramOption> availableProgramOptions = apiClient.get()
                                     .getProgramOptions(getThingHaId(), PROGRAM_HOOD_VENTING);
-                            if (availableProgramOptions.isEmpty()) {
+                            if (availableProgramOptions == null || availableProgramOptions.isEmpty()) {
                                 throw new CommunicationException("Program " + PROGRAM_HOOD_VENTING + " is unsupported");
                             }
                             availableProgramOptions.forEach(option -> {