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