]> git.basschouten.com Git - openhab-addons.git/blob
7f7798e7b234730f9b3059906a494cae9739fb34
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 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.ojelectronics.internal;
14
15 import java.util.Collection;
16 import java.util.Set;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
19
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.eclipse.jetty.client.HttpClient;
23 import org.openhab.binding.ojelectronics.internal.config.OJElectronicsBridgeConfiguration;
24 import org.openhab.binding.ojelectronics.internal.models.SignalRResultModel;
25 import org.openhab.binding.ojelectronics.internal.models.groups.GroupContentResponseModel;
26 import org.openhab.binding.ojelectronics.internal.services.OJDiscoveryService;
27 import org.openhab.binding.ojelectronics.internal.services.RefreshGroupContentService;
28 import org.openhab.binding.ojelectronics.internal.services.RefreshService;
29 import org.openhab.binding.ojelectronics.internal.services.RefreshThermostatsService;
30 import org.openhab.binding.ojelectronics.internal.services.SignInService;
31 import org.openhab.binding.ojelectronics.internal.services.UpdateService;
32 import org.openhab.core.thing.Bridge;
33 import org.openhab.core.thing.ChannelUID;
34 import org.openhab.core.thing.ThingStatus;
35 import org.openhab.core.thing.ThingStatusDetail;
36 import org.openhab.core.thing.binding.BaseBridgeHandler;
37 import org.openhab.core.thing.binding.ThingHandlerService;
38 import org.openhab.core.types.Command;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
41
42 /**
43  * Handles all traffic with OJ Electronics cloud
44  *
45  * @author Christian Kittel - Initial Contribution
46  */
47 @NonNullByDefault
48 public class OJCloudHandler extends BaseBridgeHandler {
49
50     private final Logger logger = LoggerFactory.getLogger(OJCloudHandler.class);
51     private final HttpClient httpClient;
52
53     private @Nullable RefreshService refreshService;
54     private @Nullable UpdateService updateService;
55     private @Nullable SignInService signInService;
56     private OJElectronicsBridgeConfiguration configuration;
57     private @Nullable ScheduledFuture<?> signTask;
58     private @Nullable ScheduledFuture<?> updateTask;
59     private @Nullable OJDiscoveryService discoveryService;
60
61     /**
62      * Creates a new instance of {@link OJCloudHandler}
63      *
64      * @param bridge {@link Bridge}
65      * @param httpClient HttpClient
66      */
67     public OJCloudHandler(Bridge bridge, HttpClient httpClient) {
68         super(bridge);
69         this.httpClient = httpClient;
70         this.configuration = new OJElectronicsBridgeConfiguration();
71     }
72
73     /**
74      * Initializes the binding.
75      */
76     @Override
77     public void initialize() {
78         configuration = getConfigAs(OJElectronicsBridgeConfiguration.class);
79         ensureSignIn();
80     }
81
82     /**
83      * Disposes the binding.
84      */
85     @Override
86     public void dispose() {
87         final RefreshService localRefreshService = this.refreshService;
88         if (localRefreshService != null) {
89             localRefreshService.stop();
90         }
91         final ScheduledFuture<?> signTask = this.signTask;
92         if (signTask != null) {
93             signTask.cancel(true);
94         }
95         this.refreshService = null;
96         signInService = null;
97         super.dispose();
98     }
99
100     @Override
101     public void handleCommand(ChannelUID channelUID, Command command) {
102     }
103
104     public synchronized void updateThinksChannelValuesToCloud() {
105         final UpdateService localUpdateService = this.updateService;
106         if (localUpdateService != null) {
107             final ScheduledFuture<?> localUpdateTask = this.updateTask;
108             if (localUpdateTask != null) {
109                 localUpdateTask.cancel(false);
110             }
111             this.updateTask = scheduler.schedule(() -> {
112                 localUpdateService.updateAllThermostats(getThing().getThings());
113                 this.updateTask = null;
114             }, 2, TimeUnit.SECONDS);
115         }
116     }
117
118     private void ensureSignIn() {
119         if (signInService == null) {
120             signInService = new SignInService(configuration, httpClient);
121         }
122         final SignInService localSignInService = this.signInService;
123         if (localSignInService != null) {
124             localSignInService.signIn(this::handleSignInDone, this::handleConnectionLost,
125                     this::handleUnauthorizedWhileSignIn);
126         }
127     }
128
129     private void initializationDone(@Nullable GroupContentResponseModel groupContentResponse,
130             @Nullable String errorMessage) {
131         logger.trace("OJElectronicsCloudHandler.initializationDone({})", groupContentResponse);
132         if (groupContentResponse != null && groupContentResponse.errorCode == 0) {
133             internalInitializationDone(groupContentResponse);
134         } else {
135             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
136                     (errorMessage == null) ? "Wrong or no result model; Refreshing stoppped" : errorMessage);
137             final RefreshService localRefreshService = this.refreshService;
138             if (localRefreshService != null) {
139                 localRefreshService.stop();
140             }
141         }
142     }
143
144     private void refreshDone(@Nullable SignalRResultModel resultModel, @Nullable String errorMessage) {
145         logger.trace("OJElectronicsCloudHandler.refreshDone({})", resultModel);
146         if (resultModel != null) {
147             new RefreshThermostatsService(resultModel.getThermostats(), resultModel.getThermostatRealTimes(),
148                     getThing().getThings()).handle();
149         } else {
150             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
151                     (errorMessage == null) ? "Wrong or no result model; Refreshing stoppped" : errorMessage);
152             final RefreshService localRefreshService = this.refreshService;
153             if (localRefreshService != null) {
154                 localRefreshService.stop();
155             }
156         }
157     }
158
159     private void internalInitializationDone(GroupContentResponseModel groupContentResponse) {
160         new RefreshGroupContentService(groupContentResponse.groupContents, getThing().getThings()).handle();
161         final OJDiscoveryService localDiscoveryService = this.discoveryService;
162         if (localDiscoveryService != null) {
163             localDiscoveryService.setScanResultForDiscovery(groupContentResponse.groupContents);
164         }
165     }
166
167     private void handleSignInDone(String sessionId) {
168         logger.trace("OJElectronicsCloudHandler.handleSignInDone({})", sessionId);
169         if (refreshService == null) {
170             refreshService = new RefreshService(configuration, httpClient);
171         }
172         final RefreshService localRefreshService = this.refreshService;
173         if (localRefreshService != null) {
174             localRefreshService.start(sessionId, this::initializationDone, this::refreshDone,
175                     this::handleConnectionLost, this::handleUnauthorized);
176
177             updateStatus(ThingStatus.ONLINE);
178         }
179         this.updateService = new UpdateService(configuration, httpClient, this::handleConnectionLost,
180                 this::handleUnauthorized);
181     }
182
183     private void handleUnauthorized() {
184         logger.trace("OJElectronicsCloudHandler.handleUnauthorized()");
185         final RefreshService localRefreshService = this.refreshService;
186         if (localRefreshService != null) {
187             localRefreshService.stop();
188         }
189         restartRefreshServiceAsync(1);
190     }
191
192     private void handleUnauthorizedWhileSignIn() {
193         logger.trace("OJElectronicsCloudHandler.handleUnauthorizedWhileSignIn()");
194         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR,
195                 "Could not sign in. Check user name and password.");
196         final RefreshService localRefreshService = this.refreshService;
197         if (localRefreshService != null) {
198             localRefreshService.stop();
199         }
200     }
201
202     public void reInitialize() {
203         logger.trace("OJElectronicsCloudHandler.reInitialize()");
204         final RefreshService localRefreshService = this.refreshService;
205         if (localRefreshService != null) {
206             localRefreshService.stop();
207         }
208         restartRefreshServiceAsync(1);
209     }
210
211     private void handleConnectionLost(@Nullable String message) {
212         logger.trace("OJElectronicsCloudHandler.handleConnectionLost()");
213         updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, message);
214         final RefreshService localRefreshService = this.refreshService;
215         if (localRefreshService != null) {
216             localRefreshService.stop();
217         }
218         restartRefreshServiceAsync(30);
219     }
220
221     private void restartRefreshServiceAsync(long delayInSeconds) {
222         signTask = scheduler.schedule(this::ensureSignIn, delayInSeconds, TimeUnit.SECONDS);
223     }
224
225     public void setDiscoveryService(OJDiscoveryService ojDiscoveryService) {
226         this.discoveryService = ojDiscoveryService;
227     }
228
229     @Override
230     public Collection<Class<? extends ThingHandlerService>> getServices() {
231         return Set.of(OJDiscoveryService.class);
232     }
233 }