]> git.basschouten.com Git - openhab-addons.git/blob
d66598e9cd8733d2951d66a7a40fd18ec9d2b2b5
[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.nuki.internal.dataexchange;
14
15 import java.io.InterruptedIOException;
16 import java.net.SocketException;
17 import java.net.URI;
18 import java.util.Arrays;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.TimeoutException;
21
22 import org.eclipse.jdt.annotation.NonNullByDefault;
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.constants.NukiBindingConstants;
28 import org.openhab.binding.nuki.internal.constants.NukiLinkBuilder;
29 import org.openhab.binding.nuki.internal.constants.OpenerAction;
30 import org.openhab.binding.nuki.internal.constants.SmartLockAction;
31 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackAddDto;
32 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackListDto;
33 import org.openhab.binding.nuki.internal.dto.BridgeApiCallbackRemoveDto;
34 import org.openhab.binding.nuki.internal.dto.BridgeApiInfoDto;
35 import org.openhab.binding.nuki.internal.dto.BridgeApiListDeviceDto;
36 import org.openhab.binding.nuki.internal.dto.BridgeApiLockActionDto;
37 import org.openhab.binding.nuki.internal.dto.BridgeApiLockStateDto;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import com.google.gson.Gson;
42
43 /**
44  * The {@link NukiHttpClient} class is responsible for getting data from the Nuki Bridge.
45  *
46  * @author Markus Katter - Initial contribution
47  * @contributer Jan Vybíral - Hashed token authentication
48  */
49 @NonNullByDefault
50 public class NukiHttpClient {
51
52     private final Logger logger = LoggerFactory.getLogger(NukiHttpClient.class);
53
54     private final HttpClient httpClient;
55     private final Gson gson;
56     private final NukiLinkBuilder linkBuilder;
57
58     public NukiHttpClient(HttpClient httpClient, NukiLinkBuilder linkBuilder) {
59         logger.debug("Instantiating NukiHttpClient");
60         this.httpClient = httpClient;
61         this.linkBuilder = linkBuilder;
62         gson = new Gson();
63     }
64
65     private synchronized ContentResponse executeRequest(URI uri)
66             throws InterruptedException, ExecutionException, TimeoutException {
67         logger.debug("executeRequest({})", uri);
68         ContentResponse contentResponse = httpClient.GET(uri);
69         logger.debug("contentResponseAsString[{}]", contentResponse.getContentAsString());
70         return contentResponse;
71     }
72
73     private NukiBaseResponse handleException(Exception e) {
74         if (e instanceof ExecutionException) {
75             Throwable cause = e.getCause();
76             if (cause instanceof HttpResponseException) {
77                 HttpResponseException causeException = (HttpResponseException) cause;
78                 int status = causeException.getResponse().getStatus();
79                 String reason = causeException.getResponse().getReason();
80                 logger.debug("HTTP Response Exception! Status[{}] - Reason[{}]! Check your API Token!", status, reason);
81                 return new NukiBaseResponse(status, reason);
82             } else if (cause instanceof InterruptedIOException) {
83                 logger.debug(
84                         "InterruptedIOException! Exception[{}]! Check IP/Port configuration and if Nuki Bridge is powered on!",
85                         e.getMessage());
86                 return new NukiBaseResponse(HttpStatus.REQUEST_TIMEOUT_408,
87                         "InterruptedIOException! Check IP/Port configuration and if Nuki Bridge is powered on!");
88             } else if (cause instanceof SocketException) {
89                 logger.debug(
90                         "SocketException! Exception[{}]! Check IP/Port configuration and if Nuki Bridge is powered on!",
91                         e.getMessage());
92                 return new NukiBaseResponse(HttpStatus.NOT_FOUND_404,
93                         "SocketException! Check IP/Port configuration and if Nuki Bridge is powered on!");
94             }
95         }
96         logger.error("Could not handle Exception! Exception[{}]", e.getMessage(), e);
97         return new NukiBaseResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, e.getMessage());
98     }
99
100     public BridgeInfoResponse getBridgeInfo() {
101         logger.debug("getBridgeInfo() in thread {}", Thread.currentThread().getId());
102         try {
103             ContentResponse contentResponse = executeRequest(linkBuilder.info());
104             int status = contentResponse.getStatus();
105             String response = contentResponse.getContentAsString();
106             logger.debug("getBridgeInfo status[{}] response[{}]", status, response);
107             if (status == HttpStatus.OK_200) {
108                 BridgeApiInfoDto bridgeApiInfoDto = gson.fromJson(response, BridgeApiInfoDto.class);
109                 logger.debug("getBridgeInfo OK");
110                 return new BridgeInfoResponse(status, contentResponse.getReason(), bridgeApiInfoDto);
111             } else {
112                 logger.debug("Could not get Bridge Info! Status[{}] - Response[{}]", status, response);
113                 return new BridgeInfoResponse(status, contentResponse.getReason(), null);
114             }
115         } catch (Exception e) {
116             logger.debug("Could not get Bridge Info! Exception[{}]", e.getMessage());
117             return new BridgeInfoResponse(handleException(e));
118         }
119     }
120
121     public BridgeListResponse getList() {
122         logger.debug("getList() in thread {}", Thread.currentThread().getId());
123         try {
124             ContentResponse contentResponse = executeRequest(linkBuilder.list());
125             int status = contentResponse.getStatus();
126             String response = contentResponse.getContentAsString();
127             logger.debug("getList status[{}] response[{}]", status, response);
128             if (status == HttpStatus.OK_200) {
129                 BridgeApiListDeviceDto[] bridgeApiInfoDtoArray = gson.fromJson(response,
130                         BridgeApiListDeviceDto[].class);
131                 logger.debug("getList OK");
132                 return new BridgeListResponse(status, contentResponse.getReason(),
133                         Arrays.asList(bridgeApiInfoDtoArray));
134             } else {
135                 logger.debug("Could not get Bridge Info! Status[{}] - Response[{}]", status, response);
136                 return new BridgeListResponse(status, contentResponse.getReason(), null);
137             }
138         } catch (Exception e) {
139             logger.debug("Could not get List! Exception[{}]", e.getMessage());
140             return new BridgeListResponse(handleException(e));
141         }
142     }
143
144     public BridgeLockStateResponse getBridgeLockState(String nukiId, int deviceType) {
145         logger.debug("getBridgeLockState({}) in thread {}", nukiId, Thread.currentThread().getId());
146
147         try {
148             ContentResponse contentResponse = executeRequest(linkBuilder.lockState(nukiId, deviceType));
149             int status = contentResponse.getStatus();
150             String response = contentResponse.getContentAsString();
151             logger.debug("getBridgeLockState status[{}] response[{}]", status, response);
152             if (status == HttpStatus.OK_200) {
153                 BridgeApiLockStateDto bridgeApiLockStateDto = gson.fromJson(response, BridgeApiLockStateDto.class);
154                 logger.debug("getBridgeLockState OK");
155                 return new BridgeLockStateResponse(status, contentResponse.getReason(), bridgeApiLockStateDto);
156             } else {
157                 logger.debug("Could not get Lock State! Status[{}] - Response[{}]", status, response);
158                 return new BridgeLockStateResponse(status, contentResponse.getReason(), null);
159             }
160         } catch (Exception e) {
161             logger.debug("Could not get Bridge Lock State!", e);
162             return new BridgeLockStateResponse(handleException(e));
163         }
164     }
165
166     public BridgeLockActionResponse getSmartLockAction(String nukiId, SmartLockAction action, int deviceType) {
167         return getBridgeLockAction(nukiId, action.getAction(), deviceType);
168     }
169
170     public BridgeLockActionResponse getOpenerAction(String nukiId, OpenerAction action) {
171         return getBridgeLockAction(nukiId, action.getAction(), NukiBindingConstants.DEVICE_OPENER);
172     }
173
174     private BridgeLockActionResponse getBridgeLockAction(String nukiId, int lockAction, int deviceType) {
175         logger.debug("getBridgeLockAction({}, {}) in thread {}", nukiId, lockAction, Thread.currentThread().getId());
176         try {
177             ContentResponse contentResponse = executeRequest(linkBuilder.lockAction(nukiId, deviceType, lockAction));
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             ContentResponse contentResponse = executeRequest(linkBuilder.callbackAdd(callbackUrl));
199             int status = contentResponse.getStatus();
200             String response = contentResponse.getContentAsString();
201             logger.debug("getBridgeCallbackAdd status[{}] response[{}]", status, response);
202             if (status == HttpStatus.OK_200) {
203                 BridgeApiCallbackAddDto bridgeApiCallbackAddDto = gson.fromJson(response,
204                         BridgeApiCallbackAddDto.class);
205                 logger.debug("getBridgeCallbackAdd OK");
206                 return new BridgeCallbackAddResponse(status, contentResponse.getReason(), bridgeApiCallbackAddDto);
207             } else {
208                 logger.debug("Could not execute Callback Add! Status[{}] - Response[{}]", status, response);
209                 return new BridgeCallbackAddResponse(status, contentResponse.getReason(), null);
210             }
211         } catch (Exception e) {
212             logger.debug("Could not execute Callback Add! Exception[{}]", e.getMessage());
213             return new BridgeCallbackAddResponse(handleException(e));
214         }
215     }
216
217     public BridgeCallbackListResponse getBridgeCallbackList() {
218         logger.debug("getBridgeCallbackList() in thread {}", Thread.currentThread().getId());
219         try {
220             ContentResponse contentResponse = executeRequest(linkBuilder.callbackList());
221             int status = contentResponse.getStatus();
222             String response = contentResponse.getContentAsString();
223             logger.debug("getBridgeCallbackList status[{}] response[{}]", status, response);
224             if (status == HttpStatus.OK_200) {
225                 BridgeApiCallbackListDto bridgeApiCallbackListDto = gson.fromJson(response,
226                         BridgeApiCallbackListDto.class);
227                 logger.debug("getBridgeCallbackList OK");
228                 return new BridgeCallbackListResponse(status, contentResponse.getReason(), bridgeApiCallbackListDto);
229             } else {
230                 logger.debug("Could not execute Callback List! Status[{}] - Response[{}]", status, response);
231                 return new BridgeCallbackListResponse(status, contentResponse.getReason(), null);
232             }
233         } catch (Exception e) {
234             logger.debug("Could not execute Callback List! Exception[{}]", e.getMessage());
235             return new BridgeCallbackListResponse(handleException(e));
236         }
237     }
238
239     public BridgeCallbackRemoveResponse getBridgeCallbackRemove(int id) {
240         logger.debug("getBridgeCallbackRemove({}) in thread {}", id, Thread.currentThread().getId());
241         try {
242             ContentResponse contentResponse = executeRequest(linkBuilder.callbackRemove(id));
243             int status = contentResponse.getStatus();
244             String response = contentResponse.getContentAsString();
245             logger.debug("getBridgeCallbackRemove status[{}] response[{}]", status, response);
246             if (status == HttpStatus.OK_200) {
247                 BridgeApiCallbackRemoveDto bridgeApiCallbackRemoveDto = gson.fromJson(response,
248                         BridgeApiCallbackRemoveDto.class);
249                 logger.debug("getBridgeCallbackRemove OK");
250                 return new BridgeCallbackRemoveResponse(status, contentResponse.getReason(),
251                         bridgeApiCallbackRemoveDto);
252             } else {
253                 logger.debug("Could not execute Callback Remove! Status[{}] - Response[{}]", status, response);
254                 return new BridgeCallbackRemoveResponse(status, contentResponse.getReason(), null);
255             }
256         } catch (Exception e) {
257             logger.debug("Could not execute Callback Remove! Exception[{}]", e.getMessage());
258             return new BridgeCallbackRemoveResponse(handleException(e));
259         }
260     }
261 }