2 * Copyright (c) 2010-2021 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
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
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.hydrawise.internal.api;
15 import java.util.Objects;
16 import java.util.concurrent.TimeUnit;
18 import org.eclipse.jdt.annotation.NonNullByDefault;
19 import org.eclipse.jetty.client.HttpClient;
20 import org.eclipse.jetty.client.api.ContentResponse;
21 import org.eclipse.jetty.http.HttpMethod;
22 import org.openhab.binding.hydrawise.internal.api.model.CustomerDetailsResponse;
23 import org.openhab.binding.hydrawise.internal.api.model.Response;
24 import org.openhab.binding.hydrawise.internal.api.model.SetControllerResponse;
25 import org.openhab.binding.hydrawise.internal.api.model.SetZoneResponse;
26 import org.openhab.binding.hydrawise.internal.api.model.StatusScheduleResponse;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
30 import com.google.gson.FieldNamingPolicy;
31 import com.google.gson.Gson;
32 import com.google.gson.GsonBuilder;
35 * The {@link HydrawiseCloudApiClient} communicates with the cloud based Hydrawise API service
37 * @author Dan Cunningham - Initial contribution
40 public class HydrawiseCloudApiClient {
41 private final Logger logger = LoggerFactory.getLogger(HydrawiseCloudApiClient.class);
43 private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
45 private static final String BASE_URL = "https://app.hydrawise.com/api/v1/";
46 private static final String STATUS_SCHEDUE_URL = BASE_URL
47 + "statusschedule.php?api_key=%s&controller_id=%d&hours=168";
48 private static final String CUSTOMER_DETAILS_URL = BASE_URL + "customerdetails.php?api_key=%s&type=controllers";
49 private static final String SET_CONTROLLER_URL = BASE_URL
50 + "setcontroller.php?api_key=%s&controller_id=%d&json=true";
51 private static final String SET_ZONE_URL = BASE_URL + "setzone.php?period_id=999";
52 private static final int TIMEOUT_SECONDS = 30;
53 private final HttpClient httpClient;
54 private String apiKey;
57 * Initializes the API client with a HydraWise API key from a user's account and the HTTPClient to use
60 public HydrawiseCloudApiClient(String apiKey, HttpClient httpClient) {
62 this.httpClient = httpClient;
66 * Initializes the API client with a HTTPClient to use
69 public HydrawiseCloudApiClient(HttpClient httpClient) {
74 * Set a new API key to use for requests
78 public void setApiKey(String apiKey) {
83 * Retrieves the {@link StatusScheduleResponse} for a given controller
87 * @throws HydrawiseConnectionException
88 * @throws HydrawiseAuthenticationException
90 public StatusScheduleResponse getStatusSchedule(int controllerId)
91 throws HydrawiseConnectionException, HydrawiseAuthenticationException {
92 String json = doGet(String.format(STATUS_SCHEDUE_URL, apiKey, controllerId));
93 StatusScheduleResponse response = Objects.requireNonNull(gson.fromJson(json, StatusScheduleResponse.class));
94 throwExceptionIfResponseError(response);
99 * Retrieves the {@link CustomerDetailsResponse}
102 * @throws HydrawiseConnectionException
103 * @throws HydrawiseAuthenticationException
105 public CustomerDetailsResponse getCustomerDetails()
106 throws HydrawiseConnectionException, HydrawiseAuthenticationException {
107 String json = doGet(String.format(CUSTOMER_DETAILS_URL, apiKey));
108 CustomerDetailsResponse response = Objects.requireNonNull(gson.fromJson(json, CustomerDetailsResponse.class));
109 throwExceptionIfResponseError(response);
114 * Sets the controller with supplied {@param id} as the current controller
117 * @return SetControllerResponse
118 * @throws HydrawiseConnectionException
119 * @throws HydrawiseAuthenticationException
120 * @throws HydrawiseCommandException
122 public SetControllerResponse setController(int id)
123 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
124 String json = doGet(String.format(SET_CONTROLLER_URL, apiKey, id));
125 SetControllerResponse response = Objects.requireNonNull(gson.fromJson(json, SetControllerResponse.class));
126 throwExceptionIfResponseError(response);
127 if (!response.message.equals("OK")) {
128 throw new HydrawiseCommandException(response.message);
134 * Stops a given relay
137 * @return Response message
138 * @throws HydrawiseConnectionException
139 * @throws HydrawiseAuthenticationException
140 * @throws HydrawiseCommandException
142 public String stopRelay(int relayId)
143 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
145 new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("stop").relayId(relayId).toString());
149 * Stops all relays on a given controller
151 * @param controllerId
152 * @return Response message
153 * @throws HydrawiseConnectionException
154 * @throws HydrawiseAuthenticationException
155 * @throws HydrawiseCommandException
157 public String stopAllRelays(int controllerId)
158 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
159 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("stopall")
160 .controllerId(controllerId).toString());
164 * Runs a relay for the default amount of time
167 * @return Response message
168 * @throws HydrawiseConnectionException
169 * @throws HydrawiseAuthenticationException
170 * @throws HydrawiseCommandException
172 public String runRelay(int relayId)
173 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
175 new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("run").relayId(relayId).toString());
179 * Runs a relay for the given amount of seconds
183 * @return Response message
184 * @throws HydrawiseConnectionException
185 * @throws HydrawiseAuthenticationException
186 * @throws HydrawiseCommandException
188 public String runRelay(int seconds, int relayId)
189 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
190 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("run").relayId(relayId)
191 .duration(seconds).toString());
195 * Run all relays on a given controller for the default amount of time
197 * @param controllerId
198 * @return Response message
199 * @throws HydrawiseConnectionException
200 * @throws HydrawiseAuthenticationException
201 * @throws HydrawiseCommandException
203 public String runAllRelays(int controllerId)
204 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
205 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("runall")
206 .controllerId(controllerId).toString());
210 * Run all relays on a given controller for the amount of seconds
213 * @param controllerId
214 * @return Response message
215 * @throws HydrawiseConnectionException
216 * @throws HydrawiseAuthenticationException
217 * @throws HydrawiseCommandException
219 public String runAllRelays(int seconds, int controllerId)
220 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
221 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("runall")
222 .controllerId(controllerId).duration(seconds).toString());
226 * Suspends a given relay
229 * @return Response message
230 * @throws HydrawiseConnectionException
231 * @throws HydrawiseAuthenticationException
232 * @throws HydrawiseCommandException
234 public String suspendRelay(int relayId)
235 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
237 new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspend").relayId(relayId).toString());
241 * Suspends a given relay for an amount of seconds
245 * @return Response message
246 * @throws HydrawiseConnectionException
247 * @throws HydrawiseAuthenticationException
248 * @throws HydrawiseCommandException
250 public String suspendRelay(int seconds, int relayId)
251 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
252 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspend").relayId(relayId)
253 .duration(seconds).toString());
257 * Suspend all relays on a given controller for an amount of seconds
260 * @param controllerId
261 * @return Response message
262 * @throws HydrawiseConnectionException
263 * @throws HydrawiseAuthenticationException
264 * @throws HydrawiseCommandException
266 public String suspendAllRelays(int seconds, int controllerId)
267 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
268 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspendall")
269 .controllerId(controllerId).duration(seconds).toString());
272 private String relayCommand(String url)
273 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
274 String json = doGet(url);
275 SetZoneResponse response = Objects.requireNonNull(gson.fromJson(json, SetZoneResponse.class));
276 throwExceptionIfResponseError(response);
277 if ("error".equals(response.messageType)) {
278 throw new HydrawiseCommandException(response.message);
280 return response.message;
283 private String doGet(String url) throws HydrawiseConnectionException {
284 logger.trace("Getting {}", url);
285 ContentResponse response;
287 response = httpClient.newRequest(url).method(HttpMethod.GET).timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
289 } catch (Exception e) {
290 throw new HydrawiseConnectionException(e);
292 if (response.getStatus() != 200) {
293 throw new HydrawiseConnectionException(
294 "Could not connect to Hydrawise API. Response code " + response.getStatus());
296 String stringResponse = response.getContentAsString();
297 logger.trace("Response: {}", stringResponse);
298 return stringResponse;
301 private void throwExceptionIfResponseError(Response response)
302 throws HydrawiseConnectionException, HydrawiseAuthenticationException {
303 String error = response.errorMsg;
305 if (error.equalsIgnoreCase("unauthorized")) {
306 throw new HydrawiseAuthenticationException();
308 throw new HydrawiseConnectionException(response.errorMsg);