[homeconnect] Delay update of state options when not accessible (#10784)

* [homeconnect] Delay update of state options when not accessible

Fix #10705

Signed-off-by: Laurent Garnier <lg.hc@free.fr>

* Review comment: parseBoolean

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
lolodomo 2021-06-05 19:30:43 +02:00 committed by GitHub
parent 3dc7b9ed25
commit 17eb0d5d78
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 19 deletions

View File

@ -79,7 +79,6 @@ public class HomeConnectApiClient {
private final Logger logger = LoggerFactory.getLogger(HomeConnectApiClient.class); private final Logger logger = LoggerFactory.getLogger(HomeConnectApiClient.class);
private final HttpClient client; private final HttpClient client;
private final String apiUrl; private final String apiUrl;
private final Map<String, List<AvailableProgramOption>> availableProgramOptionsCache;
private final Map<String, List<AvailableProgram>> programsCache; private final Map<String, List<AvailableProgram>> programsCache;
private final OAuthClientService oAuthClientService; private final OAuthClientService oAuthClientService;
private final CircularQueue<ApiRequest> communicationQueue; private final CircularQueue<ApiRequest> communicationQueue;
@ -91,7 +90,6 @@ public class HomeConnectApiClient {
this.oAuthClientService = oAuthClientService; this.oAuthClientService = oAuthClientService;
this.apiBridgeConfiguration = apiBridgeConfiguration; this.apiBridgeConfiguration = apiBridgeConfiguration;
availableProgramOptionsCache = new ConcurrentHashMap<>();
programsCache = new ConcurrentHashMap<>(); programsCache = new ConcurrentHashMap<>();
apiUrl = simulated ? API_SIMULATOR_BASE_URL : API_BASE_URL; apiUrl = simulated ? API_SIMULATOR_BASE_URL : API_BASE_URL;
communicationQueue = new CircularQueue<>(COMMUNICATION_QUEUE_SIZE); communicationQueue = new CircularQueue<>(COMMUNICATION_QUEUE_SIZE);
@ -631,12 +629,6 @@ public class HomeConnectApiClient {
public List<AvailableProgramOption> getProgramOptions(String haId, String programKey) public List<AvailableProgramOption> getProgramOptions(String haId, String programKey)
throws CommunicationException, AuthorizationException, ApplianceOfflineException { throws CommunicationException, AuthorizationException, ApplianceOfflineException {
if (availableProgramOptionsCache.containsKey(programKey)) {
logger.debug("Returning cached options for '{}'.", programKey);
List<AvailableProgramOption> availableProgramOptions = availableProgramOptionsCache.get(programKey);
return availableProgramOptions != null ? availableProgramOptions : Collections.emptyList();
}
Request request = createRequest(HttpMethod.GET, BASE_PATH + haId + "/programs/available/" + programKey); Request request = createRequest(HttpMethod.GET, BASE_PATH + haId + "/programs/available/" + programKey);
try { try {
ContentResponse response = sendRequest(request, apiBridgeConfiguration.getClientId()); ContentResponse response = sendRequest(request, apiBridgeConfiguration.getClientId());
@ -652,11 +644,8 @@ public class HomeConnectApiClient {
responseBody == null ? "" : responseBody); responseBody == null ? "" : responseBody);
} }
List<AvailableProgramOption> availableProgramOptions = response.getStatus() == HttpStatus.OK_200 return response.getStatus() == HttpStatus.OK_200 ? mapToAvailableProgramOption(responseBody, haId)
? mapToAvailableProgramOption(responseBody, haId)
: List.of(); : List.of();
availableProgramOptionsCache.put(programKey, availableProgramOptions);
return availableProgramOptions;
} 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

@ -21,6 +21,7 @@ import static org.openhab.core.library.unit.Units.*;
import static org.openhab.core.thing.ThingStatus.*; import static org.openhab.core.thing.ThingStatus.*;
import java.time.Duration; import java.time.Duration;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional; import java.util.Optional;
@ -96,6 +97,7 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
private @Nullable ScheduledFuture<?> reinitializationFuture2; private @Nullable ScheduledFuture<?> reinitializationFuture2;
private @Nullable ScheduledFuture<?> reinitializationFuture3; private @Nullable ScheduledFuture<?> reinitializationFuture3;
private boolean ignoreEventSourceClosedEvent; private boolean ignoreEventSourceClosedEvent;
private @Nullable String programOptionsDelayedUpdate;
private final ConcurrentHashMap<String, EventHandler> eventHandlers; private final ConcurrentHashMap<String, EventHandler> eventHandlers;
private final ConcurrentHashMap<String, ChannelUpdateHandler> channelUpdateHandlers; private final ConcurrentHashMap<String, ChannelUpdateHandler> channelUpdateHandlers;
@ -103,6 +105,7 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
private final ExpiringStateMap expiringStateMap; private final ExpiringStateMap expiringStateMap;
private final AtomicBoolean accessible; private final AtomicBoolean accessible;
private final Logger logger = LoggerFactory.getLogger(AbstractHomeConnectThingHandler.class); private final Logger logger = LoggerFactory.getLogger(AbstractHomeConnectThingHandler.class);
private final Map<String, List<AvailableProgramOption>> availableProgramOptionsCache;
public AbstractHomeConnectThingHandler(Thing thing, public AbstractHomeConnectThingHandler(Thing thing,
HomeConnectDynamicStateDescriptionProvider dynamicStateDescriptionProvider) { HomeConnectDynamicStateDescriptionProvider dynamicStateDescriptionProvider) {
@ -112,6 +115,7 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider; this.dynamicStateDescriptionProvider = dynamicStateDescriptionProvider;
expiringStateMap = new ExpiringStateMap(Duration.ofSeconds(CACHE_TTL_SEC)); expiringStateMap = new ExpiringStateMap(Duration.ofSeconds(CACHE_TTL_SEC));
accessible = new AtomicBoolean(false); accessible = new AtomicBoolean(false);
availableProgramOptionsCache = new ConcurrentHashMap<>();
configureEventHandlers(eventHandlers); configureEventHandlers(eventHandlers);
configureChannelUpdateHandlers(channelUpdateHandlers); configureChannelUpdateHandlers(channelUpdateHandlers);
@ -855,15 +859,41 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
}); });
} }
protected EventHandler updateRemoteControlActiveAndProgramOptionsStateEventHandler() {
return event -> {
defaultBooleanEventHandler(CHANNEL_REMOTE_CONTROL_ACTIVE_STATE).handle(event);
// update available program options if update was previously delayed and remote control is enabled
try {
String programKey = programOptionsDelayedUpdate;
if (programKey != null && Boolean.parseBoolean(event.getValue())) {
logger.debug("Delayed update of options for program {}", programKey);
updateProgramOptionsStateDescriptions(programKey, null);
programOptionsDelayedUpdate = null;
}
} catch (CommunicationException | ApplianceOfflineException | AuthorizationException e) {
logger.debug("Could not update program options. {}", e.getMessage());
}
};
}
protected EventHandler updateProgramOptionsAndSelectedProgramStateEventHandler() { protected EventHandler updateProgramOptionsAndSelectedProgramStateEventHandler() {
return event -> { return event -> {
defaultSelectedProgramStateEventHandler().handle(event); defaultSelectedProgramStateEventHandler().handle(event);
// update available program options // update available program options
try { try {
Optional<HomeConnectApiClient> apiClient = getApiClient();
String programKey = event.getValue(); String programKey = event.getValue();
if (programKey != null) { if (apiClient.isPresent() && programKey != null) {
updateProgramOptionsStateDescriptions(programKey, null); // Delay the update if options are not yet cached and remote control is disabled
if (availableProgramOptionsCache.get(programKey) == null
&& !apiClient.get().isRemoteControlActive(getThingHaId())) {
logger.debug("Delay update of options for program {}", programKey);
programOptionsDelayedUpdate = programKey;
} else {
updateProgramOptionsStateDescriptions(programKey, null);
}
} }
} catch (CommunicationException | ApplianceOfflineException | AuthorizationException e) { } catch (CommunicationException | ApplianceOfflineException | AuthorizationException e) {
logger.debug("Could not update program options. {}", e.getMessage()); logger.debug("Could not update program options. {}", e.getMessage());
@ -1322,8 +1352,16 @@ public abstract class AbstractHomeConnectThingHandler extends BaseThingHandler i
throws CommunicationException, AuthorizationException, ApplianceOfflineException { throws CommunicationException, AuthorizationException, ApplianceOfflineException {
Optional<HomeConnectApiClient> apiClient = getApiClient(); Optional<HomeConnectApiClient> apiClient = getApiClient();
if (apiClient.isPresent()) { if (apiClient.isPresent()) {
List<AvailableProgramOption> availableProgramOptions = apiClient.get().getProgramOptions(getThingHaId(), List<AvailableProgramOption> availableProgramOptions;
programKey); if (availableProgramOptionsCache.containsKey(programKey)) {
logger.debug("Returning cached options for '{}'.", programKey);
availableProgramOptions = availableProgramOptionsCache.get(programKey);
availableProgramOptions = availableProgramOptions != null ? availableProgramOptions
: Collections.emptyList();
} else {
availableProgramOptions = apiClient.get().getProgramOptions(getThingHaId(), programKey);
availableProgramOptionsCache.put(programKey, availableProgramOptions);
}
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);

View File

@ -66,7 +66,7 @@ public class HomeConnectDryerHandler extends AbstractHomeConnectThingHandler {
protected void configureEventHandlers(Map<String, EventHandler> handlers) { protected void configureEventHandlers(Map<String, EventHandler> handlers) {
// register default event handlers // register default event handlers
handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler()); handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler());
handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, defaultBooleanEventHandler(CHANNEL_REMOTE_CONTROL_ACTIVE_STATE)); handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, updateRemoteControlActiveAndProgramOptionsStateEventHandler());
handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED, handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED,
defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE)); defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE));
handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler()); handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler());

View File

@ -85,7 +85,7 @@ public class HomeConnectWasherDryerHandler extends AbstractHomeConnectThingHandl
protected void configureEventHandlers(Map<String, EventHandler> handlers) { protected void configureEventHandlers(Map<String, EventHandler> handlers) {
// register default event handlers // register default event handlers
handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler()); handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler());
handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, defaultBooleanEventHandler(CHANNEL_REMOTE_CONTROL_ACTIVE_STATE)); handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, updateRemoteControlActiveAndProgramOptionsStateEventHandler());
handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED, handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED,
defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE)); defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE));
handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler()); handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler());

View File

@ -85,7 +85,7 @@ public class HomeConnectWasherHandler extends AbstractHomeConnectThingHandler {
protected void configureEventHandlers(Map<String, EventHandler> handlers) { protected void configureEventHandlers(Map<String, EventHandler> handlers) {
// register default event handlers // register default event handlers
handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler()); handlers.put(EVENT_DOOR_STATE, defaultDoorStateEventHandler());
handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, defaultBooleanEventHandler(CHANNEL_REMOTE_CONTROL_ACTIVE_STATE)); handlers.put(EVENT_REMOTE_CONTROL_ACTIVE, updateRemoteControlActiveAndProgramOptionsStateEventHandler());
handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED, handlers.put(EVENT_REMOTE_CONTROL_START_ALLOWED,
defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE)); defaultBooleanEventHandler(CHANNEL_REMOTE_START_ALLOWANCE_STATE));
handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler()); handlers.put(EVENT_FINISH_IN_RELATIVE, defaultRemainingProgramTimeEventHandler());