]> git.basschouten.com Git - openhab-addons.git/blob
ffe56c2d0a01ce7ee00fae34733f873a553b50e1
[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.dataexchange;
14
15 import java.io.InterruptedIOException;
16 import java.math.BigDecimal;
17 import java.net.SocketException;
18 import java.net.URLEncoder;
19 import java.time.Instant;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.TimeoutException;
22
23 import org.eclipse.jetty.client.HttpClient;
24 import org.eclipse.jetty.client.HttpResponseException;
25 import org.eclipse.jetty.client.api.ContentResponse;
26 import org.eclipse.jetty.http.HttpStatus;
27 import org.openhab.binding.nuki.internal.NukiBindingConstants;
28 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackAddDto;
29 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackListDto;
30 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackRemoveDto;
31 import org.openhab.binding.nuki.internal.dto.BridgeApiInfoDto;
32 import org.openhab.binding.nuki.internal.dto.BridgeApiLockActionDto;
33 import org.openhab.binding.nuki.internal.dto.BridgeApiLockStateDto;
34 import org.openhab.core.config.core.Configuration;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.google.gson.Gson;
39
40 /**
41  * The {@link NukiHttpClient} class is responsible for getting data from the Nuki Bridge.
42  *
43  * @author Markus Katter - Initial contribution
44  */
45 public class NukiHttpClient {
46
47     private final Logger logger = LoggerFactory.getLogger(NukiHttpClient.class);
48     private static final long CACHE_PERIOD = 5;
49
50     private HttpClient httpClient;
51     private Configuration configuration;
52     private Gson gson;
53     private BridgeLockStateResponse bridgeLockStateResponseCache;
54
55     public NukiHttpClient(HttpClient httpClient, Configuration configuration) {
56         logger.debug("Instantiating NukiHttpClient({})", configuration);
57         this.configuration = configuration;
58         this.httpClient = httpClient;
59         gson = new Gson();
60     }
61
62     private String prepareUri(String uriTemplate, String... additionalArguments) {
63         String configIp = (String) configuration.get(NukiBindingConstants.CONFIG_IP);
64         BigDecimal configPort = (BigDecimal) configuration.get(NukiBindingConstants.CONFIG_PORT);
65         String configApiToken = (String) configuration.get(NukiBindingConstants.CONFIG_API_TOKEN);
66         String[] parameters = new String[additionalArguments.length + 3];
67         parameters[0] = configIp;
68         parameters[1] = configPort.toString();
69         parameters[2] = configApiToken;
70         System.arraycopy(additionalArguments, 0, parameters, 3, additionalArguments.length);
71         String uri = String.format(uriTemplate, parameters);
72         logger.trace("prepareUri(...):URI[{}]", uri);
73         return uri;
74     }
75
76     private synchronized ContentResponse executeRequest(String uri)
77             throws InterruptedException, ExecutionException, TimeoutException {
78         logger.debug("executeRequest({})", uri);
79         try {
80             Thread.sleep(100);
81         } catch (InterruptedException e) {
82         }
83         ContentResponse contentResponse = httpClient.GET(uri);
84         logger.debug("contentResponseAsString[{}]", contentResponse.getContentAsString());
85         return contentResponse;
86     }
87
88     private NukiBaseResponse handleException(Exception e) {
89         if (e instanceof ExecutionException) {
90             if (e.getCause() instanceof HttpResponseException) {
91                 HttpResponseException cause = (HttpResponseException) e.getCause();
92                 int status = cause.getResponse().getStatus();
93                 String reason = cause.getResponse().getReason();
94                 logger.debug("HTTP Response Exception! Status[{}] - Reason[{}]! Check your API Token!", status, reason);
95                 return new NukiBaseResponse(status, reason);
96             } else if (e.getCause() instanceof InterruptedIOException) {
97                 logger.debug(
98                         "InterruptedIOException! Exception[{}]! Check IP/Port configuration and if Nuki Bridge is powered on!",
99                         e.getMessage());
100                 return new NukiBaseResponse(HttpStatus.REQUEST_TIMEOUT_408,
101                         "InterruptedIOException! Check IP/Port configuration and if Nuki Bridge is powered on!");
102             } else if (e.getCause() instanceof SocketException) {
103                 logger.debug(
104                         "SocketException! Exception[{}]! Check IP/Port configuration and if Nuki Bridge is powered on!",
105                         e.getMessage());
106                 return new NukiBaseResponse(HttpStatus.NOT_FOUND_404,
107                         "SocketException! Check IP/Port configuration and if Nuki Bridge is powered on!");
108             }
109         }
110         logger.error("Could not handle Exception! Exception[{}]", e.getMessage(), e);
111         return new NukiBaseResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, e.getMessage());
112     }
113
114     public BridgeInfoResponse getBridgeInfo() {
115         logger.debug("getBridgeInfo() in thread {}", Thread.currentThread().getId());
116         String uri = prepareUri(NukiBindingConstants.URI_INFO);
117         try {
118             ContentResponse contentResponse = executeRequest(uri);
119             int status = contentResponse.getStatus();
120             String response = contentResponse.getContentAsString();
121             logger.debug("getBridgeInfo status[{}] response[{}]", status, response);
122             if (status == HttpStatus.OK_200) {
123                 BridgeApiInfoDto bridgeApiInfoDto = gson.fromJson(response, BridgeApiInfoDto.class);
124                 logger.debug("getBridgeInfo OK");
125                 return new BridgeInfoResponse(status, contentResponse.getReason(), bridgeApiInfoDto);
126             } else {
127                 logger.debug("Could not get Bridge Info! Status[{}] - Response[{}]", status, response);
128                 return new BridgeInfoResponse(status, contentResponse.getReason(), null);
129             }
130         } catch (Exception e) {
131             logger.debug("Could not get Bridge Info! Exception[{}]", e.getMessage());
132             return new BridgeInfoResponse(handleException(e));
133         }
134     }
135
136     public BridgeLockStateResponse getBridgeLockState(String nukiId) {
137         logger.debug("getBridgeLockState({}) in thread {}", nukiId, Thread.currentThread().getId());
138         long timestampSecs = Instant.now().getEpochSecond();
139         if (this.bridgeLockStateResponseCache != null
140                 && timestampSecs < this.bridgeLockStateResponseCache.getCreated().getEpochSecond() + CACHE_PERIOD) {
141             logger.debug("Returning LockState from cache - now[{}]<created[{}]+cachePeriod[{}]", timestampSecs,
142                     this.bridgeLockStateResponseCache.getCreated().getEpochSecond(), CACHE_PERIOD);
143             return bridgeLockStateResponseCache;
144         } else {
145             logger.debug("Requesting LockState from Bridge.");
146         }
147         String uri = prepareUri(NukiBindingConstants.URI_LOCKSTATE, nukiId);
148         try {
149             ContentResponse contentResponse = executeRequest(uri);
150             int status = contentResponse.getStatus();
151             String response = contentResponse.getContentAsString();
152             logger.debug("getBridgeLockState status[{}] response[{}]", status, response);
153             if (status == HttpStatus.OK_200) {
154                 BridgeApiLockStateDto bridgeApiLockStateDto = gson.fromJson(response, BridgeApiLockStateDto.class);
155                 logger.debug("getBridgeLockState OK");
156                 return bridgeLockStateResponseCache = new BridgeLockStateResponse(status, contentResponse.getReason(),
157                         bridgeApiLockStateDto);
158             } else {
159                 logger.debug("Could not get Lock State! Status[{}] - Response[{}]", status, response);
160                 return new BridgeLockStateResponse(status, contentResponse.getReason(), null);
161             }
162         } catch (Exception e) {
163             logger.debug("Could not get Bridge Lock State! Exception[{}]", e.getMessage());
164             return new BridgeLockStateResponse(handleException(e));
165         }
166     }
167
168     public BridgeLockActionResponse getBridgeLockAction(String nukiId, int lockAction) {
169         logger.debug("getBridgeLockAction({}, {}) in thread {}", nukiId, lockAction, Thread.currentThread().getId());
170         String uri = prepareUri(NukiBindingConstants.URI_LOCKACTION, nukiId, Integer.toString(lockAction));
171         try {
172             ContentResponse contentResponse = executeRequest(uri);
173             int status = contentResponse.getStatus();
174             String response = contentResponse.getContentAsString();
175             logger.debug("getBridgeLockAction status[{}] response[{}]", status, response);
176             if (status == HttpStatus.OK_200) {
177                 BridgeApiLockActionDto bridgeApiLockActionDto = gson.fromJson(response, BridgeApiLockActionDto.class);
178                 logger.debug("getBridgeLockAction OK");
179                 return new BridgeLockActionResponse(status, contentResponse.getReason(), bridgeApiLockActionDto);
180             } else {
181                 logger.debug("Could not execute Lock Action! Status[{}] - Response[{}]", status, response);
182                 return new BridgeLockActionResponse(status, contentResponse.getReason(), null);
183             }
184         } catch (Exception e) {
185             logger.debug("Could not execute Lock Action! Exception[{}]", e.getMessage());
186             return new BridgeLockActionResponse(handleException(e));
187         }
188     }
189
190     public BridgeCallbackAddResponse getBridgeCallbackAdd(String callbackUrl) {
191         logger.debug("getBridgeCallbackAdd({}) in thread {}", callbackUrl, Thread.currentThread().getId());
192         try {
193             String uri = prepareUri(NukiBindingConstants.URI_CBADD, URLEncoder.encode(callbackUrl, "UTF-8"));
194             ContentResponse contentResponse = executeRequest(uri);
195             int status = contentResponse.getStatus();
196             String response = contentResponse.getContentAsString();
197             logger.debug("getBridgeCallbackAdd status[{}] response[{}]", status, response);
198             if (status == HttpStatus.OK_200) {
199                 BridgeApiCallbackAddDto bridgeApiCallbackAddDto = gson.fromJson(response,
200                         BridgeApiCallbackAddDto.class);
201                 logger.debug("getBridgeCallbackAdd OK");
202                 return new BridgeCallbackAddResponse(status, contentResponse.getReason(), bridgeApiCallbackAddDto);
203             } else {
204                 logger.debug("Could not execute Callback Add! Status[{}] - Response[{}]", status, response);
205                 return new BridgeCallbackAddResponse(status, contentResponse.getReason(), null);
206             }
207         } catch (Exception e) {
208             logger.debug("Could not execute Callback Add! Exception[{}]", e.getMessage());
209             return new BridgeCallbackAddResponse(handleException(e));
210         }
211     }
212
213     public BridgeCallbackListResponse getBridgeCallbackList() {
214         logger.debug("getBridgeCallbackList() in thread {}", Thread.currentThread().getId());
215         String uri = prepareUri(NukiBindingConstants.URI_CBLIST);
216         try {
217             ContentResponse contentResponse = executeRequest(uri);
218             int status = contentResponse.getStatus();
219             String response = contentResponse.getContentAsString();
220             logger.debug("getBridgeCallbackList status[{}] response[{}]", status, response);
221             if (status == HttpStatus.OK_200) {
222                 BridgeApiCallbackListDto bridgeApiCallbackListDto = gson.fromJson(response,
223                         BridgeApiCallbackListDto.class);
224                 logger.debug("getBridgeCallbackList OK");
225                 return new BridgeCallbackListResponse(status, contentResponse.getReason(), bridgeApiCallbackListDto);
226             } else {
227                 logger.debug("Could not execute Callback List! Status[{}] - Response[{}]", status, response);
228                 return new BridgeCallbackListResponse(status, contentResponse.getReason(), null);
229             }
230         } catch (Exception e) {
231             logger.debug("Could not execute Callback List! Exception[{}]", e.getMessage());
232             return new BridgeCallbackListResponse(handleException(e));
233         }
234     }
235
236     public BridgeCallbackRemoveResponse getBridgeCallbackRemove(int id) {
237         logger.debug("getBridgeCallbackRemove({}) in thread {}", id, Thread.currentThread().getId());
238         try {
239             String uri = prepareUri(NukiBindingConstants.URI_CBREMOVE, Integer.toString(id));
240             ContentResponse contentResponse = executeRequest(uri);
241             int status = contentResponse.getStatus();
242             String response = contentResponse.getContentAsString();
243             logger.debug("getBridgeCallbackRemove status[{}] response[{}]", status, response);
244             if (status == HttpStatus.OK_200) {
245                 BridgeApiCallbackRemoveDto bridgeApiCallbackRemoveDto = gson.fromJson(response,
246                         BridgeApiCallbackRemoveDto.class);
247                 logger.debug("getBridgeCallbackRemove OK");
248                 return new BridgeCallbackRemoveResponse(status, contentResponse.getReason(),
249                         bridgeApiCallbackRemoveDto);
250             } else {
251                 logger.debug("Could not execute Callback Remove! Status[{}] - Response[{}]", status, response);
252                 return new BridgeCallbackRemoveResponse(status, contentResponse.getReason(), null);
253             }
254         } catch (Exception e) {
255             logger.debug("Could not execute Callback Remove! Exception[{}]", e.getMessage());
256             return new BridgeCallbackRemoveResponse(handleException(e));
257         }
258     }
259 }