Skip to content

Commit 73c70f1

Browse files
committed
Made SnaphotState capable of streaming
1 parent f8a010c commit 73c70f1

3 files changed

Lines changed: 138 additions & 85 deletions

File tree

src/org/noroomattheinn/tesla/APICall.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
import java.io.IOException;
1010
import java.util.Date;
1111
import java.util.logging.Level;
12-
import java.util.logging.Logger;
1312
import us.monoid.json.JSONException;
1413
import us.monoid.json.JSONObject;
1514
import us.monoid.web.Resty;

src/org/noroomattheinn/tesla/SnapshotState.java

Lines changed: 120 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,42 @@
2929
*/
3030

3131
public class SnapshotState extends APICall {
32-
// Class Variables
32+
33+
/*------------------------------------------------------------------------------
34+
*
35+
* Constants and Enums
36+
*
37+
*----------------------------------------------------------------------------*/
38+
private enum Keys {
39+
timestamp, odometer, speed, soc, elevation, est_heading,
40+
est_lat, est_lng, power, shift_state, range};
41+
private final Keys[] keyList = Keys.values();
42+
private final String allKeys =
43+
StringUtils.join(keyList, ',', 1, keyList.length);
44+
45+
private static final String endpointFormat =
46+
"https://streaming.vn.teslamotors.com/stream/%s/?values=%s";
3347

34-
//
35-
// Field Accessor Methods
36-
//
48+
private static final int WakeupRetries = 3;
49+
private static final int ReadTimeoutInMillis = 1 * 1000;
50+
51+
/*------------------------------------------------------------------------------
52+
*
53+
* Internal State
54+
*
55+
*----------------------------------------------------------------------------*/
56+
57+
private Vehicle vehicleWithToken = null;
58+
private BufferedReader reader = null;
59+
3760

61+
/*==============================================================================
62+
* ------- -------
63+
* ------- Public Interface To This Class -------
64+
* ------- -------
65+
*============================================================================*/
66+
67+
// Accessors
3868
public Date timestamp() {return(new Date(getLong(Keys.timestamp))); }
3969
public double speed() { return(getDouble(Keys.speed)); }
4070
public double odometer() {return(getDouble(Keys.odometer)); }
@@ -46,131 +76,141 @@ public class SnapshotState extends APICall {
4676
public int power() { return(getInteger(Keys.power)); }
4777
public String shiftState() { return(getString(Keys.shift_state)); }
4878
public int range() { return(getInteger(Keys.range)); }
79+
public String getStateName() { return "Unstreamed State"; }
4980

5081

51-
//
5282
// Constructors
53-
//
54-
5583
public SnapshotState(Vehicle v) {
5684
super(v);
5785
}
5886

5987

60-
// Accessors
61-
public String getStateName() { return "Unstreamed State"; }
62-
63-
// Update Methods
88+
/*------------------------------------------------------------------------------
89+
*
90+
* Methods overridden from APICall
91+
*
92+
*----------------------------------------------------------------------------*/
6493

6594
public boolean refresh() {
66-
BufferedReader reader = prepareToProduce();
67-
JSONObject val;
68-
if (reader != null && (val = produce(reader)) != null) {
69-
setState(val);
70-
return true;
95+
reader = null;
96+
return refreshStream();
97+
}
98+
99+
public boolean refreshStream() {
100+
// We need to be prepared to try twice just in case the reader went
101+
// stale on us since the last refresh()
102+
for (int i = 0; i < 2; i++) {
103+
prepare();
104+
JSONObject val;
105+
if (reader != null && (val = produce(reader)) != null) {
106+
setState(val);
107+
return true;
108+
}
109+
reader = null;
71110
}
72111
invalidate();
73112
return false;
74113
}
75114

76115

77-
//
78-
// Override Methods
79-
//
116+
/*------------------------------------------------------------------------------
117+
*
118+
* Methods overridden from Object
119+
*
120+
*----------------------------------------------------------------------------*/
121+
80122

81123
public String toString() {
82124
return String.format(
83-
"Time Stamp: %s\n" +
125+
"Time Stamp: %s.%s\n" +
84126
"Speed: %3.1f\n" +
85127
"Location: [(Lat: %f, Lng: %3f), Heading: %d, Elevation: %d]\n" +
86128
"Charge Info: [SoC: %d, Power: %d]\n" +
87129
"Odometer: %7.1f\n" +
88130
"Range: %d\n",
89-
timestamp().getTime(),
131+
timestamp().getTime()/1000, timestamp().getTime()%1000,
90132
speed(),
91133
estLat(), estLng(), estHeading(), elevation(),
92134
soc(), power(),
93135
odometer(), range()
94136
// Don't know what shift_state is! Always seems to be null
95137
);
96138
}
97-
98139

99-
public enum Keys {
100-
timestamp, odometer, speed, soc, elevation, est_heading,
101-
est_lat, est_lng, power, shift_state, range};
102-
103-
private static final String endpointFormat =
104-
"https://streaming.vn.teslamotors.com/stream/%s/?values=%s";
105-
106-
// Instance Variables
107-
private Keys[] keyList = Keys.values();
108-
private final String allKeys =
109-
StringUtils.join(keyList, ',', 1, keyList.length);
140+
/*------------------------------------------------------------------------------
141+
*
142+
* Methods for setting up the Streaming connection and reading the data
143+
*
144+
*----------------------------------------------------------------------------*/
145+
146+
private JSONObject produce(BufferedReader reader) {
147+
try {
148+
String line = reader.readLine();
149+
if (line == null) return null;
110150

111-
112-
private JSONObject produce(BufferedReader reader) {
113-
try {
114-
String line = reader.readLine();
115-
if (line == null) return null;
116-
117-
JSONObject jo = new JSONObject();
118-
String vals[] = line.split(",");
119-
for (int i = 0; i < keyList.length; i++) {
120-
try {
121-
jo.put(keyList[i], vals[i]);
122-
} catch (JSONException ex) {
123-
Tesla.logger.log(Level.SEVERE, "Malformed data", ex);
124-
return null;
125-
}
151+
JSONObject jo = new JSONObject();
152+
String vals[] = line.split(",");
153+
for (int i = 0; i < keyList.length; i++) {
154+
try {
155+
jo.put(keyList[i], vals[i]);
156+
} catch (JSONException ex) {
157+
Tesla.logger.log(Level.SEVERE, "Malformed data", ex);
158+
return null;
126159
}
127-
return jo;
128-
} catch (IOException ex) {
129-
Tesla.logger.log(Level.FINEST, "Timeouts are expected here...", ex);
130-
return null;
131160
}
161+
return jo;
162+
} catch (IOException ex) {
163+
Tesla.logger.log(Level.FINEST, "Timeouts are expected here...", ex);
164+
return null;
132165
}
166+
}
133167

134-
private BufferedReader prepareToProduce() {
135-
BufferedReader r = prepareInternal();
136-
if (r != null) return r;
137-
return prepareInternal(); // Try again. Auth tokens may have expired.
138-
}
168+
private void prepare() {
169+
prepareInternal();
170+
if (reader != null) return;
171+
prepareInternal(); // Try again. Auth tokens may have expired.
172+
}
139173

140-
private Vehicle vehicleWithToken = null;
141174

142-
private BufferedReader prepareInternal() {
143-
if (vehicleWithToken == null) {
144-
vehicleWithToken = getVehicleWithAuthToken(v);
145-
if (vehicleWithToken == null)
146-
return null;
147-
}
175+
private void prepareInternal() {
176+
if (reader != null) return;
177+
148178

149-
try {
150-
String endpoint = String.format(
151-
endpointFormat, vehicleWithToken.getStreamingVID(), allKeys);
152-
153-
honorRateLimit();
154-
requestCount++; // Count it even if it fails...
155-
TextResource r = getAuthAPI(vehicleWithToken).text(endpoint);
156-
return new BufferedReader(new InputStreamReader(r.stream()));
157-
} catch (IOException ex) {
158-
// Timed out or other problem
159-
Tesla.logger.log(Level.INFO, "Failed getting streaming data. HANDLED.", ex);
160-
}
161-
vehicleWithToken = null; // Tokens may have expired, force refetch
162-
return null;
179+
if (vehicleWithToken == null) {
180+
vehicleWithToken = getVehicleWithAuthToken(v);
181+
if (vehicleWithToken == null) return;
163182
}
183+
184+
String endpoint = String.format(
185+
endpointFormat, vehicleWithToken.getStreamingVID(), allKeys);
186+
187+
honorRateLimit();
188+
requestCount++; // Count it even if it fails...
164189

190+
try {
191+
TextResource r = getAuthAPI(vehicleWithToken).text(endpoint);
192+
reader = new BufferedReader(new InputStreamReader(r.stream()));
193+
} catch (IOException ex) {
194+
// Timed out or other problem
195+
Tesla.logger.log(Level.INFO, "Failed getting streaming data. HANDLED.", ex.getMessage());
196+
vehicleWithToken = null; // Tokens may have expired, force refetch
197+
reader = null;
198+
}
199+
}
200+
201+
/*------------------------------------------------------------------------------
202+
*
203+
* This section contains the methods and classes necessary to get auth
204+
* tokens and create an authenticated connection to Tesla
205+
*
206+
*----------------------------------------------------------------------------*/
165207

166208
private void setAuthHeader(Resty api, String username, String authToken) {
167209
byte[] authString = (username + ":" + authToken).getBytes();
168210
String encodedString = Base64.encodeBase64String(authString);
169211
api.withHeader("Authorization", "Basic " + encodedString);
170212
}
171213

172-
private static final int WakeupRetries = 3;
173-
private static final int ReadTimeoutInMillis = 5 * 1000;
174214

175215
private Vehicle getVehicleWithAuthToken(Vehicle basedOn) {
176216
String vid = basedOn.getVID();

src/org/noroomattheinn/tesla/test/StreamingHandler.java

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
package org.noroomattheinn.tesla.test;
88

99
import org.noroomattheinn.utils.Handler;
10-
import org.noroomattheinn.tesla.StreamingState;
1110
import org.noroomattheinn.tesla.SnapshotState;
1211
import org.noroomattheinn.tesla.Vehicle;
12+
import org.noroomattheinn.utils.Utils;
1313

1414
/**
1515
* StreamHandler
@@ -28,20 +28,34 @@ public class StreamingHandler extends TeslaHandler {
2828

2929

3030
StreamingHandler(Vehicle v) {
31-
super(Name, Description, v);
31+
super(Name, Description, "s", v);
3232
state = new SnapshotState(v);
3333
repl.addHandler(new StreamingHandler.DisplayHandler());
34+
repl.addHandler(new StreamingHandler.StreamHandler());
3435
}
3536

3637

3738
//
3839
// Handler classes
3940
//
4041

42+
class StreamHandler extends Handler {
43+
StreamHandler() { super("stream", "Display streaming state", "s"); }
44+
public boolean execute() {
45+
for (int i = 0; i < 10; i++) {
46+
System.out.println("Streaming Status:");
47+
if (state.refreshStream()) {
48+
System.out.println(state);
49+
}
50+
Utils.sleep(500);
51+
}
52+
return true;
53+
}
54+
}
55+
4156
class DisplayHandler extends Handler {
42-
DisplayHandler() { super("display", "Display streaming state", "d"); }
57+
DisplayHandler() { super("display", "Display snapshot state", "d"); }
4358
public boolean execute() {
44-
System.out.println("Streaming Status:");
4559
if (state.refresh()) {
4660
System.out.println(state);
4761
}

0 commit comments

Comments
 (0)