]> git.basschouten.com Git - openhab-addons.git/blob
ec9b5f1a7c88e72806b92eaf477552f5a486019e
[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.juicenet.internal.api;
14
15 import java.util.Arrays;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Objects;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.TimeUnit;
22 import java.util.concurrent.TimeoutException;
23
24 import org.eclipse.jdt.annotation.NonNullByDefault;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.eclipse.jetty.client.HttpClient;
27 import org.eclipse.jetty.client.api.ContentResponse;
28 import org.eclipse.jetty.client.api.Request;
29 import org.eclipse.jetty.client.util.StringContentProvider;
30 import org.eclipse.jetty.http.HttpHeader;
31 import org.eclipse.jetty.http.HttpStatus;
32 import org.openhab.binding.juicenet.internal.api.dto.JuiceNetApiDevice;
33 import org.openhab.binding.juicenet.internal.api.dto.JuiceNetApiDeviceStatus;
34 import org.openhab.binding.juicenet.internal.api.dto.JuiceNetApiInfo;
35 import org.openhab.binding.juicenet.internal.api.dto.JuiceNetApiTouSchedule;
36 import org.openhab.core.thing.ThingUID;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39
40 import com.google.gson.Gson;
41 import com.google.gson.JsonElement;
42 import com.google.gson.JsonObject;
43 import com.google.gson.JsonParser;
44 import com.google.gson.JsonSyntaxException;
45
46 /**
47  * The {@link JuiceNetApi} is responsible for implementing the api interface to the JuiceNet cloud server
48  *
49  * @author Jeff James - Initial contribution
50  */
51 @NonNullByDefault
52 public class JuiceNetApi {
53     private final Logger logger = LoggerFactory.getLogger(JuiceNetApi.class);
54
55     private static final String API_HOST = "https://jbv1-api.emotorwerks.com/";
56     private static final String API_ACCOUNT = API_HOST + "box_pin";
57     private static final String API_DEVICE = API_HOST + "box_api_secure";
58     private static final int REQUEST_TIMEOUT_MS = 10_000;
59
60     private String apiToken = "";
61     private HttpClient httpClient;
62     private ThingUID bridgeUID;
63
64     public enum ApiCommand {
65         GET_ACCOUNT_UNITS("get_account_units", API_ACCOUNT),
66         GET_STATE("get_state", API_DEVICE),
67         SET_CHARGING_LIMIT("set_limit", API_DEVICE),
68         GET_SCHEDULE("get_schedule", API_DEVICE),
69         SET_SCHEDULE("set_schedule", API_DEVICE),
70         GET_INFO("get_info", API_DEVICE),
71         SET_OVERRIDE("set_override", API_DEVICE);
72
73         final String command;
74         final String uri;
75
76         ApiCommand(String command, String uri) {
77             this.command = command;
78             this.uri = uri;
79         }
80     }
81
82     public JuiceNetApi(HttpClient httpClient, ThingUID bridgeUID) {
83         this.bridgeUID = bridgeUID;
84         this.httpClient = httpClient;
85     }
86
87     public void setApiToken(String apiToken) {
88         this.apiToken = apiToken;
89     }
90
91     public List<JuiceNetApiDevice> queryDeviceList() throws JuiceNetApiException, InterruptedException {
92         JuiceNetApiDevice[] listDevices;
93         try {
94             JsonObject jsonResponse = postApiCommand(ApiCommand.GET_ACCOUNT_UNITS, null);
95
96             JsonElement unitsElement = jsonResponse.get("units");
97             if (unitsElement == null) {
98                 throw new JuiceNetApiException("getDevices from Juicenet API failed, no 'units' element in response.");
99             }
100
101             listDevices = new Gson().fromJson(unitsElement.getAsJsonArray(), JuiceNetApiDevice[].class);
102         } catch (JsonSyntaxException e) {
103             throw new JuiceNetApiException("getDevices from JuiceNet API failed, invalid JSON list.");
104         } catch (IllegalStateException e) {
105             throw new JuiceNetApiException("getDevices from JuiceNet API failed - did not return valid array.");
106         }
107
108         return Arrays.asList(listDevices);
109     }
110
111     public JuiceNetApiDeviceStatus queryDeviceStatus(String token) throws JuiceNetApiException, InterruptedException {
112         JuiceNetApiDeviceStatus deviceStatus;
113         try {
114             JsonObject jsonResponse = postApiCommand(ApiCommand.GET_STATE, token);
115
116             deviceStatus = new Gson().fromJson(jsonResponse, JuiceNetApiDeviceStatus.class);
117         } catch (JsonSyntaxException e) {
118             throw new JuiceNetApiException("queryDeviceStatus from JuiceNet API failed, invalid JSON list.");
119         } catch (IllegalStateException e) {
120             throw new JuiceNetApiException("queryDeviceStatus from JuiceNet API failed - did not return valid array.");
121         }
122
123         return Objects.requireNonNull(deviceStatus);
124     }
125
126     public JuiceNetApiInfo queryInfo(String token) throws InterruptedException, JuiceNetApiException {
127         JuiceNetApiInfo info;
128         try {
129             JsonObject jsonResponse = postApiCommand(ApiCommand.GET_INFO, token);
130
131             info = new Gson().fromJson(jsonResponse, JuiceNetApiInfo.class);
132         } catch (JsonSyntaxException e) {
133             throw new JuiceNetApiException("queryInfo from JuiceNet API failed, invalid JSON list.");
134         } catch (IllegalStateException e) {
135             throw new JuiceNetApiException("queryInfo from JuiceNet API failed - did not return valid array.");
136         }
137
138         return Objects.requireNonNull(info);
139     }
140
141     public JuiceNetApiTouSchedule queryTOUSchedule(String token) throws InterruptedException, JuiceNetApiException {
142         JuiceNetApiTouSchedule deviceTouSchedule;
143         try {
144             JsonObject jsonResponse = postApiCommand(ApiCommand.GET_SCHEDULE, token);
145
146             deviceTouSchedule = new Gson().fromJson(jsonResponse, JuiceNetApiTouSchedule.class);
147         } catch (JsonSyntaxException e) {
148             throw new JuiceNetApiException("queryTOUSchedule from JuiceNet API failed, invalid JSON list.");
149         } catch (IllegalStateException e) {
150             throw new JuiceNetApiException("queryTOUSchedule from JuiceNet API failed - did not return valid array.");
151         }
152
153         return Objects.requireNonNull(deviceTouSchedule);
154     }
155
156     public void setOverride(String token, int energy_at_plugin, Long override_time, int energy_to_add)
157             throws InterruptedException, JuiceNetApiException {
158         Map<String, Object> params = new HashMap<>();
159
160         params.put("energy_at_plugin", Integer.toString(energy_at_plugin));
161         params.put("override_time", Long.toString(override_time));
162         params.put("energy_to_add", Integer.toString(energy_to_add));
163
164         postApiCommand(ApiCommand.SET_OVERRIDE, token, params);
165     }
166
167     public void setCurrentLimit(String token, int limit) throws InterruptedException, JuiceNetApiException {
168         Map<String, Object> params = new HashMap<>();
169
170         params.put("amperage", Integer.toString(limit));
171
172         postApiCommand(ApiCommand.SET_OVERRIDE, token, params);
173     }
174
175     public JsonObject postApiCommand(ApiCommand cmd, @Nullable String token)
176             throws InterruptedException, JuiceNetApiException {
177         Map<String, Object> params = new HashMap<>();
178
179         return postApiCommand(cmd, token, params);
180     }
181
182     public JsonObject postApiCommand(ApiCommand cmd, @Nullable String token, Map<String, Object> params)
183             throws InterruptedException, JuiceNetApiException {
184         Request request = httpClient.POST(cmd.uri);
185         request.timeout(REQUEST_TIMEOUT_MS, TimeUnit.MILLISECONDS);
186         request.header(HttpHeader.CONTENT_TYPE, "application/json");
187
188         // Add required params
189         params.put("cmd", cmd.command);
190         params.put("device_id", bridgeUID.getAsString());
191         params.put("account_token", apiToken);
192
193         if (token != null) {
194             params.put("token", token);
195         }
196
197         JsonObject jsonResponse;
198         try {
199             request.content(new StringContentProvider(new Gson().toJson(params)), "application/json");
200             ContentResponse response = request.send();
201             if (response.getStatus() != HttpStatus.OK_200) {
202                 throw new JuiceNetApiException(
203                         cmd.command + "from JuiceNet API unsuccessful, please check configuation. (HTTP code :"
204                                 + response.getStatus() + ").");
205             }
206
207             String responseString = response.getContentAsString();
208             logger.trace("{}", responseString);
209
210             jsonResponse = JsonParser.parseString(responseString).getAsJsonObject();
211             JsonElement successElement = jsonResponse.get("success");
212             if (successElement == null) {
213                 throw new JuiceNetApiException(
214                         cmd.command + " from JuiceNet API failed, 'success' element missing from response.");
215             }
216             boolean success = successElement.getAsBoolean();
217
218             if (!success) {
219                 throw new JuiceNetApiException(cmd.command + " from JuiceNet API failed, please check configuration.");
220             }
221         } catch (IllegalStateException e) {
222             throw new JuiceNetApiException(cmd.command + " from JuiceNet API failed, invalid JSON.");
223         } catch (TimeoutException e) {
224             throw new JuiceNetApiException(cmd.command + " from JuiceNet API timeout.");
225         } catch (ExecutionException e) {
226             throw new JuiceNetApiException(cmd.command + " from JuiceNet API execution issue.");
227         }
228
229         return jsonResponse;
230     }
231 }