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.
Files changed (32) hide show
  1. tesla_fleet_api/const.py +1 -1
  2. tesla_fleet_api/exceptions.py +239 -46
  3. tesla_fleet_api/pb2/__init__.pyi +9 -0
  4. tesla_fleet_api/pb2/car_server_pb2.py +164 -386
  5. tesla_fleet_api/pb2/car_server_pb2.pyi +904 -0
  6. tesla_fleet_api/pb2/common_pb2.py +26 -60
  7. tesla_fleet_api/pb2/common_pb2.pyi +130 -0
  8. tesla_fleet_api/pb2/errors_pb2.py +10 -22
  9. tesla_fleet_api/pb2/errors_pb2.pyi +32 -0
  10. tesla_fleet_api/pb2/keys_pb2.py +8 -16
  11. tesla_fleet_api/pb2/keys_pb2.pyi +21 -0
  12. tesla_fleet_api/pb2/managed_charging_pb2.py +8 -14
  13. tesla_fleet_api/pb2/managed_charging_pb2.pyi +17 -0
  14. tesla_fleet_api/pb2/signatures_pb2.py +28 -75
  15. tesla_fleet_api/pb2/signatures_pb2.pyi +152 -0
  16. tesla_fleet_api/pb2/universal_message_pb2.py +22 -78
  17. tesla_fleet_api/pb2/universal_message_pb2.pyi +148 -0
  18. tesla_fleet_api/pb2/vcsec_pb2.py +70 -236
  19. tesla_fleet_api/pb2/vcsec_pb2.pyi +482 -0
  20. tesla_fleet_api/pb2/vehicle_pb2.py +114 -267
  21. tesla_fleet_api/pb2/vehicle_pb2.pyi +1183 -0
  22. tesla_fleet_api/teslafleetapi.py +7 -5
  23. tesla_fleet_api/teslafleetoauth.py +1 -1
  24. tesla_fleet_api/teslemetry.py +2 -2
  25. tesla_fleet_api/vehicle.py +1 -1
  26. tesla_fleet_api/vehiclesigned.py +143 -102
  27. {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/METADATA +12 -3
  28. tesla_fleet_api-0.9.7.dist-info/RECORD +42 -0
  29. {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/WHEEL +1 -1
  30. tesla_fleet_api-0.9.5.dist-info/RECORD +0 -33
  31. {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/LICENSE +0 -0
  32. {tesla_fleet_api-0.9.5.dist-info → tesla_fleet_api-0.9.7.dist-info}/top_level.txt +0 -0
@@ -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&prompt=login&client_id={self.client_id}&redirect_uri={self.redirect_uri}&scope={'+'.join(scopes)}&state={state}"
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."""
@@ -96,11 +96,11 @@ class Teslemetry(TeslaFleetApi):
96
96
  )
97
97
  ).get("response")
98
98
 
99
- async def vehicle_force_refresh(self, vin: str) -> dict[str, Any]:
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/force/{vin}",
103
+ f"api/refresh/{vin}",
104
104
  )
105
105
 
106
106
  async def _request(
@@ -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[3] in ["S", "X"]
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
@@ -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 .exceptions import MESSAGE_FAULTS, TeslaFleetMessageFaultIncorrectEpoch
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
- def __init__(self, key: bytes, counter: int, epoch: bytes, delta: int):
126
- """Create a session instance for a single domain"""
127
- self.key = key
128
- self.counter = counter
129
- self.epoch = epoch
130
- self.delta = delta
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 += 1
138
- signature = HMAC_Personalized_Signature_Data()
139
- signature.epoch = self.epoch
140
- signature.counter = self.counter
141
- signature.expires_at = int(time.time()) - self.delta + 10
142
- return signature
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 _signed_message(self, msg: RoutableMessage) -> RoutableMessage:
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
- if resp.signedMessageStatus:
188
- LOGGER.error("Command returned with signedMessageStatus: %s", resp.signedMessageStatus)
189
- if resp.signedMessageStatus.operation_status == OPERATIONSTATUS_ERROR:
190
- raise MESSAGE_FAULTS[resp.signedMessageStatus.signed_message_fault]
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
- return resp
194
+ # Check UUID?
195
+ # Check RoutingAdress?
193
196
 
194
- async def _handshake(self, domain: int) -> None:
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
- resp = await self._signed_message(msg)
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
- # Derive shared key from private key _key and vehicle public key
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
- if DOMAIN_VEHICLE_SECURITY not in self._sessions:
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
- if DOMAIN_INFOTAINMENT not in self._sessions:
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 _send(self, domain: int, command: bytes, attempt: int = 1) -> dict[str, Any]:
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
- session = self._sessions[domain].get()
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(session.epoch),
260
- *session.epoch,
259
+ len(hmac_personalized.epoch),
260
+ *hmac_personalized.epoch,
261
261
  TAG_EXPIRES_AT,
262
262
  4,
263
- *struct.pack(">I", session.expires_at),
263
+ *struct.pack(">I", hmac_personalized.expires_at),
264
264
  TAG_COUNTER,
265
265
  4,
266
- *struct.pack(">I", session.counter),
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
- signature = SignatureData()
273
- signature.HMAC_Personalized_data.CopyFrom(session)
274
- signature.signer_identity.public_key = self._public_key
270
+ hmac_personalized.tag = hmac.new(
271
+ session.hmac, metadata + command, hashlib.sha256
272
+ ).digest()
275
273
 
276
- msg.signature_data.CopyFrom(signature)
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._signed_message(msg)
280
- except TeslaFleetMessageFaultIncorrectEpoch as e:
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
- LOGGER.info(f"Session expired, starting new handshake with {Domain.Name(domain)}")
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
- return {"response": {"result": False}}
292
-
293
- LOGGER.debug("Command response: %s", resp)
294
- reason = resp.protobuf_message_as_bytes[8:].decode()
295
-
296
- if reason:
297
- LOGGER.error("Command failed with reason: %s", reason)
298
- return {"response": {"result": False, "reason": reason}}
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=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 = LatLong()
1008
- location.latitude = lat
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
1
+ Metadata-Version: 2.2
2
2
  Name: tesla_fleet_api
3
- Version: 0.9.5
3
+ Version: 0.9.7
4
4
  Summary: Tesla Fleet API library for Python
5
- Home-page: https://github.com/Teslemetry/tesla_fleet_api
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,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.7.0)
2
+ Generator: setuptools (75.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -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,,