]> git.basschouten.com Git - openhab-addons.git/blob
91d810dc73432c1a291936e0c1e0cfc9e05997dd
[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  * @author 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 causeException) {
77                 int status = causeException.getResponse().getStatus();
78                 String reason = causeException.getResponse().getReason();
79                 logger.debug("HTTP Response Exception! Status[{}] - Reason[{}]! Check your API Token!", status, reason);
80                 return new NukiBaseResponse(status, reason);
81             } else if (cause instanceof InterruptedIOException) {
82                 logger.debug(
83                         "InterruptedIOException! Exception[{}]! Check IP/Port configuration and if Nuki Bridge is powered on!",
84                         e.getMessage());
85                 return new NukiBaseResponse(HttpStatus.REQUEST_TIMEOUT_408,
86                         "InterruptedIOException! Check IP/Port configuration and if Nuki Bridge is powered on!");
87             } else if (cause instanceof SocketException) {
88                 logger.debug(
89                         "SocketException! Exception[{}]! Check IP/Port configuration and if Nuki Bridge is powered on!",
90                         e.getMessage());
91                 return new NukiBaseResponse(HttpStatus.NOT_FOUND_404,
92                         "SocketException! Check IP/Port configuration and if Nuki Bridge is powered on!");
93             }
94         }
95         logger.error("Could not handle Exception! Exception[{}]", e.getMessage(), e);
96         return new NukiBaseResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, e.getMessage());
97     }
98
99     public BridgeInfoResponse getBridgeInfo() {
100         logger.debug("getBridgeInfo() in thread {}", Thread.currentThread().getId());
101         try {
102             ContentResponse contentResponse = executeRequest(linkBuilder.info());
103             int status = contentResponse.getStatus();
104             String response = contentResponse.getContentAsString();
105             logger.debug("getBridgeInfo status[{}] response[{}]", status, response);
106             if (status == HttpStatus.OK_200) {
107                 BridgeApiInfoDto bridgeApiInfoDto = gson.fromJson(response, BridgeApiInfoDto.class);
108                 logger.debug("getBridgeInfo OK");
109                 return new BridgeInfoResponse(status, contentResponse.getReason(), bridgeApiInfoDto);
110             } else {
111                 logger.debug("Could not get Bridge Info! Status[{}] - Response[{}]", status, response);
112                 return new BridgeInfoResponse(status, contentResponse.getReason(), null);
113             }
114         } catch (Exception e) {
115             logger.debug("Could not get Bridge Info! Exception[{}]", e.getMessage());
116             return new BridgeInfoResponse(handleException(e));
117         }
118     }
119
120     public BridgeListResponse getList() {
121         logger.debug("getList() in thread {}", Thread.currentThread().getId());
122         try {
123             ContentResponse contentResponse = executeRequest(linkBuilder.list());
124             int status = contentResponse.getStatus();
125             String response = contentResponse.getContentAsString();
126             logger.debug("getList status[{}] response[{}]", status, response);
127             if (status == HttpStatus.OK_200) {
128                 BridgeApiListDeviceDto[] bridgeApiInfoDtoArray = gson.fromJson(response,
129                         BridgeApiListDeviceDto[].class);
130                 logger.debug("getList OK");
131                 return new BridgeListResponse(status, contentResponse.getReason(),
132                         Arrays.asList(bridgeApiInfoDtoArray));
133             } else {
134                 logger.debug("Could not get Bridge Info! Status[{}] - Response[{}]", status, response);
135                 return new BridgeListResponse(status, contentResponse.getReason(), null);
136             }
137         } catch (Exception e) {
138             logger.debug("Could not get List! Exception[{}]", e.getMessage());
139             return new BridgeListResponse(handleException(e));
140         }
141     }
142
143     public BridgeLockStateResponse getBridgeLockState(String nukiId, int deviceType) {
144         logger.debug("getBridgeLockState({}) in thread {}", nukiId, Thread.currentThread().getId());
145
146         try {
147             ContentResponse contentResponse = executeRequest(linkBuilder.lockState(nukiId, deviceType));
148             int status = contentResponse.getStatus();
149             String response = contentResponse.getContentAsString();
150             logger.debug("getBridgeLockState status[{}] response[{}]", status, response);
151             if (status == HttpStatus.OK_200) {
152                 BridgeApiLockStateDto bridgeApiLockStateDto = gson.fromJson(response, BridgeApiLockStateDto.class);
153                 logger.debug("getBridgeLockState OK");
154                 return new BridgeLockStateResponse(status, contentResponse.getReason(), bridgeApiLockStateDto);
155             } else {
156                 logger.debug("Could not get Lock State! Status[{}] - Response[{}]", status, response);
157                 return new BridgeLockStateResponse(status, contentResponse.getReason(), null);
158             }
159         } catch (Exception e) {
160             logger.debug("Could not get Bridge Lock State!", e);
161             return new BridgeLockStateResponse(handleException(e));
162         }
163     }
164
165     public BridgeLockActionResponse getSmartLockAction(String nukiId, SmartLockAction action, int deviceType) {
166         return getBridgeLockAction(nukiId, action.getAction(), deviceType);
167     }
168
169     public BridgeLockActionResponse getOpenerAction(String nukiId, OpenerAction action) {
170         return getBridgeLockAction(nukiId, action.getAction(), NukiBindingConstants.DEVICE_OPENER);
171     }
172
173     private BridgeLockActionResponse getBridgeLockAction(String nukiId, int lockAction, int deviceType) {
174         logger.debug("getBridgeLockAction({}, {}) in thread {}", nukiId, lockAction, Thread.currentThread().getId());
175         try {
176             ContentResponse contentResponse = executeRequest(linkBuilder.lockAction(nukiId, deviceType, lockAction));
177             int status = contentResponse.getStatus();
178             String response = contentResponse.getContentAsString();
179             logger.debug("getBridgeLockAction status[{}] response[{}]", status, response);
180             if (status == HttpStatus.OK_200) {
181                 BridgeApiLockActionDto bridgeApiLockActionDto = gson.fromJson(response, BridgeApiLockActionDto.class);
182                 logger.debug("getBridgeLockAction OK");
183                 return new BridgeLockActionResponse(status, contentResponse.getReason(), bridgeApiLockActionDto);
184             } else {
185                 logger.debug("Could not execute Lock Action! Status[{}] - Response[{}]", status, response);
186                 return new BridgeLockActionResponse(status, contentResponse.getReason(), null);
187             }
188         } catch (Exception e) {
189             logger.debug("Could not execute Lock Action! Exception[{}]", e.getMessage());
190             return new BridgeLockActionResponse(handleException(e));
191         }
192     }
193
194     public BridgeCallbackAddResponse getBridgeCallbackAdd(String callbackUrl) {
195         logger.debug("getBridgeCallbackAdd({}) in thread {}", callbackUrl, Thread.currentThread().getId());
196         try {
197             ContentResponse contentResponse = executeRequest(linkBuilder.callbackAdd(callbackUrl));
198             int status = contentResponse.getStatus();
199             String response = contentResponse.getContentAsString();
200             logger.debug("getBridgeCallbackAdd status[{}] response[{}]", status, response);
201             if (status == HttpStatus.OK_200) {
202                 BridgeApiCallbackAddDto bridgeApiCallbackAddDto = gson.fromJson(response,
203                         BridgeApiCallbackAddDto.class);
204                 logger.debug("getBridgeCallbackAdd OK");
205                 return new BridgeCallbackAddResponse(status, contentResponse.getReason(), bridgeApiCallbackAddDto);
206             } else {
207                 logger.debug("Could not execute Callback Add! Status[{}] - Response[{}]", status, response);
208                 return new BridgeCallbackAddResponse(status, contentResponse.getReason(), null);
209             }
210         } catch (Exception e) {
211             logger.debug("Could not execute Callback Add! Exception[{}]", e.getMessage());
212             return new BridgeCallbackAddResponse(handleException(e));
213         }
214     }
215
216     public BridgeCallbackListResponse getBridgeCallbackList() {
217         logger.debug("getBridgeCallbackList() in thread {}", Thread.currentThread().getId());
218         try {
219             ContentResponse contentResponse = executeRequest(linkBuilder.callbackList());
220             int status = contentResponse.getStatus();
221             String response = contentResponse.getContentAsString();
222             logger.debug("getBridgeCallbackList status[{}] response[{}]", status, response);
223             if (status == HttpStatus.OK_200) {
224                 BridgeApiCallbackListDto bridgeApiCallbackListDto = gson.fromJson(response,
225                         BridgeApiCallbackListDto.class);
226                 logger.debug("getBridgeCallbackList OK");
227                 return new BridgeCallbackListResponse(status, contentResponse.getReason(), bridgeApiCallbackListDto);
228             } else {
229                 logger.debug("Could not execute Callback List! Status[{}] - Response[{}]", status, response);
230                 return new BridgeCallbackListResponse(status, contentResponse.getReason(), null);
231             }
232         } catch (Exception e) {
233             logger.debug("Could not execute Callback List! Exception[{}]", e.getMessage());
234             return new BridgeCallbackListResponse(handleException(e));
235         }
236     }
237
238     public BridgeCallbackRemoveResponse getBridgeCallbackRemove(int id) {
239         logger.debug("getBridgeCallbackRemove({}) in thread {}", id, Thread.currentThread().getId());
240         try {
241             ContentResponse contentResponse = executeRequest(linkBuilder.callbackRemove(id));
242             int status = contentResponse.getStatus();
243             String response = contentResponse.getContentAsString();
244             logger.debug("getBridgeCallbackRemove status[{}] response[{}]", status, response);
245             if (status == HttpStatus.OK_200) {
246                 BridgeApiCallbackRemoveDto bridgeApiCallbackRemoveDto = gson.fromJson(response,
247                         BridgeApiCallbackRemoveDto.class);
248                 logger.debug("getBridgeCallbackRemove OK");
249                 return new BridgeCallbackRemoveResponse(status, contentResponse.getReason(),
250                         bridgeApiCallbackRemoveDto);
251             } else {
252                 logger.debug("Could not execute Callback Remove! Status[{}] - Response[{}]", status, response);
253                 return new BridgeCallbackRemoveResponse(status, contentResponse.getReason(), null);
254             }
255         } catch (Exception e) {
256             logger.debug("Could not execute Callback Remove! Exception[{}]", e.getMessage());
257             return new BridgeCallbackRemoveResponse(handleException(e));
258         }
259     }
260 }