]> git.basschouten.com Git - openhab-addons.git/blob
129531e12828af5e8de89bf2d5ce2d424192766a
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2021 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
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
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.groheondus.internal.handler;
14
15 import java.io.IOException;
16 import java.time.Duration;
17 import java.time.Instant;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
20
21 import javax.security.auth.login.LoginException;
22
23 import org.eclipse.jdt.annotation.NonNullByDefault;
24 import org.eclipse.jdt.annotation.Nullable;
25 import org.grohe.ondus.api.OndusService;
26 import org.openhab.binding.groheondus.internal.AccountServlet;
27 import org.openhab.binding.groheondus.internal.GroheOndusAccountConfiguration;
28 import org.openhab.core.storage.Storage;
29 import org.openhab.core.thing.Bridge;
30 import org.openhab.core.thing.ChannelUID;
31 import org.openhab.core.thing.ThingStatus;
32 import org.openhab.core.thing.ThingStatusDetail;
33 import org.openhab.core.thing.binding.BaseBridgeHandler;
34 import org.openhab.core.types.Command;
35 import org.osgi.service.http.HttpService;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 /**
40  * @author Florian Schmidt and Arne Wohlert - Initial contribution
41  */
42 @NonNullByDefault
43 public class GroheOndusAccountHandler extends BaseBridgeHandler {
44
45     private static final String STORAGE_KEY_REFRESH_TOKEN = "refreshToken";
46
47     private final Logger logger = LoggerFactory.getLogger(GroheOndusAccountHandler.class);
48
49     private HttpService httpService;
50     private Storage<String> storage;
51     private @Nullable AccountServlet accountServlet;
52     private @Nullable OndusService ondusService;
53     private @Nullable ScheduledFuture<?> refreshTokenFuture;
54
55     public GroheOndusAccountHandler(Bridge bridge, HttpService httpService, Storage<String> storage) {
56         super(bridge);
57         this.httpService = httpService;
58         this.storage = storage;
59     }
60
61     public OndusService getService() {
62         OndusService ret = this.ondusService;
63         if (ret == null) {
64             throw new IllegalStateException("OndusService requested, which is null (UNINITIALIZED)");
65         }
66         return ret;
67     }
68
69     public void deleteRefreshToken() {
70         this.storage.remove(STORAGE_KEY_REFRESH_TOKEN);
71         this.initialize();
72
73         if (refreshTokenFuture != null) {
74             refreshTokenFuture.cancel(true);
75         }
76     }
77
78     public void setRefreshToken(String refreshToken) {
79         this.storage.put(STORAGE_KEY_REFRESH_TOKEN, refreshToken);
80         this.initialize();
81     }
82
83     private void scheduleTokenRefresh() {
84         if (ondusService != null) {
85             Instant expiresAt = ondusService.authorizationExpiresAt();
86             Duration between = Duration.between(Instant.now(), expiresAt);
87             refreshTokenFuture = scheduler.schedule(() -> {
88                 OndusService ondusService = this.ondusService;
89                 if (ondusService == null) {
90                     logger.warn("Trying to refresh Ondus account without a service being present.");
91                     return;
92                 }
93                 try {
94                     setRefreshToken(ondusService.refreshAuthorization());
95                 } catch (Exception e) {
96                     logger.warn("Could not refresh authorization for GROHE ONDUS account", e);
97                 }
98             }, between.getSeconds(), TimeUnit.SECONDS);
99         }
100     }
101
102     public boolean hasRefreshToken() {
103         return this.storage.containsKey(STORAGE_KEY_REFRESH_TOKEN);
104     }
105
106     @Override
107     public void handleCommand(ChannelUID channelUID, Command command) {
108         // Nothing to do for bridge
109     }
110
111     @Override
112     public void dispose() {
113         super.dispose();
114         if (ondusService != null) {
115             ondusService = null;
116         }
117         if (accountServlet != null) {
118             accountServlet.dispose();
119         }
120         if (refreshTokenFuture != null) {
121             refreshTokenFuture.cancel(true);
122         }
123     }
124
125     @Override
126     public void initialize() {
127         GroheOndusAccountConfiguration config = getConfigAs(GroheOndusAccountConfiguration.class);
128
129         if (this.accountServlet == null) {
130             this.accountServlet = new AccountServlet(httpService, this.getThing().getUID().getId(), this);
131         }
132
133         if ((config.username == null || config.password == null) && !this.hasRefreshToken()) {
134             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_PENDING,
135                     "Need username/password or refreshToken");
136             return;
137         }
138
139         updateStatus(ThingStatus.UNKNOWN);
140         try {
141             if (storage.containsKey(STORAGE_KEY_REFRESH_TOKEN)) {
142                 ondusService = OndusService.login(storage.get(STORAGE_KEY_REFRESH_TOKEN));
143                 scheduleTokenRefresh();
144             } else {
145                 // TODO: That's probably really inefficient, internally the loginWebform method acquires a refresh
146                 // token, maybe there should be a way to obtain this token here, somehow.
147                 ondusService = OndusService.loginWebform(config.username, config.password);
148             }
149             updateStatus(ThingStatus.ONLINE);
150
151             scheduler.submit(() -> getThing().getThings().forEach(thing -> {
152                 GroheOndusBaseHandler thingHandler = (GroheOndusBaseHandler) thing.getHandler();
153                 if (thingHandler != null) {
154                     thingHandler.updateChannels();
155                 }
156             }));
157         } catch (LoginException e) {
158             logger.debug("Grohe api login failed", e);
159             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "Login failed");
160         } catch (IOException e) {
161             logger.debug("Communication error while logging into the grohe api", e);
162             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, e.getMessage());
163         }
164     }
165 }