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.tesla.internal.command;
15 import static org.openhab.binding.tesla.internal.TeslaBindingConstants.*;
17 import java.io.BufferedReader;
18 import java.io.InputStreamReader;
19 import java.util.Arrays;
20 import java.util.List;
22 import javax.ws.rs.client.Client;
23 import javax.ws.rs.client.ClientBuilder;
24 import javax.ws.rs.client.Entity;
25 import javax.ws.rs.client.WebTarget;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
29 import org.eclipse.jdt.annotation.NonNullByDefault;
30 import org.eclipse.jdt.annotation.Nullable;
31 import org.openhab.binding.tesla.internal.TeslaBindingConstants;
32 import org.openhab.binding.tesla.internal.discovery.TeslaAccountDiscoveryService;
33 import org.openhab.binding.tesla.internal.protocol.TokenRequest;
34 import org.openhab.binding.tesla.internal.protocol.TokenRequestPassword;
35 import org.openhab.binding.tesla.internal.protocol.TokenResponse;
36 import org.openhab.core.config.discovery.DiscoveryResult;
37 import org.openhab.core.config.discovery.DiscoveryResultBuilder;
38 import org.openhab.core.io.console.Console;
39 import org.openhab.core.io.console.extensions.AbstractConsoleCommandExtension;
40 import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
41 import org.openhab.core.thing.ThingUID;
42 import org.openhab.core.util.UIDUtils;
43 import org.osgi.service.component.annotations.Activate;
44 import org.osgi.service.component.annotations.Component;
45 import org.osgi.service.component.annotations.Reference;
46 import org.osgi.service.component.annotations.ReferenceCardinality;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
50 import com.google.gson.Gson;
53 * Console commands for interacting with the Tesla integration
55 * @author Nicolai Grødum - Initial contribution
56 * @author Kai Kreuzer - refactored to use Tesla account thing
59 @Component(service = ConsoleCommandExtension.class)
60 public class TeslaCommandExtension extends AbstractConsoleCommandExtension {
62 private static final String CMD_LOGIN = "login";
64 private final Logger logger = LoggerFactory.getLogger(TeslaCommandExtension.class);
66 @Reference(cardinality = ReferenceCardinality.OPTIONAL)
67 private @Nullable ClientBuilder injectedClientBuilder;
69 private @Nullable WebTarget tokenTarget;
71 private final TeslaAccountDiscoveryService teslaAccountDiscoveryService;
74 public TeslaCommandExtension(@Reference TeslaAccountDiscoveryService teslaAccountDiscoveryService) {
75 super("tesla", "Interact with the Tesla integration.");
76 this.teslaAccountDiscoveryService = teslaAccountDiscoveryService;
80 public void execute(String[] args, Console console) {
81 if (args.length > 0) {
82 String subCommand = args[0];
85 if (args.length == 1) {
87 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
88 console.print("Username (email): ");
89 String username = br.readLine();
90 console.println(username);
92 console.print("Password: ");
94 String pwd = br.readLine();
96 console.println("Attempting login...");
97 login(console, username, pwd);
98 } catch (Exception e) {
99 console.println(e.toString());
101 } else if (args.length == 3) {
102 login(console, args[1], args[2]);
109 console.println("Unknown command '" + subCommand + "'");
117 public List<String> getUsages() {
118 return Arrays.asList(buildCommandUsage(CMD_LOGIN + " [<user email>] [<password>]",
119 "Authenticates the user and provides a refresh token."));
122 private void login(Console console, String username, String password) {
124 Gson gson = new Gson();
126 TokenRequest token = new TokenRequestPassword(username, password);
127 String payLoad = gson.toJson(token);
129 Response response = getTokenTarget().request()
130 .post(Entity.entity(payLoad, MediaType.APPLICATION_JSON_TYPE));
132 if (response != null) {
133 if (response.getStatus() == 200 && response.hasEntity()) {
134 String responsePayLoad = response.readEntity(String.class);
135 TokenResponse tokenResponse = gson.fromJson(responsePayLoad.trim(), TokenResponse.class);
136 console.println("Refresh token: " + tokenResponse.refresh_token);
138 ThingUID thingUID = new ThingUID(TeslaBindingConstants.THING_TYPE_ACCOUNT,
139 UIDUtils.encode(username));
140 DiscoveryResult result = DiscoveryResultBuilder.create(thingUID).withLabel("Tesla Account")
141 .withProperty(TeslaBindingConstants.CONFIG_REFRESHTOKEN, tokenResponse.refresh_token)
142 .withProperty(TeslaBindingConstants.CONFIG_USERNAME, username)
143 .withRepresentationProperty(TeslaBindingConstants.CONFIG_USERNAME).build();
144 teslaAccountDiscoveryService.thingDiscovered(result);
147 "Failure: " + response.getStatus() + " " + response.getStatusInfo().getReasonPhrase());
150 } catch (Exception e) {
151 console.println("Failed to retrieve token: " + e.getMessage());
152 logger.error("Could not get refresh token.", e);
156 private synchronized WebTarget getTokenTarget() {
157 WebTarget target = this.tokenTarget;
158 if (target != null) {
163 client = ClientBuilder.newBuilder().build();
164 } catch (Exception e) {
165 // we seem to have no Jersey, so let's hope for an injected builder by CXF
166 if (this.injectedClientBuilder != null) {
167 client = injectedClientBuilder.build();
169 throw new IllegalStateException("No JAX RS Client Builder available.");
172 WebTarget teslaTarget = client.target(URI_OWNERS);
173 target = teslaTarget.path(URI_ACCESS_TOKEN);
174 this.tokenTarget = target;