2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.windcentrale.internal.handler;
15 import static java.util.function.Predicate.not;
17 import java.util.Collection;
18 import java.util.List;
19 import java.util.Objects;
20 import java.util.concurrent.Future;
21 import java.util.stream.Collectors;
22 import java.util.stream.Stream;
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.openhab.binding.windcentrale.internal.WindcentraleDiscoveryService;
27 import org.openhab.binding.windcentrale.internal.api.RequestListener;
28 import org.openhab.binding.windcentrale.internal.api.TokenProvider;
29 import org.openhab.binding.windcentrale.internal.api.WindcentraleAPI;
30 import org.openhab.binding.windcentrale.internal.config.AccountConfiguration;
31 import org.openhab.binding.windcentrale.internal.exception.FailedGettingDataException;
32 import org.openhab.binding.windcentrale.internal.exception.InvalidAccessTokenException;
33 import org.openhab.core.io.net.http.HttpClientFactory;
34 import org.openhab.core.thing.Bridge;
35 import org.openhab.core.thing.ChannelUID;
36 import org.openhab.core.thing.ThingStatus;
37 import org.openhab.core.thing.ThingStatusDetail;
38 import org.openhab.core.thing.binding.BaseBridgeHandler;
39 import org.openhab.core.thing.binding.ThingHandlerService;
40 import org.openhab.core.types.Command;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * The {@link WindcentraleAccountHandler} provides the {@link WindcentraleAPI} instance used by the windmill handlers.
47 * @author Wouter Born - Initial contribution
50 public class WindcentraleAccountHandler extends BaseBridgeHandler {
52 private final Logger logger = LoggerFactory.getLogger(WindcentraleAccountHandler.class);
54 private final HttpClientFactory httpClientFactory;
56 private @Nullable WindcentraleAPI api;
57 private @Nullable Exception apiException;
58 private @Nullable Future<?> initializeFuture;
60 private final RequestListener requestListener = new RequestListener() {
62 public void onError(Exception exception) {
63 apiException = exception;
64 logger.debug("API exception occurred");
69 public void onSuccess() {
70 if (apiException != null) {
72 logger.debug("API exception cleared");
78 public WindcentraleAccountHandler(Bridge bridge, HttpClientFactory httpClientFactory) {
80 this.httpClientFactory = httpClientFactory;
84 public void dispose() {
85 Future<?> localFuture = initializeFuture;
86 if (localFuture != null) {
87 localFuture.cancel(true);
88 initializeFuture = null;
91 WindcentraleAPI localAPI = api;
92 if (localAPI != null) {
98 public @Nullable WindcentraleAPI getAPI() {
103 public void initialize() {
104 updateStatus(ThingStatus.UNKNOWN);
106 initializeFuture = scheduler.submit(() -> {
107 api = initializeAPI();
112 private WindcentraleAPI initializeAPI() {
113 AccountConfiguration config = getConfigAs(AccountConfiguration.class);
114 TokenProvider tokenProvider = new TokenProvider(httpClientFactory, config.username, config.password);
116 WindcentraleAPI api = new WindcentraleAPI(httpClientFactory, tokenProvider);
117 api.addRequestListener(requestListener);
123 } catch (FailedGettingDataException | InvalidAccessTokenException e) {
130 public Collection<Class<? extends ThingHandlerService>> getServices() {
131 return List.of(WindcentraleDiscoveryService.class);
135 public void handleCommand(ChannelUID channelUID, Command command) {
138 private void updateThingStatus() {
139 Exception e = apiException;
141 if (e instanceof InvalidAccessTokenException) {
142 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, e.getMessage());
144 Throwable cause = e.getCause();
145 String description = Stream
146 .of(Objects.requireNonNullElse(e.getMessage(), ""),
147 cause == null ? "" : Objects.requireNonNullElse(cause.getMessage(), ""))
148 .filter(not(String::isBlank)) //
149 .collect(Collectors.joining(": "));
150 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, description);
153 updateStatus(ThingStatus.ONLINE, ThingStatusDetail.NONE);