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