2 * Copyright (c) 2010-2020 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.concurrent.TimeUnit;
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.eclipse.jetty.client.HttpClient;
19 import org.eclipse.jetty.client.api.ContentResponse;
20 import org.eclipse.jetty.http.HttpMethod;
21 import org.openhab.binding.hydrawise.internal.api.model.CustomerDetailsResponse;
22 import org.openhab.binding.hydrawise.internal.api.model.Response;
23 import org.openhab.binding.hydrawise.internal.api.model.SetControllerResponse;
24 import org.openhab.binding.hydrawise.internal.api.model.SetZoneResponse;
25 import org.openhab.binding.hydrawise.internal.api.model.StatusScheduleResponse;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
29 import com.google.gson.FieldNamingPolicy;
30 import com.google.gson.Gson;
31 import com.google.gson.GsonBuilder;
34 * The {@link HydrawiseCloudApiClient} communicates with the cloud based Hydrawise API service
36 * @author Dan Cunningham - Initial contribution
39 public class HydrawiseCloudApiClient {
40 private final Logger logger = LoggerFactory.getLogger(HydrawiseCloudApiClient.class);
42 private final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
44 private static final String BASE_URL = "https://app.hydrawise.com/api/v1/";
45 private static final String STATUS_SCHEDUE_URL = BASE_URL
46 + "statusschedule.php?api_key=%s&controller_id=%d&hours=168";
47 private static final String CUSTOMER_DETAILS_URL = BASE_URL + "customerdetails.php?api_key=%s&type=controllers";
48 private static final String SET_CONTROLLER_URL = BASE_URL
49 + "setcontroller.php?api_key=%s&controller_id=%d&json=true";
50 private static final String SET_ZONE_URL = BASE_URL + "setzone.php?period_id=999";
51 private static final int TIMEOUT_SECONDS = 30;
52 private final HttpClient httpClient;
53 private String apiKey;
56 * Initializes the API client with a HydraWise API key from a user's account and the HTTPClient to use
59 public HydrawiseCloudApiClient(String apiKey, HttpClient httpClient) {
61 this.httpClient = httpClient;
65 * Initializes the API client with a HTTPClient to use
68 public HydrawiseCloudApiClient(HttpClient httpClient) {
73 * Set a new API key to use for requests
77 public void setApiKey(String apiKey) {
82 * Retrieves the {@link StatusScheduleResponse} for a given controller
86 * @throws HydrawiseConnectionException
87 * @throws HydrawiseAuthenticationException
89 public StatusScheduleResponse getStatusSchedule(int controllerId)
90 throws HydrawiseConnectionException, HydrawiseAuthenticationException {
91 String json = doGet(String.format(STATUS_SCHEDUE_URL, apiKey, controllerId));
92 StatusScheduleResponse response = gson.fromJson(json, StatusScheduleResponse.class);
93 throwExceptionIfResponseError(response);
98 * Retrieves the {@link CustomerDetailsResponse}
101 * @throws HydrawiseConnectionException
102 * @throws HydrawiseAuthenticationException
104 public CustomerDetailsResponse getCustomerDetails()
105 throws HydrawiseConnectionException, HydrawiseAuthenticationException {
106 String json = doGet(String.format(CUSTOMER_DETAILS_URL, apiKey));
107 CustomerDetailsResponse response = gson.fromJson(json, CustomerDetailsResponse.class);
108 throwExceptionIfResponseError(response);
113 * Sets the controller with supplied {@value id} as the current controller
116 * @return SetControllerResponse
117 * @throws HydrawiseConnectionException
118 * @throws HydrawiseAuthenticationException
119 * @throws HydrawiseCommandException
121 public SetControllerResponse setController(int id)
122 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
123 String json = doGet(String.format(SET_CONTROLLER_URL, apiKey, id));
124 SetControllerResponse response = gson.fromJson(json, SetControllerResponse.class);
125 throwExceptionIfResponseError(response);
126 if (!response.message.equals("OK")) {
127 throw new HydrawiseCommandException(response.message);
133 * Stops a given relay
136 * @return Response message
137 * @throws HydrawiseConnectionException
138 * @throws HydrawiseAuthenticationException
139 * @throws HydrawiseCommandException
141 public String stopRelay(int relayId)
142 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
144 new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("stop").relayId(relayId).toString());
148 * Stops all relays on a given controller
150 * @param controllerId
151 * @return Response message
152 * @throws HydrawiseConnectionException
153 * @throws HydrawiseAuthenticationException
154 * @throws HydrawiseCommandException
156 public String stopAllRelays(int controllerId)
157 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
158 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("stopall")
159 .controllerId(controllerId).toString());
163 * Runs a relay for the default amount of time
166 * @return Response message
167 * @throws HydrawiseConnectionException
168 * @throws HydrawiseAuthenticationException
169 * @throws HydrawiseCommandException
171 public String runRelay(int relayId)
172 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
174 new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("run").relayId(relayId).toString());
178 * Runs a relay for the given amount of seconds
182 * @return Response message
183 * @throws HydrawiseConnectionException
184 * @throws HydrawiseAuthenticationException
185 * @throws HydrawiseCommandException
187 public String runRelay(int seconds, int relayId)
188 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
189 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("run").relayId(relayId)
190 .duration(seconds).toString());
194 * Run all relays on a given controller for the default amount of time
196 * @param controllerId
197 * @return Response message
198 * @throws HydrawiseConnectionException
199 * @throws HydrawiseAuthenticationException
200 * @throws HydrawiseCommandException
202 public String runAllRelays(int controllerId)
203 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
204 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("runall")
205 .controllerId(controllerId).toString());
209 * Run all relays on a given controller for the amount of seconds
212 * @param controllerId
213 * @return Response message
214 * @throws HydrawiseConnectionException
215 * @throws HydrawiseAuthenticationException
216 * @throws HydrawiseCommandException
218 public String runAllRelays(int seconds, int controllerId)
219 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
220 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("runall")
221 .controllerId(controllerId).duration(seconds).toString());
225 * Suspends a given relay
228 * @return Response message
229 * @throws HydrawiseConnectionException
230 * @throws HydrawiseAuthenticationException
231 * @throws HydrawiseCommandException
233 public String suspendRelay(int relayId)
234 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
236 new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspend").relayId(relayId).toString());
240 * Suspends a given relay for an amount of seconds
244 * @return Response message
245 * @throws HydrawiseConnectionException
246 * @throws HydrawiseAuthenticationException
247 * @throws HydrawiseCommandException
249 public String suspendRelay(int seconds, int relayId)
250 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
251 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspend").relayId(relayId)
252 .duration(seconds).toString());
256 * Suspend all relays on a given controller for an amount of seconds
259 * @param controllerId
260 * @return Response message
261 * @throws HydrawiseConnectionException
262 * @throws HydrawiseAuthenticationException
263 * @throws HydrawiseCommandException
265 public String suspendAllRelays(int seconds, int controllerId)
266 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
267 return relayCommand(new HydrawiseZoneCommandBuilder(SET_ZONE_URL, apiKey).action("suspendall")
268 .controllerId(controllerId).duration(seconds).toString());
271 private String relayCommand(String url)
272 throws HydrawiseConnectionException, HydrawiseAuthenticationException, HydrawiseCommandException {
273 String json = doGet(url);
274 SetZoneResponse response = gson.fromJson(json, SetZoneResponse.class);
275 throwExceptionIfResponseError(response);
276 if ("error".equals(response.messageType)) {
277 throw new HydrawiseCommandException(response.message);
279 return response.message;
282 private String doGet(String url) throws HydrawiseConnectionException {
283 logger.trace("Getting {}", url);
284 ContentResponse response;
286 response = httpClient.newRequest(url).method(HttpMethod.GET).timeout(TIMEOUT_SECONDS, TimeUnit.SECONDS)
288 } catch (Exception e) {
289 throw new HydrawiseConnectionException(e);
291 if (response.getStatus() != 200) {
292 throw new HydrawiseConnectionException(
293 "Could not connect to Hydrawise API. Response code " + response.getStatus());
295 String stringResponse = response.getContentAsString();
296 logger.trace("Response: {}", stringResponse);
297 return stringResponse;
300 private void throwExceptionIfResponseError(Response response)
301 throws HydrawiseConnectionException, HydrawiseAuthenticationException {
302 String error = response.errorMsg;
304 if (error.equalsIgnoreCase("unauthorized")) {
305 throw new HydrawiseAuthenticationException();
307 throw new HydrawiseConnectionException(response.errorMsg);