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.ojelectronics.internal;
15 import java.util.Collection;
17 import java.util.concurrent.ScheduledFuture;
18 import java.util.concurrent.TimeUnit;
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;
43 * Handles all traffic with OJ Electronics cloud
45 * @author Christian Kittel - Initial Contribution
48 public class OJCloudHandler extends BaseBridgeHandler {
50 private final Logger logger = LoggerFactory.getLogger(OJCloudHandler.class);
51 private final HttpClient httpClient;
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;
62 * Creates a new instance of {@link OJCloudHandler}
64 * @param bridge {@link Bridge}
65 * @param httpClient HttpClient
67 public OJCloudHandler(Bridge bridge, HttpClient httpClient) {
69 this.httpClient = httpClient;
70 this.configuration = new OJElectronicsBridgeConfiguration();
74 * Initializes the binding.
77 public void initialize() {
78 configuration = getConfigAs(OJElectronicsBridgeConfiguration.class);
83 * Disposes the binding.
86 public void dispose() {
87 final RefreshService localRefreshService = this.refreshService;
88 if (localRefreshService != null) {
89 localRefreshService.stop();
91 final ScheduledFuture<?> signTask = this.signTask;
92 if (signTask != null) {
93 signTask.cancel(true);
95 this.refreshService = null;
101 public void handleCommand(ChannelUID channelUID, Command command) {
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);
111 this.updateTask = scheduler.schedule(() -> {
112 localUpdateService.updateAllThermostats(getThing().getThings());
113 this.updateTask = null;
114 }, 2, TimeUnit.SECONDS);
118 private void ensureSignIn() {
119 if (signInService == null) {
120 signInService = new SignInService(configuration, httpClient);
122 final SignInService localSignInService = this.signInService;
123 if (localSignInService != null) {
124 localSignInService.signIn(this::handleSignInDone, this::handleConnectionLost,
125 this::handleUnauthorizedWhileSignIn);
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);
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();
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();
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();
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);
167 private void handleSignInDone(String sessionId) {
168 logger.trace("OJElectronicsCloudHandler.handleSignInDone({})", sessionId);
169 if (refreshService == null) {
170 refreshService = new RefreshService(configuration, httpClient);
172 final RefreshService localRefreshService = this.refreshService;
173 if (localRefreshService != null) {
174 localRefreshService.start(sessionId, this::initializationDone, this::refreshDone,
175 this::handleConnectionLost, this::handleUnauthorized);
177 updateStatus(ThingStatus.ONLINE);
179 this.updateService = new UpdateService(configuration, httpClient, this::handleConnectionLost,
180 this::handleUnauthorized);
183 private void handleUnauthorized() {
184 logger.trace("OJElectronicsCloudHandler.handleUnauthorized()");
185 final RefreshService localRefreshService = this.refreshService;
186 if (localRefreshService != null) {
187 localRefreshService.stop();
189 restartRefreshServiceAsync(1);
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();
202 public void reInitialize() {
203 logger.trace("OJElectronicsCloudHandler.reInitialize()");
204 final RefreshService localRefreshService = this.refreshService;
205 if (localRefreshService != null) {
206 localRefreshService.stop();
208 restartRefreshServiceAsync(1);
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();
218 restartRefreshServiceAsync(30);
221 private void restartRefreshServiceAsync(long delayInSeconds) {
222 signTask = scheduler.schedule(this::ensureSignIn, delayInSeconds, TimeUnit.SECONDS);
225 public void setDiscoveryService(OJDiscoveryService ojDiscoveryService) {
226 this.discoveryService = ojDiscoveryService;
230 public Collection<Class<? extends ThingHandlerService>> getServices() {
231 return Set.of(OJDiscoveryService.class);