]> git.basschouten.com Git - openhab-addons.git/blob
1ae750797815469ec2f7f9df13346e4aaeaecd73
[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.nuki.internal.handler;
14
15 import java.util.List;
16 import java.util.concurrent.ScheduledFuture;
17 import java.util.concurrent.TimeUnit;
18
19 import org.eclipse.jetty.client.HttpClient;
20 import org.eclipse.jetty.http.HttpStatus;
21 import org.openhab.binding.nuki.internal.NukiBindingConstants;
22 import org.openhab.binding.nuki.internal.dataexchange.BridgeCallbackAddResponse;
23 import org.openhab.binding.nuki.internal.dataexchange.BridgeCallbackListResponse;
24 import org.openhab.binding.nuki.internal.dataexchange.BridgeCallbackRemoveResponse;
25 import org.openhab.binding.nuki.internal.dataexchange.BridgeInfoResponse;
26 import org.openhab.binding.nuki.internal.dataexchange.NukiHttpClient;
27 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackListCallbackDto;
28 import org.openhab.core.config.core.Configuration;
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.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 /**
39  * The {@link NukiBridgeHandler} is responsible for handling commands, which are
40  * sent to one of the channels.
41  *
42  * @author Markus Katter - Initial contribution
43  */
44 public class NukiBridgeHandler extends BaseBridgeHandler {
45
46     private final Logger logger = LoggerFactory.getLogger(NukiBridgeHandler.class);
47     private static final int JOB_INTERVAL = 600;
48
49     private HttpClient httpClient;
50     private NukiHttpClient nukiHttpClient;
51     private String callbackUrl;
52     private ScheduledFuture<?> checkBridgeOnlineJob;
53     private String bridgeIp;
54     private boolean manageCallbacks;
55     private boolean initializable;
56
57     public NukiBridgeHandler(Bridge bridge, HttpClient httpClient, String callbackUrl) {
58         super(bridge);
59         logger.debug("Instantiating NukiBridgeHandler({}, {}, {})", bridge, httpClient, callbackUrl);
60         this.httpClient = httpClient;
61         this.callbackUrl = callbackUrl;
62         this.initializable = getConfig().get(NukiBindingConstants.CONFIG_IP) != null
63                 && getConfig().get(NukiBindingConstants.CONFIG_API_TOKEN) != null;
64     }
65
66     public NukiHttpClient getNukiHttpClient() {
67         if (nukiHttpClient == null) {
68             nukiHttpClient = new NukiHttpClient(httpClient, getConfig());
69         }
70         return nukiHttpClient;
71     }
72
73     public boolean isInitializable() {
74         return initializable;
75     }
76
77     @Override
78     public void initialize() {
79         logger.debug("initialize() for Bridge[{}].", getThing().getUID());
80         Configuration config = getConfig();
81         bridgeIp = (String) config.get(NukiBindingConstants.CONFIG_IP);
82         manageCallbacks = (Boolean) config.get(NukiBindingConstants.CONFIG_MANAGECB);
83         if (bridgeIp == null) {
84             logger.debug("NukiBridgeHandler[{}] is not initializable, IP setting is unset in the configuration!",
85                     getThing().getUID());
86             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "IP setting is unset");
87         } else if (config.get(NukiBindingConstants.CONFIG_API_TOKEN) == null) {
88             logger.debug("NukiBridgeHandler[{}] is not initializable, apiToken setting is unset in the configuration!",
89                     getThing().getUID());
90             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.CONFIGURATION_ERROR, "apiToken setting is unset");
91         } else {
92             scheduler.execute(this::initializeHandler);
93             checkBridgeOnlineJob = scheduler.scheduleWithFixedDelay(this::checkBridgeOnline, JOB_INTERVAL, JOB_INTERVAL,
94                     TimeUnit.SECONDS);
95         }
96     }
97
98     @Override
99     public void handleCommand(ChannelUID channelUID, Command command) {
100         logger.debug("handleCommand({}, {}) for Bridge[{}] not implemented!", channelUID, command, bridgeIp);
101     }
102
103     @Override
104     public void dispose() {
105         logger.debug("dispose() for Bridge[{}].", getThing().getUID());
106         nukiHttpClient = null;
107         if (checkBridgeOnlineJob != null && !checkBridgeOnlineJob.isCancelled()) {
108             checkBridgeOnlineJob.cancel(true);
109         }
110         checkBridgeOnlineJob = null;
111     }
112
113     private synchronized void initializeHandler() {
114         logger.debug("initializeHandler() for Bridge[{}].", bridgeIp);
115         BridgeInfoResponse bridgeInfoResponse = getNukiHttpClient().getBridgeInfo();
116         if (bridgeInfoResponse.getStatus() == HttpStatus.OK_200) {
117             if (manageCallbacks) {
118                 manageNukiBridgeCallbacks();
119             }
120             logger.debug("Bridge[{}] responded with status[{}]. Switching the bridge online.", bridgeIp,
121                     bridgeInfoResponse.getStatus());
122             updateStatus(ThingStatus.ONLINE);
123         } else {
124             logger.debug("Bridge[{}] responded with status[{}]. Switching the bridge offline!", bridgeIp,
125                     bridgeInfoResponse.getStatus());
126             updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR, bridgeInfoResponse.getMessage());
127         }
128     }
129
130     private void checkBridgeOnline() {
131         logger.debug("checkBridgeOnline():bridgeIp[{}] status[{}]", bridgeIp, getThing().getStatus());
132         if (getThing().getStatus().equals(ThingStatus.ONLINE)) {
133             logger.debug("Requesting BridgeInfo to ensure Bridge[{}] is online.", bridgeIp);
134             BridgeInfoResponse bridgeInfoResponse = getNukiHttpClient().getBridgeInfo();
135             int status = bridgeInfoResponse.getStatus();
136             if (status == HttpStatus.OK_200) {
137                 logger.debug("Bridge[{}] responded with status[{}]. Bridge is online.", bridgeIp, status);
138             } else if (status == HttpStatus.SERVICE_UNAVAILABLE_503) {
139                 logger.debug(
140                         "Bridge[{}] responded with status[{}]. REST service seems to be busy but Bridge is online.",
141                         bridgeIp, status);
142             } else {
143                 logger.debug("Bridge[{}] responded with status[{}]. Switching the bridge offline!", bridgeIp, status);
144                 updateStatus(ThingStatus.OFFLINE, ThingStatusDetail.COMMUNICATION_ERROR,
145                         bridgeInfoResponse.getMessage());
146             }
147         } else {
148             initializeHandler();
149         }
150     }
151
152     private void manageNukiBridgeCallbacks() {
153         logger.debug("manageNukiBridgeCallbacks() for Bridge[{}].", bridgeIp);
154         BridgeCallbackListResponse bridgeCallbackListResponse = getNukiHttpClient().getBridgeCallbackList();
155         List<BridgeApiCallbackListCallbackDto> callbacks = bridgeCallbackListResponse.getCallbacks();
156         boolean callbackExists = false;
157         int callbackCount = callbacks == null ? 0 : callbacks.size();
158         if (callbacks != null) {
159             for (BridgeApiCallbackListCallbackDto callback : callbacks) {
160                 if (callback.getUrl().equals(callbackUrl)) {
161                     logger.debug("callbackUrl[{}] already existing on Bridge[{}].", callbackUrl, bridgeIp);
162                     callbackExists = true;
163                     continue;
164                 }
165                 if (callback.getUrl().contains(NukiBindingConstants.CALLBACK_ENDPOINT)) {
166                     logger.debug("Partial callbackUrl[{}] found on Bridge[{}] - Removing it!", callbackUrl, bridgeIp);
167                     BridgeCallbackRemoveResponse bridgeCallbackRemoveResponse = getNukiHttpClient()
168                             .getBridgeCallbackRemove(callback.getId());
169                     if (bridgeCallbackRemoveResponse.getStatus() == HttpStatus.OK_200) {
170                         logger.debug("Successfully removed callbackUrl[{}] on Bridge[{}]!", callbackUrl, bridgeIp);
171                         callbackCount--;
172                     }
173                 }
174             }
175         }
176         if (!callbackExists) {
177             if (callbackCount == 3) {
178                 logger.debug("Already 3 callback URLs existing on Bridge[{}] - Removing ID 0!", bridgeIp);
179                 BridgeCallbackRemoveResponse bridgeCallbackRemoveResponse = getNukiHttpClient()
180                         .getBridgeCallbackRemove(0);
181                 if (bridgeCallbackRemoveResponse.getStatus() == HttpStatus.OK_200) {
182                     logger.debug("Successfully removed callbackUrl[{}] on Bridge[{}]!", callbackUrl, bridgeIp);
183                     callbackCount--;
184                 }
185             }
186             logger.debug("Adding callbackUrl[{}] to Bridge[{}]!", callbackUrl, bridgeIp);
187             BridgeCallbackAddResponse bridgeCallbackAddResponse = getNukiHttpClient().getBridgeCallbackAdd(callbackUrl);
188             if (bridgeCallbackAddResponse.getStatus() == HttpStatus.OK_200) {
189                 logger.debug("Successfully added callbackUrl[{}] on Bridge[{}]!", callbackUrl, bridgeIp);
190                 callbackExists = true;
191             }
192         }
193     }
194 }