tesla-fleet-api 0.9.5__py3-none-any.whl → 0.9.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tesla_fleet_api/const.py +1 -1
- tesla_fleet_api/exceptions.py +239 -46
- tesla_fleet_api/pb2/__init__.pyi +9 -0
- tesla_fleet_api/pb2/car_server_pb2.py +164 -386
- tesla_fleet_api/pb2/car_server_pb2.pyi +904 -0
- tesla_fleet_api/pb2/common_pb2.py +26 -60
- tesla_fleet_api/pb2/common_pb2.pyi +130 -0
- tesla_fleet_api/pb2/errors_pb2.py +10 -22
- tesla_fleet_api/pb2/errors_pb2.pyi +32 -0
- tesla_fleet_api/pb2/keys_pb2.py +8 -16
- tesla_fleet_api/pb2/keys_pb2.pyi +21 -0
- tesla_fleet_api/pb2/managed_charging_pb2.py +8 -14
- tesla_fleet_api/pb2/managed_charging_pb2.pyi +17 -0
- tesla_fleet_api/pb2/signatures_pb2.py +28 -75
- tesla_fleet_api/pb2/signatures_pb2.pyi +152 -0
- tesla_fleet_api/pb2/universal_message_pb2.py +22 -78
- tesla_fleet_api/pb2/universal_message_pb2.pyi +148 -0
- tesla_fleet_api/pb2/vcsec_pb2.py +70 -236
- tesla_fleet_api/pb2/vcsec_pb2.pyi +482 -0
- tesla_fleet_api/pb2/vehicle_pb2.py +114 -267
- tesla_fleet_api/pb2/vehicle_pb2.pyi +1183 -0
- tesla_fleet_api/teslafleetapi.py +7 -5
- tesla_fleet_api/teslafleetoauth.py +1 -1
- tesla_fleet_api/teslemetry.py +2 -2
- tesla_fleet_api/vehicle.py +1 -1
- tesla_fleet_api/vehiclesigned.py +143 -102
- {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/METADATA +12 -3
- tesla_fleet_api-0.9.7.dist-info/RECORD +42 -0
- {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/WHEEL +1 -1
- tesla_fleet_api-0.9.5.dist-info/RECORD +0 -33
- {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/LICENSE +0 -0
- {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/top_level.txt +0 -0
tesla_fleet_api/teslafleetapi.py
CHANGED
@@ -106,6 +106,11 @@ class TeslaFleetApi:
|
|
106
106
|
if access_token := await self.refresh_hook():
|
107
107
|
self.access_token = access_token
|
108
108
|
|
109
|
+
headers = {
|
110
|
+
"Authorization": f"Bearer {self.access_token}",
|
111
|
+
"X-Library": f"python tesla_fleet_api {VERSION}",
|
112
|
+
}
|
113
|
+
|
109
114
|
# Remove None values from params and json
|
110
115
|
if params:
|
111
116
|
params = {k: v for k, v in params.items() if v is not None}
|
@@ -113,15 +118,12 @@ class TeslaFleetApi:
|
|
113
118
|
if json:
|
114
119
|
json = {k: v for k, v in json.items() if v is not None}
|
115
120
|
LOGGER.debug("Body: %s", dumps(json))
|
121
|
+
headers["Content-Type"] = "application/json"
|
116
122
|
|
117
123
|
async with self.session.request(
|
118
124
|
method,
|
119
125
|
f"{self.server}/{path}",
|
120
|
-
headers=
|
121
|
-
"Authorization": f"Bearer {self.access_token}",
|
122
|
-
"Content-Type": "application/json",
|
123
|
-
"X-Library": f"python tesla_fleet_api {VERSION}",
|
124
|
-
},
|
126
|
+
headers=headers,
|
125
127
|
json=json,
|
126
128
|
params=params,
|
127
129
|
) as resp:
|
@@ -45,7 +45,7 @@ class TeslaFleetOAuth(TeslaFleetApi):
|
|
45
45
|
"""Get the login URL."""
|
46
46
|
if self.redirect_uri is None:
|
47
47
|
raise ValueError("Redirect URI is missing")
|
48
|
-
return f"https://auth.tesla.com/oauth2/v3/authorize?response_type=code&
|
48
|
+
return f"https://auth.tesla.com/oauth2/v3/authorize?response_type=code&client_id={self.client_id}&redirect_uri={self.redirect_uri}&scope={'+'.join(scopes)}&state={state}"
|
49
49
|
|
50
50
|
async def get_refresh_token(self, code: str) -> None:
|
51
51
|
"""Get the refresh token."""
|
tesla_fleet_api/teslemetry.py
CHANGED
@@ -96,11 +96,11 @@ class Teslemetry(TeslaFleetApi):
|
|
96
96
|
)
|
97
97
|
).get("response")
|
98
98
|
|
99
|
-
async def
|
99
|
+
async def vehicle_data_refresh(self, vin: str) -> dict[str, Any]:
|
100
100
|
"""Force a refresh of the vehicle data."""
|
101
101
|
return await self._request(
|
102
102
|
Method.GET,
|
103
|
-
f"api/
|
103
|
+
f"api/refresh/{vin}",
|
104
104
|
)
|
105
105
|
|
106
106
|
async def _request(
|
tesla_fleet_api/vehicle.py
CHANGED
@@ -44,7 +44,7 @@ class Vehicle:
|
|
44
44
|
|
45
45
|
def pre2021(self, vin: str) -> bool:
|
46
46
|
"""Checks if a vehicle is a pre-2021 model S or X."""
|
47
|
-
return vin[9] <= "L" and vin[
|
47
|
+
return vin[3] in ["S", "X"] and (vin[9] <= "L" or (vin[9] == "M" and vin[7] in ['1', '2', '3', '4']))
|
48
48
|
|
49
49
|
async def actuate_trunk(
|
50
50
|
self, vehicle_tag: str | int, which_trunk: Trunk | str
|
tesla_fleet_api/vehiclesigned.py
CHANGED
@@ -8,8 +8,11 @@ import hmac
|
|
8
8
|
import hashlib
|
9
9
|
from cryptography.hazmat.primitives.asymmetric import ec
|
10
10
|
from cryptography.hazmat.primitives.serialization import PublicFormat, Encoding
|
11
|
+
from asyncio import Lock, sleep
|
11
12
|
|
12
|
-
from .
|
13
|
+
from tesla_fleet_api.pb2.errors_pb2 import GenericError_E
|
14
|
+
|
15
|
+
from .exceptions import MESSAGE_FAULTS, SIGNED_MESSAGE_INFORMATION_FAULTS, TeslaFleetMessageFaultIncorrectEpoch, TeslaFleetMessageFaultInvalidTokenOrCounter
|
13
16
|
|
14
17
|
from .const import (
|
15
18
|
LOGGER,
|
@@ -22,17 +25,15 @@ from .const import (
|
|
22
25
|
from .vehiclespecific import VehicleSpecific
|
23
26
|
|
24
27
|
from .pb2.universal_message_pb2 import (
|
25
|
-
# OPERATIONSTATUS_OK,
|
26
|
-
MESSAGEFAULT_ERROR_INCORRECT_EPOCH,
|
27
28
|
OPERATIONSTATUS_WAIT,
|
28
29
|
OPERATIONSTATUS_ERROR,
|
29
30
|
DOMAIN_VEHICLE_SECURITY,
|
30
31
|
DOMAIN_INFOTAINMENT,
|
31
32
|
Domain,
|
32
|
-
# MessageFault_E,
|
33
33
|
RoutableMessage,
|
34
34
|
)
|
35
35
|
from .pb2.car_server_pb2 import (
|
36
|
+
Response,
|
36
37
|
Action,
|
37
38
|
MediaPlayAction,
|
38
39
|
VehicleAction,
|
@@ -82,6 +83,8 @@ from .pb2.car_server_pb2 import (
|
|
82
83
|
from .pb2.vehicle_pb2 import VehicleState
|
83
84
|
from .pb2.vcsec_pb2 import (
|
84
85
|
# SignedMessage_information_E,
|
86
|
+
OPERATIONSTATUS_OK,
|
87
|
+
FromVCSECMessage,
|
85
88
|
UnsignedMessage,
|
86
89
|
RKEAction_E,
|
87
90
|
ClosureMoveRequest,
|
@@ -91,7 +94,6 @@ from .pb2.signatures_pb2 import (
|
|
91
94
|
SIGNATURE_TYPE_HMAC_PERSONALIZED,
|
92
95
|
TAG_DOMAIN,
|
93
96
|
TAG_SIGNATURE_TYPE,
|
94
|
-
SignatureData,
|
95
97
|
SessionInfo,
|
96
98
|
HMAC_Personalized_Signature_Data,
|
97
99
|
TAG_PERSONALIZATION,
|
@@ -102,7 +104,6 @@ from .pb2.signatures_pb2 import (
|
|
102
104
|
)
|
103
105
|
from .pb2.common_pb2 import (
|
104
106
|
Void,
|
105
|
-
LatLong,
|
106
107
|
PreconditioningTimes,
|
107
108
|
OffPeakChargingTimes,
|
108
109
|
# ChargeSchedule,
|
@@ -121,35 +122,38 @@ class Session:
|
|
121
122
|
epoch: bytes
|
122
123
|
delta: int
|
123
124
|
hmac: bytes
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
self.
|
129
|
-
|
130
|
-
|
125
|
+
publicKey: bytes
|
126
|
+
lock: Lock
|
127
|
+
|
128
|
+
def __init__(self):
|
129
|
+
self.lock = Lock()
|
130
|
+
|
131
|
+
def update(self, sessionInfo: SessionInfo, privateKey: ec.EllipticCurvePrivateKey):
|
132
|
+
"""Update the session with new information"""
|
133
|
+
self.counter = sessionInfo.counter
|
134
|
+
self.epoch = sessionInfo.epoch
|
135
|
+
self.delta = int(time.time()) - sessionInfo.clock_time
|
136
|
+
self.publicKey = sessionInfo.publicKey
|
137
|
+
self.key = hashlib.sha1(
|
138
|
+
privateKey.exchange(
|
139
|
+
ec.ECDH(),
|
140
|
+
ec.EllipticCurvePublicKey.from_encoded_point(
|
141
|
+
ec.SECP256R1(), self.publicKey
|
142
|
+
),
|
143
|
+
)
|
144
|
+
).digest()[:16]
|
131
145
|
self.hmac = hmac.new(
|
132
|
-
key, "authenticated command".encode(), hashlib.sha256
|
146
|
+
self.key, "authenticated command".encode(), hashlib.sha256
|
133
147
|
).digest()
|
134
148
|
|
135
149
|
def get(self) -> HMAC_Personalized_Signature_Data:
|
136
150
|
"""Sign a command and return session metadata"""
|
137
|
-
self.counter
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
def tag(
|
145
|
-
self,
|
146
|
-
signature: HMAC_Personalized_Signature_Data,
|
147
|
-
command: bytes,
|
148
|
-
metadata: bytes,
|
149
|
-
) -> HMAC_Personalized_Signature_Data:
|
150
|
-
"""Sign a command and return the signature"""
|
151
|
-
signature.tag = hmac.new(self.hmac, metadata + command, hashlib.sha256).digest()
|
152
|
-
return signature
|
151
|
+
self.counter = self.counter+1
|
152
|
+
return HMAC_Personalized_Signature_Data(
|
153
|
+
epoch=self.epoch,
|
154
|
+
counter=self.counter,
|
155
|
+
expires_at=int(time.time()) - self.delta + 10,
|
156
|
+
)
|
153
157
|
|
154
158
|
|
155
159
|
class VehicleSigned(VehicleSpecific):
|
@@ -177,22 +181,35 @@ class VehicleSigned(VehicleSpecific):
|
|
177
181
|
self._from_destination = randbytes(16)
|
178
182
|
self._sessions = {}
|
179
183
|
|
180
|
-
async def
|
184
|
+
async def _send(self, msg: RoutableMessage) -> RoutableMessage:
|
181
185
|
"""Serialize a message and send to the signed command endpoint."""
|
182
|
-
routable_message = base64.b64encode(msg.SerializeToString()).decode()
|
183
|
-
resp_json = await self.signed_command(routable_message)
|
184
|
-
resp = RoutableMessage()
|
185
|
-
resp.ParseFromString(base64.b64decode(resp_json["response"]))
|
186
186
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
187
|
+
async with self._sessions[msg.to_destination.domain].lock:
|
188
|
+
resp = await self.signed_command(
|
189
|
+
base64.b64encode(msg.SerializeToString()).decode()
|
190
|
+
)
|
191
|
+
|
192
|
+
resp_msg = RoutableMessage.FromString(base64.b64decode(resp["response"]))
|
191
193
|
|
192
|
-
|
194
|
+
# Check UUID?
|
195
|
+
# Check RoutingAdress?
|
193
196
|
|
194
|
-
|
197
|
+
if resp_msg.session_info:
|
198
|
+
self._sessions[resp_msg.from_destination.domain].update(
|
199
|
+
SessionInfo.FromString(resp_msg.session_info), self.private_key
|
200
|
+
)
|
201
|
+
|
202
|
+
if resp_msg.signedMessageStatus.signed_message_fault:
|
203
|
+
raise MESSAGE_FAULTS[resp_msg.signedMessageStatus.signed_message_fault]
|
204
|
+
|
205
|
+
return resp_msg
|
206
|
+
|
207
|
+
async def _handshake(self, domain: Domain) -> Session:
|
195
208
|
"""Perform a handshake with the vehicle."""
|
209
|
+
if session := self._sessions.get(domain):
|
210
|
+
return session
|
211
|
+
self._sessions[domain] = Session()
|
212
|
+
|
196
213
|
LOGGER.debug(f"Handshake with domain {Domain.Name(domain)}")
|
197
214
|
msg = RoutableMessage()
|
198
215
|
msg.to_destination.domain = domain
|
@@ -201,51 +218,34 @@ class VehicleSigned(VehicleSpecific):
|
|
201
218
|
msg.uuid = randbytes(16)
|
202
219
|
|
203
220
|
# Send handshake message
|
204
|
-
|
205
|
-
|
206
|
-
# Get session info with publicKey, epoch, and clock_time
|
207
|
-
info = SessionInfo.FromString(resp.session_info)
|
208
|
-
|
209
|
-
vehicle_public_key = info.publicKey
|
221
|
+
await self._send(msg)
|
210
222
|
|
211
|
-
|
212
|
-
shared = self.private_key.exchange(
|
213
|
-
ec.ECDH(),
|
214
|
-
ec.EllipticCurvePublicKey.from_encoded_point(
|
215
|
-
ec.SECP256R1(), vehicle_public_key
|
216
|
-
),
|
217
|
-
)
|
218
|
-
|
219
|
-
self._sessions[domain] = Session(
|
220
|
-
key=hashlib.sha1(shared).digest()[:16],
|
221
|
-
counter=info.counter,
|
222
|
-
epoch=info.epoch,
|
223
|
-
delta=int(time.time()) - info.clock_time,
|
224
|
-
)
|
223
|
+
return self._sessions[domain]
|
225
224
|
|
226
225
|
async def _sendVehicleSecurity(self, command: UnsignedMessage) -> dict[str, Any]:
|
227
226
|
"""Sign and send a message to Infotainment computer."""
|
228
|
-
|
229
|
-
await self._handshake(DOMAIN_VEHICLE_SECURITY)
|
230
|
-
return await self._send(DOMAIN_VEHICLE_SECURITY, command.SerializeToString())
|
227
|
+
return await self._sign(DOMAIN_VEHICLE_SECURITY, command.SerializeToString())
|
231
228
|
|
232
229
|
async def _sendInfotainment(self, command: Action) -> dict[str, Any]:
|
233
230
|
"""Sign and send a message to Infotainment computer."""
|
234
|
-
|
235
|
-
await self._handshake(DOMAIN_INFOTAINMENT)
|
236
|
-
return await self._send(DOMAIN_INFOTAINMENT, command.SerializeToString())
|
231
|
+
return await self._sign(DOMAIN_INFOTAINMENT, command.SerializeToString())
|
237
232
|
|
238
|
-
async def
|
233
|
+
async def _sign(
|
234
|
+
self, domain: Domain, command: bytes, attempt: int = 1
|
235
|
+
) -> dict[str, Any]:
|
239
236
|
"""Send a signed message to the vehicle."""
|
240
237
|
LOGGER.debug(f"Sending to domain {Domain.Name(domain)}")
|
238
|
+
|
239
|
+
session = await self._handshake(domain)
|
240
|
+
hmac_personalized = session.get()
|
241
|
+
|
241
242
|
msg = RoutableMessage()
|
242
243
|
msg.to_destination.domain = domain
|
243
244
|
msg.from_destination.routing_address = self._from_destination
|
244
245
|
msg.protobuf_message_as_bytes = command
|
245
246
|
msg.uuid = randbytes(16)
|
246
247
|
|
247
|
-
|
248
|
-
metadata = [
|
248
|
+
metadata = bytes([
|
249
249
|
TAG_SIGNATURE_TYPE,
|
250
250
|
1,
|
251
251
|
SIGNATURE_TYPE_HMAC_PERSONALIZED,
|
@@ -256,46 +256,90 @@ class VehicleSigned(VehicleSpecific):
|
|
256
256
|
17,
|
257
257
|
*self.vin.encode(),
|
258
258
|
TAG_EPOCH,
|
259
|
-
len(
|
260
|
-
*
|
259
|
+
len(hmac_personalized.epoch),
|
260
|
+
*hmac_personalized.epoch,
|
261
261
|
TAG_EXPIRES_AT,
|
262
262
|
4,
|
263
|
-
*struct.pack(">I",
|
263
|
+
*struct.pack(">I", hmac_personalized.expires_at),
|
264
264
|
TAG_COUNTER,
|
265
265
|
4,
|
266
|
-
*struct.pack(">I",
|
266
|
+
*struct.pack(">I", hmac_personalized.counter),
|
267
267
|
TAG_END,
|
268
|
-
]
|
269
|
-
|
270
|
-
session = self._sessions[domain].tag(session, command, bytes(metadata))
|
268
|
+
])
|
271
269
|
|
272
|
-
|
273
|
-
|
274
|
-
|
270
|
+
hmac_personalized.tag = hmac.new(
|
271
|
+
session.hmac, metadata + command, hashlib.sha256
|
272
|
+
).digest()
|
275
273
|
|
276
|
-
|
274
|
+
# I think this whole section could be improved
|
275
|
+
msg.signature_data.HMAC_Personalized_data.CopyFrom(hmac_personalized)
|
276
|
+
msg.signature_data.signer_identity.public_key = self._public_key
|
277
277
|
|
278
278
|
try:
|
279
|
-
resp = await self.
|
280
|
-
except
|
279
|
+
resp = await self._send(msg)
|
280
|
+
except (
|
281
|
+
TeslaFleetMessageFaultIncorrectEpoch,
|
282
|
+
TeslaFleetMessageFaultInvalidTokenOrCounter,
|
283
|
+
) as e:
|
281
284
|
attempt += 1
|
282
285
|
if attempt > 3:
|
283
286
|
# We tried 3 times, give up, raise the error
|
284
287
|
raise e
|
285
|
-
|
286
|
-
await self._handshake(domain)
|
287
|
-
LOGGER.info(f"Handshake complete, retrying message to {Domain.Name(domain)}")
|
288
|
-
return await self._send(domain, command, attempt)
|
288
|
+
return await self._sign(domain, command, attempt)
|
289
289
|
|
290
290
|
if resp.signedMessageStatus.operation_status == OPERATIONSTATUS_WAIT:
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
291
|
+
attempt += 1
|
292
|
+
if attempt > 3:
|
293
|
+
# We tried 3 times, give up, raise the error
|
294
|
+
return {"response": {"result": False, "reason": "Too many retries"}}
|
295
|
+
async with session.lock:
|
296
|
+
await sleep(2)
|
297
|
+
return await self._sign(domain, command, attempt)
|
298
|
+
|
299
|
+
if resp.HasField("protobuf_message_as_bytes"):
|
300
|
+
if(resp.from_destination.domain == DOMAIN_VEHICLE_SECURITY):
|
301
|
+
vcsec = FromVCSECMessage.FromString(resp.protobuf_message_as_bytes)
|
302
|
+
LOGGER.debug("VCSEC Response: %s", vcsec)
|
303
|
+
if vcsec.HasField("nominalError"):
|
304
|
+
LOGGER.error("Command failed with reason: %s", vcsec.nominalError.genericError)
|
305
|
+
return {
|
306
|
+
"response": {
|
307
|
+
"result": False,
|
308
|
+
"reason": GenericError_E.Name(vcsec.nominalError.genericError)
|
309
|
+
}
|
310
|
+
}
|
311
|
+
elif vcsec.commandStatus.operationStatus == OPERATIONSTATUS_OK:
|
312
|
+
return {"response": {"result": True, "reason": ""}}
|
313
|
+
elif vcsec.commandStatus.operationStatus == OPERATIONSTATUS_WAIT:
|
314
|
+
attempt += 1
|
315
|
+
if attempt > 3:
|
316
|
+
# We tried 3 times, give up, raise the error
|
317
|
+
return {"response": {"result": False, "reason": "Too many retries"}}
|
318
|
+
async with session.lock:
|
319
|
+
await sleep(2)
|
320
|
+
return await self._sign(domain, command, attempt)
|
321
|
+
elif vcsec.commandStatus.operationStatus == OPERATIONSTATUS_ERROR:
|
322
|
+
if(resp.HasField("signedMessageStatus")):
|
323
|
+
raise SIGNED_MESSAGE_INFORMATION_FAULTS[vcsec.commandStatus.signedMessageStatus.signedMessageInformation]
|
324
|
+
|
325
|
+
elif(resp.from_destination.domain == DOMAIN_INFOTAINMENT):
|
326
|
+
response = Response.FromString(resp.protobuf_message_as_bytes)
|
327
|
+
LOGGER.debug("Infotainment Response: %s", response)
|
328
|
+
if (response.HasField("ping")):
|
329
|
+
print(response.ping)
|
330
|
+
return {
|
331
|
+
"response": {
|
332
|
+
"result": True,
|
333
|
+
"reason": response.ping.local_timestamp
|
334
|
+
}
|
335
|
+
}
|
336
|
+
if response.HasField("actionStatus"):
|
337
|
+
return {
|
338
|
+
"response": {
|
339
|
+
"result": response.actionStatus.result == OPERATIONSTATUS_OK,
|
340
|
+
"reason": response.actionStatus.result_reason.plain_text or ""
|
341
|
+
}
|
342
|
+
}
|
299
343
|
|
300
344
|
return {"response": {"result": True, "reason": ""}}
|
301
345
|
|
@@ -975,6 +1019,7 @@ class VehicleSigned(VehicleSpecific):
|
|
975
1019
|
"""Controls the panoramic sunroof on the Model S."""
|
976
1020
|
if isinstance(state, SunRoofCommand):
|
977
1021
|
state = state.value
|
1022
|
+
action = VehicleControlSunroofOpenCloseAction()
|
978
1023
|
match state:
|
979
1024
|
case "vent":
|
980
1025
|
action = VehicleControlSunroofOpenCloseAction(vent=Void())
|
@@ -986,9 +1031,7 @@ class VehicleSigned(VehicleSpecific):
|
|
986
1031
|
return await self._sendInfotainment(
|
987
1032
|
Action(
|
988
1033
|
vehicleAction=VehicleAction(
|
989
|
-
vehicleControlSunroofOpenCloseAction=
|
990
|
-
state=state
|
991
|
-
)
|
1034
|
+
vehicleControlSunroofOpenCloseAction=action
|
992
1035
|
)
|
993
1036
|
)
|
994
1037
|
)
|
@@ -1004,10 +1047,8 @@ class VehicleSigned(VehicleSpecific):
|
|
1004
1047
|
"""Turns on HomeLink (used to open and close garage doors)."""
|
1005
1048
|
action = VehicleControlTriggerHomelinkAction()
|
1006
1049
|
if lat is not None and lon is not None:
|
1007
|
-
location =
|
1008
|
-
location.
|
1009
|
-
location.longitude = lon
|
1010
|
-
action.location = location
|
1050
|
+
action.location.latitude = lat
|
1051
|
+
action.location.longitude = lon
|
1011
1052
|
if token is not None:
|
1012
1053
|
action.token = token
|
1013
1054
|
|
@@ -1,8 +1,8 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.2
|
2
2
|
Name: tesla_fleet_api
|
3
|
-
Version: 0.9.
|
3
|
+
Version: 0.9.7
|
4
4
|
Summary: Tesla Fleet API library for Python
|
5
|
-
Home-page: https://github.com/Teslemetry/
|
5
|
+
Home-page: https://github.com/Teslemetry/python-tesla-fleet-api
|
6
6
|
Author: Brett Adams
|
7
7
|
Author-email: hello@teslemetry.com
|
8
8
|
Classifier: Development Status :: 4 - Beta
|
@@ -17,6 +17,15 @@ Requires-Dist: aiofiles
|
|
17
17
|
Requires-Dist: aiolimiter
|
18
18
|
Requires-Dist: cryptography
|
19
19
|
Requires-Dist: protobuf
|
20
|
+
Dynamic: author
|
21
|
+
Dynamic: author-email
|
22
|
+
Dynamic: classifier
|
23
|
+
Dynamic: description
|
24
|
+
Dynamic: description-content-type
|
25
|
+
Dynamic: home-page
|
26
|
+
Dynamic: requires-dist
|
27
|
+
Dynamic: requires-python
|
28
|
+
Dynamic: summary
|
20
29
|
|
21
30
|
# Tesla Fleet Api
|
22
31
|
Python library for Tesla Fleet API and Teslemetry.
|
@@ -0,0 +1,42 @@
|
|
1
|
+
tesla_fleet_api/__init__.py,sha256=BVZUDsfaxT05tAfcMHHWiyFyXwmDOx_wP_IHZBscgho,729
|
2
|
+
tesla_fleet_api/charging.py,sha256=N_mc8axrXj3iduqLj_jCt4Vx86tHqe3xqQT4R1R7HvU,1689
|
3
|
+
tesla_fleet_api/const.py,sha256=mXVzA4arIzrL9WOnfvqEtf2ImNnje36hG7kJkHKRpXc,12888
|
4
|
+
tesla_fleet_api/energy.py,sha256=S7D75MPuMVsHgkyUcFfMqjGCLZBM5YVFlWLEHbaX-zw,5957
|
5
|
+
tesla_fleet_api/energyspecific.py,sha256=UfeaGE59aoAa8UhpQCXUi0sOrNCA40xZlqwF73BXTVY,4254
|
6
|
+
tesla_fleet_api/exceptions.py,sha256=qnRWqPJ_5gia4-j3o4mP5OwUuBRtC3SAbZKo-_XSRiI,29729
|
7
|
+
tesla_fleet_api/partner.py,sha256=1vIBUaxKLIfqcC0X6VXZN0dMAzj_CLNPUMjA6QVqZ1k,1223
|
8
|
+
tesla_fleet_api/ratecalculator.py,sha256=4lz8yruUeouHXh_3ezsXX-CTpIegp1T1J4VuRV_qdHA,1791
|
9
|
+
tesla_fleet_api/teslafleetapi.py,sha256=8j-kvV6_oCuIlDdS5kWlCbo9chWsT48Gn2iKt3uOAjg,7409
|
10
|
+
tesla_fleet_api/teslafleetoauth.py,sha256=NmzycAeg68sWASjiWan3B5LdIgrfmoLTDqLHYCmoKKg,4108
|
11
|
+
tesla_fleet_api/teslafleetopensource.py,sha256=TJfVPcqJlA1b3kMoGuLr-g5Gn8UDyYsTZhjvGY1MtIk,2007
|
12
|
+
tesla_fleet_api/teslemetry.py,sha256=_n59RQvJKl82ylLe09bLY_8iyfjz_DHqCdRVsWeif4s,3308
|
13
|
+
tesla_fleet_api/tessie.py,sha256=4dBYxe1G2v9JvJGRbb01wXrAmvWT4jOfV4f_VQE_vkE,2302
|
14
|
+
tesla_fleet_api/user.py,sha256=TZE2oh-n5zrhKXmGRuiNL9voKVODD7rBhGE_IObYVGA,1179
|
15
|
+
tesla_fleet_api/vehicle.py,sha256=mSFJG-bLBNh_iSJnruk9EZSypZUxMpKwMgKA9_8CPDc,32146
|
16
|
+
tesla_fleet_api/vehiclesigned.py,sha256=uwfX3MwPAtn5Otf5jUwSGuKWDVbswd3dDnNjPoxoYrM,41863
|
17
|
+
tesla_fleet_api/vehiclespecific.py,sha256=P7KI8MqUbAyM2cfDC8NqbJXzGL2ZsOIx3IBeqB8xYQY,20656
|
18
|
+
tesla_fleet_api/pb2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
+
tesla_fleet_api/pb2/__init__.pyi,sha256=qFXWNIgl71wB260u-XPzaAwWAHL6krw21q-aXnBtop0,252
|
20
|
+
tesla_fleet_api/pb2/car_server_pb2.py,sha256=v_eb4NDIkx_ZYPYW29_EFRky5vQ4b2q14gwuQSbouYw,29202
|
21
|
+
tesla_fleet_api/pb2/car_server_pb2.pyi,sha256=qkig9HEsOE4Dk2-r38BAWOyALqt7CtUnlirgSVt_oa8,46334
|
22
|
+
tesla_fleet_api/pb2/common_pb2.py,sha256=C5O6BBTckU3F-XItLfivaPG_XVCnzF_JX4mpVfM_jFk,3931
|
23
|
+
tesla_fleet_api/pb2/common_pb2.pyi,sha256=8aZiigp74MfSOMpHtMw0D9Jj0kwPz1zV_BIZfVWhh_0,5012
|
24
|
+
tesla_fleet_api/pb2/errors_pb2.py,sha256=nfOvriyjVgVxnJZIAYNRHiBa1_14dOXhC9Pokc5anV8,1631
|
25
|
+
tesla_fleet_api/pb2/errors_pb2.pyi,sha256=CNsAR7Oe6wavnqjzhInEyAFxMio6TtXfaNT0DUztn6o,1478
|
26
|
+
tesla_fleet_api/pb2/keys_pb2.py,sha256=-hyVP9-W1DypTYLaWwkOSUzgia6l9R3M9wUIgvNs-T0,1252
|
27
|
+
tesla_fleet_api/pb2/keys_pb2.pyi,sha256=HH-TfhE5ihwmoPCGdiVnZ5B7KkaMJglEpusgLc1J02M,676
|
28
|
+
tesla_fleet_api/pb2/managed_charging_pb2.py,sha256=4crkLo6uC0YPkgw90jRjAqlGMFnRze_koUt2-pw14m4,1430
|
29
|
+
tesla_fleet_api/pb2/managed_charging_pb2.pyi,sha256=SqEmrfknTfzYTUYHtsoCpt1Fw2YpU3OyQllX247UfyQ,1227
|
30
|
+
tesla_fleet_api/pb2/signatures_pb2.py,sha256=TRaJ6lzmJtryhhmBC_PbYzftc-pqCmwC6wuBCXHeuTg,4734
|
31
|
+
tesla_fleet_api/pb2/signatures_pb2.pyi,sha256=-OGm9ctBnEJiXk-3nkFCPRTxKgFiqFgMbKeq3x2zGGM,6101
|
32
|
+
tesla_fleet_api/pb2/universal_message_pb2.py,sha256=UklH73qoYsqxylie6IK8iIcw2tmykSqDiaBKSWz66OQ,5093
|
33
|
+
tesla_fleet_api/pb2/universal_message_pb2.pyi,sha256=a_RygTJL26v0rA7QuUwsxiG1_ZBcliwXCqOAqTIJ6UE,7647
|
34
|
+
tesla_fleet_api/pb2/vcsec_pb2.py,sha256=PDv9TfiXnNs6sQ0D5vBrsSSPinSqu3eBUwvTcG8xMWo,15919
|
35
|
+
tesla_fleet_api/pb2/vcsec_pb2.pyi,sha256=cyK1uyRtDjRVqVlyl5uRQYY1RhFlWSJheLg3PGfs-_s,28524
|
36
|
+
tesla_fleet_api/pb2/vehicle_pb2.py,sha256=bqyFJM-1qZ7W9XKREINhYZx8yXAudmq6W8_Pdfkhbkk,44711
|
37
|
+
tesla_fleet_api/pb2/vehicle_pb2.pyi,sha256=sAUW_9aVB8NqJCnhZjXMLfqfePLVZv_7PfSKZKEBaQA,74251
|
38
|
+
tesla_fleet_api-0.9.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
39
|
+
tesla_fleet_api-0.9.7.dist-info/METADATA,sha256=kzwE1qQtPqXFC5sWlf4bvF9wA4f9tpqan5b10uEganA,4022
|
40
|
+
tesla_fleet_api-0.9.7.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
41
|
+
tesla_fleet_api-0.9.7.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
|
42
|
+
tesla_fleet_api-0.9.7.dist-info/RECORD,,
|
@@ -1,33 +0,0 @@
|
|
1
|
-
tesla_fleet_api/__init__.py,sha256=BVZUDsfaxT05tAfcMHHWiyFyXwmDOx_wP_IHZBscgho,729
|
2
|
-
tesla_fleet_api/charging.py,sha256=N_mc8axrXj3iduqLj_jCt4Vx86tHqe3xqQT4R1R7HvU,1689
|
3
|
-
tesla_fleet_api/const.py,sha256=40Oi7XwilcT6ZbNcQnm9hOawKNY4JLrfZA0Xc4H7g7s,12888
|
4
|
-
tesla_fleet_api/energy.py,sha256=S7D75MPuMVsHgkyUcFfMqjGCLZBM5YVFlWLEHbaX-zw,5957
|
5
|
-
tesla_fleet_api/energyspecific.py,sha256=UfeaGE59aoAa8UhpQCXUi0sOrNCA40xZlqwF73BXTVY,4254
|
6
|
-
tesla_fleet_api/exceptions.py,sha256=KUozIEvZv9Haal6ofRb0SFHQQBe8UH-lEAFVwkJFzW0,20942
|
7
|
-
tesla_fleet_api/partner.py,sha256=1vIBUaxKLIfqcC0X6VXZN0dMAzj_CLNPUMjA6QVqZ1k,1223
|
8
|
-
tesla_fleet_api/ratecalculator.py,sha256=4lz8yruUeouHXh_3ezsXX-CTpIegp1T1J4VuRV_qdHA,1791
|
9
|
-
tesla_fleet_api/teslafleetapi.py,sha256=4Rnh_HNZkIw54o9SYAaHsA8vY0pmk_bMncrLuJ8MtSk,7389
|
10
|
-
tesla_fleet_api/teslafleetoauth.py,sha256=ClrVh4_lpatW8w44fWM0PZiVB-ciPHr-9h4yw1Zf9w8,4121
|
11
|
-
tesla_fleet_api/teslafleetopensource.py,sha256=TJfVPcqJlA1b3kMoGuLr-g5Gn8UDyYsTZhjvGY1MtIk,2007
|
12
|
-
tesla_fleet_api/teslemetry.py,sha256=IiDxEjDfWdXlpI7qFGW2YwroWoLbUdWSSVM6zCnhQl8,3307
|
13
|
-
tesla_fleet_api/tessie.py,sha256=4dBYxe1G2v9JvJGRbb01wXrAmvWT4jOfV4f_VQE_vkE,2302
|
14
|
-
tesla_fleet_api/user.py,sha256=TZE2oh-n5zrhKXmGRuiNL9voKVODD7rBhGE_IObYVGA,1179
|
15
|
-
tesla_fleet_api/vehicle.py,sha256=e0AotkaI-WftNfxJbLF8peIq3l99f6-ezVSEQbkOD1I,32090
|
16
|
-
tesla_fleet_api/vehiclesigned.py,sha256=PXXBeMpQf_5-ZQccjhtf6wllgCMhOOmtSjZzmjHYgls,39886
|
17
|
-
tesla_fleet_api/vehiclespecific.py,sha256=P7KI8MqUbAyM2cfDC8NqbJXzGL2ZsOIx3IBeqB8xYQY,20656
|
18
|
-
tesla_fleet_api/pb2/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
19
|
-
tesla_fleet_api/pb2/__init__.pyi,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
|
-
tesla_fleet_api/pb2/car_server_pb2.py,sha256=I3bq-cbq_4GXZblJatOFtjUny9seZb_1caNWMUciry0,51750
|
21
|
-
tesla_fleet_api/pb2/common_pb2.py,sha256=Iip_uomlO1s6wTyQl2QYxkUdVKB1qqSrpD3MHr-5rl0,6041
|
22
|
-
tesla_fleet_api/pb2/errors_pb2.py,sha256=ESk8GRN-jbsVvPWsWC0WfntmOXfRWVjy3sPT99WL89Q,2149
|
23
|
-
tesla_fleet_api/pb2/keys_pb2.py,sha256=T5q0OMlMiwFJV5xSmn6E2tnLCzr463Rk3pweaLFiPgM,1366
|
24
|
-
tesla_fleet_api/pb2/managed_charging_pb2.py,sha256=g6dJu9sYe9D2BCAWNFUNM_Qr0gJM5AHxmAJikHstQMc,1792
|
25
|
-
tesla_fleet_api/pb2/signatures_pb2.py,sha256=UZCXDYgV-tYIrzVHeqi0NaytUtRZJB-_lC7IVjIbggc,7719
|
26
|
-
tesla_fleet_api/pb2/universal_message_pb2.py,sha256=XF08dOMbhN0F9D4xbaNJhUIAEqbKdK1iYQdZFAloWdk,7826
|
27
|
-
tesla_fleet_api/pb2/vcsec_pb2.py,sha256=CMJ97e4Mm4p7NFcgybbCC2KJRcvtrcqmBy_pGycYhMo,26238
|
28
|
-
tesla_fleet_api/pb2/vehicle_pb2.py,sha256=ViSm74kS3iLjB2C18w-FDZyCkvi2e71GNKVmH2FU8zg,57629
|
29
|
-
tesla_fleet_api-0.9.5.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
30
|
-
tesla_fleet_api-0.9.5.dist-info/METADATA,sha256=f08KYxa2kQw_SuEZ0lAir5VORsuA95XYMVMmRl-80hE,3818
|
31
|
-
tesla_fleet_api-0.9.5.dist-info/WHEEL,sha256=A3WOREP4zgxI0fKrHUG8DC8013e3dK3n7a6HDbcEIwE,91
|
32
|
-
tesla_fleet_api-0.9.5.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
|
33
|
-
tesla_fleet_api-0.9.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|