tesla-fleet-api 1.0.7__py3-none-any.whl → 1.0.8__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 CHANGED
@@ -3,7 +3,7 @@
3
3
  from enum import Enum
4
4
  import logging
5
5
 
6
- VERSION = "1.0.7"
6
+ VERSION = "1.0.8"
7
7
  LOGGER = logging.getLogger(__package__)
8
8
  SERVERS = {
9
9
  "na": "https://fleet-api.prd.na.vn.cloud.tesla.com",
@@ -875,9 +875,6 @@ SIGNED_MESSAGE_INFORMATION_FAULTS = [
875
875
  class WhitelistOperationStatus(TeslaFleetError):
876
876
  message = "Whitelist operation failed"
877
877
 
878
- def __init__(self, message):
879
- self.message = message
880
-
881
878
  class WhitelistOperationUndocumentedError(WhitelistOperationStatus):
882
879
  message = "Undocumented whitelist operation error"
883
880
  code = 1
@@ -3,21 +3,21 @@
3
3
  import hashlib
4
4
  import re
5
5
  from google.protobuf.json_format import MessageToJson, MessageToDict
6
- from bleak.backends.device import BLEDevice
7
- from cryptography.hazmat.primitives.asymmetric import ec
8
6
 
9
7
  from tesla_fleet_api.tesla.tesla import Tesla
10
- from tesla_fleet_api.tesla.vehicle.bluetooth import VehicleBluetooth
8
+ from tesla_fleet_api.tesla.vehicle.vehicles import VehiclesBluetooth
11
9
 
12
10
  class TeslaBluetooth(Tesla):
13
11
  """Class describing a Tesla Bluetooth connection."""
14
12
 
13
+ Vehicles = VehiclesBluetooth
14
+
15
15
  def __init__(
16
16
  self,
17
17
  ):
18
18
  """Initialize the Tesla Fleet API."""
19
19
 
20
- self.vehicles = Vehicles(self)
20
+ self.vehicles = self.Vehicles(self)
21
21
 
22
22
  def valid_name(self, name: str) -> bool:
23
23
  """Check if a BLE device name is a valid Tesla vehicle."""
@@ -27,23 +27,8 @@ class TeslaBluetooth(Tesla):
27
27
  """Get the name of a vehicle."""
28
28
  return "S" + hashlib.sha1(vin.encode('utf-8')).hexdigest()[:16] + "C"
29
29
 
30
- class Vehicles(dict[str, VehicleBluetooth]):
31
- """Class containing and creating vehicles."""
32
-
33
- _parent: TeslaBluetooth
34
-
35
- def __init__(self, parent: TeslaBluetooth):
36
- self._parent = parent
37
-
38
- def create(self, vin: str) -> VehicleBluetooth:
39
- """Creates a specific vehicle."""
40
- return self.createBluetooth(vin)
41
30
 
42
- def createBluetooth(self, vin: str, key: ec.EllipticCurvePrivateKey | None = None, device: None | str | BLEDevice = None) -> VehicleBluetooth:
43
- """Creates a specific vehicle."""
44
- vehicle = VehicleBluetooth(self._parent, vin, key, device)
45
- self[vin] = vehicle
46
- return vehicle
31
+ # Helpers
47
32
 
48
33
  def toJson(message) -> str:
49
34
  """Convert a protobuf message to JSON."""
@@ -7,11 +7,6 @@ import aiohttp
7
7
  from tesla_fleet_api.tesla.tesla import Tesla
8
8
  from tesla_fleet_api.exceptions import raise_for_status, InvalidRegion, LibraryError, ResponseError
9
9
  from tesla_fleet_api.const import SERVERS, Method, LOGGER, VERSION
10
- from tesla_fleet_api.tesla.charging import Charging
11
- from tesla_fleet_api.tesla.energysite import EnergySites
12
- from tesla_fleet_api.tesla.partner import Partner
13
- from tesla_fleet_api.tesla.user import User
14
- from tesla_fleet_api.tesla.vehicle.vehicles import Vehicles
15
10
 
16
11
 
17
12
  # Based on https://developer.tesla.com/docs/fleet-api
@@ -54,15 +49,15 @@ class TeslaFleetApi(Tesla):
54
49
  LOGGER.debug("Using server %s", self.server)
55
50
 
56
51
  if charging_scope:
57
- self.charging = Charging(self)
52
+ self.charging = self.Charging(self)
58
53
  if energy_scope:
59
- self.energySites = EnergySites(self)
54
+ self.energySites = self.EnergySites(self)
60
55
  if user_scope:
61
- self.user = User(self)
56
+ self.user = self.User(self)
62
57
  if partner_scope:
63
- self.partner = Partner(self)
58
+ self.partner = self.Partner(self)
64
59
  if vehicle_scope:
65
- self.vehicles = Vehicles(self)
60
+ self.vehicles = self.Vehicles(self)
66
61
 
67
62
  async def find_server(self) -> str:
68
63
  """Find the server URL for the Tesla Fleet API."""
@@ -3,6 +3,12 @@
3
3
  from os.path import exists
4
4
  import aiofiles
5
5
 
6
+ from tesla_fleet_api.tesla.charging import Charging
7
+ from tesla_fleet_api.tesla.energysite import EnergySites
8
+ from tesla_fleet_api.tesla.partner import Partner
9
+ from tesla_fleet_api.tesla.user import User
10
+ from tesla_fleet_api.tesla.vehicle.vehicles import Vehicles
11
+
6
12
  # cryptography
7
13
  from cryptography.hazmat.primitives.asymmetric import ec
8
14
  from cryptography.hazmat.primitives import serialization
@@ -11,6 +17,12 @@ from cryptography.hazmat.backends import default_backend
11
17
  class Tesla:
12
18
  """Base class describing interactions with Tesla products."""
13
19
 
20
+ Charging = Charging
21
+ EnergySites = EnergySites
22
+ Partner = Partner
23
+ User = User
24
+ Vehicles = Vehicles
25
+
14
26
  private_key: ec.EllipticCurvePrivateKey | None = None
15
27
 
16
28
  async def get_private_key(
@@ -86,7 +86,7 @@ class VehicleBluetooth(Commands):
86
86
  _auth_method = "aes"
87
87
 
88
88
  def __init__(
89
- self, parent: Tesla, vin: str, key: ec.EllipticCurvePrivateKey | None = None, device: None | str | BLEDevice = None
89
+ self, parent: Tesla, vin: str, key: ec.EllipticCurvePrivateKey | None = None, device: BLEDevice | None = None
90
90
  ):
91
91
  super().__init__(parent, vin, key)
92
92
  self.ble_name = "S" + hashlib.sha1(vin.encode('utf-8')).hexdigest()[:16] + "C"
@@ -95,14 +95,15 @@ class VehicleBluetooth(Commands):
95
95
  Domain.DOMAIN_INFOTAINMENT: asyncio.Queue(),
96
96
  }
97
97
  if device is not None:
98
- self.client = BleakClient(device, services=[SERVICE_UUID])
98
+ self.device = device
99
99
 
100
100
  async def find_vehicle(self, name: str | None = None, address: str | None = None, scanner: BleakScanner = BleakScanner()) -> BLEDevice:
101
101
  """Find the Tesla BLE device."""
102
- if name is not None:
103
- device = await scanner.find_device_by_name(name)
104
- elif address is not None:
102
+
103
+ if address is not None:
105
104
  device = await scanner.find_device_by_address(address)
105
+ elif name is not None:
106
+ device = await scanner.find_device_by_name(name)
106
107
  else:
107
108
  device = await scanner.find_device_by_name(self.ble_name)
108
109
  if not device:
@@ -116,12 +117,10 @@ class VehicleBluetooth(Commands):
116
117
  def get_device(self) -> BLEDevice:
117
118
  return self.device
118
119
 
119
- async def connect(self, device: BLEDevice | None = None, max_attempts: int = MAX_CONNECT_ATTEMPTS) -> None:
120
+ async def connect(self, max_attempts: int = MAX_CONNECT_ATTEMPTS) -> None:
120
121
  """Connect to the Tesla BLE device."""
121
- if device:
122
- self.device = device
123
- if not self.device:
124
- raise ValueError(f"Device {self.ble_name} not found")
122
+ if not hasattr(self, 'device'):
123
+ raise ValueError(f"BLEDevice {self.ble_name} has not been found or set")
125
124
  self.client = await establish_connection(
126
125
  BleakClient,
127
126
  self.device,
@@ -189,7 +188,7 @@ class VehicleBluetooth(Commands):
189
188
  LOGGER.debug(f"Received response: {msg}")
190
189
  await self._queues[msg.from_destination.domain].put(msg)
191
190
 
192
- async def _send(self, msg: RoutableMessage, requires: str) -> RoutableMessage:
191
+ async def _send(self, msg: RoutableMessage, requires: str, timeout: int = 2) -> RoutableMessage:
193
192
  """Serialize a message and send to the vehicle and wait for a response."""
194
193
  domain = msg.to_destination.domain
195
194
  async with self._sessions[domain].lock:
@@ -203,7 +202,7 @@ class VehicleBluetooth(Commands):
203
202
  await self.client.write_gatt_char(WRITE_UUID, payload, True)
204
203
 
205
204
  # Process the response
206
- async with asyncio.timeout(2):
205
+ async with asyncio.timeout(timeout):
207
206
  while True:
208
207
  resp = await self._queues[domain].get()
209
208
  LOGGER.debug(f"Received message {resp}")
@@ -213,7 +212,7 @@ class VehicleBluetooth(Commands):
213
212
  if resp.HasField(requires):
214
213
  return resp
215
214
 
216
- async def pair(self, role: Role = Role.ROLE_OWNER, form: KeyFormFactor = KeyFormFactor.KEY_FORM_FACTOR_CLOUD_KEY):
215
+ async def pair(self, role: Role = Role.ROLE_OWNER, form: KeyFormFactor = KeyFormFactor.KEY_FORM_FACTOR_CLOUD_KEY, timeout: int = 60):
217
216
  """Pair the key."""
218
217
 
219
218
  request = UnsignedMessage(
@@ -236,7 +235,7 @@ class VehicleBluetooth(Commands):
236
235
  ),
237
236
  protobuf_message_as_bytes=request.SerializeToString(),
238
237
  )
239
- resp = await self._send(msg, "protobuf_message_as_bytes")
238
+ resp = await self._send(msg, "protobuf_message_as_bytes", timeout)
240
239
  respMsg = FromVCSECMessage.FromString(resp.protobuf_message_as_bytes)
241
240
  if(respMsg.commandStatus.whitelistOperationStatus.whitelistOperationInformation):
242
241
  if(respMsg.commandStatus.whitelistOperationStatus.whitelistOperationInformation < len(WHITELIST_OPERATION_STATUS)):
@@ -1,5 +1,7 @@
1
1
  from __future__ import annotations
2
2
  from typing import TYPE_CHECKING
3
+ from bleak.backends.device import BLEDevice
4
+ from cryptography.hazmat.primitives.asymmetric import ec
3
5
 
4
6
  from tesla_fleet_api.tesla.vehicle.signed import VehicleSigned
5
7
  from tesla_fleet_api.tesla.vehicle.bluetooth import VehicleBluetooth
@@ -8,7 +10,7 @@ from tesla_fleet_api.tesla.vehicle.vehicle import Vehicle
8
10
 
9
11
  if TYPE_CHECKING:
10
12
  from tesla_fleet_api.tesla.fleet import TeslaFleetApi
11
-
13
+ from tesla_fleet_api.tesla.bluetooth import TeslaBluetooth
12
14
 
13
15
 
14
16
  class Vehicles(dict[str, Vehicle]):
@@ -47,3 +49,23 @@ class Vehicles(dict[str, Vehicle]):
47
49
  def specificSigned(self, vin: str) -> VehicleSigned:
48
50
  """Legacy method for creating a Fleet API vehicle that uses command protocol."""
49
51
  return self.createSigned(vin)
52
+
53
+
54
+ class VehiclesBluetooth(dict[str, Vehicle]):
55
+ """Class containing and creating bluetooth vehicles."""
56
+
57
+ _parent: TeslaBluetooth
58
+ Bluetooth = VehicleBluetooth
59
+
60
+ def __init__(self, parent: TeslaBluetooth):
61
+ self._parent = parent
62
+
63
+ def create(self, vin: str, key: ec.EllipticCurvePrivateKey | None = None, device: BLEDevice | None = None) -> VehicleBluetooth:
64
+ """Creates a bluetooth vehicle that uses command protocol."""
65
+ return self.createBluetooth(vin, key, device)
66
+
67
+ def createBluetooth(self, vin: str, key: ec.EllipticCurvePrivateKey | None = None, device: BLEDevice | None = None) -> VehicleBluetooth:
68
+ """Creates a bluetooth vehicle that uses command protocol."""
69
+ vehicle = self.Bluetooth(self._parent, vin, key, device)
70
+ self[vin] = vehicle
71
+ return vehicle
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tesla_fleet_api
3
- Version: 1.0.7
3
+ Version: 1.0.8
4
4
  Summary: Tesla Fleet API library for Python
5
5
  Home-page: https://github.com/Teslemetry/python-tesla-fleet-api
6
6
  Author: Brett Adams
@@ -1,23 +1,23 @@
1
1
  tesla_fleet_api/__init__.py,sha256=3DZMoZ-5srW-7SooAjqcRubQDuZPY8rMKH7eqIp4qtg,392
2
- tesla_fleet_api/const.py,sha256=SBoj3pXbqLxQ0upG6_D3oV-um6M6OGSLXoN6eLQqajs,3748
3
- tesla_fleet_api/exceptions.py,sha256=iZJv_6YJO6wK_lYvR18SugpNk-ZTzElmcsOqNqd05M0,35495
2
+ tesla_fleet_api/const.py,sha256=677X3D-SV_9h-QyD0UM9cz8XHt5PY5TnHmkQzT1458Q,3748
3
+ tesla_fleet_api/exceptions.py,sha256=GvjJBR77xGt2g3vhiAxcNtysj-e1Me7F-9PwO9dyzOo,35430
4
4
  tesla_fleet_api/ratecalculator.py,sha256=4lz8yruUeouHXh_3ezsXX-CTpIegp1T1J4VuRV_qdHA,1791
5
5
  tesla_fleet_api/tesla/__init__.py,sha256=Cvpqu8OaOFmbuwu9KjgYrje8eVluDp2IU_zwdtXbmO0,282
6
- tesla_fleet_api/tesla/bluetooth.py,sha256=WhDo66OEwCGhvsGskvWcGUiNv6eyFsdEiQdIm571jQM,1835
6
+ tesla_fleet_api/tesla/bluetooth.py,sha256=vxDPTM-Uq9IAVJjK54-p_llj26hssEEXAQI5-lVGx8Q,1137
7
7
  tesla_fleet_api/tesla/charging.py,sha256=D7I7cAf-3-95sIjyP6wpVqCq9Cppj6U-VPFQGpQQ8bs,1704
8
8
  tesla_fleet_api/tesla/energysite.py,sha256=vStffklBQfQNAO_1wrHLFu7BlBCTVVbLh7_IrAUL3wg,6131
9
- tesla_fleet_api/tesla/fleet.py,sha256=X74tzwGO9w65j9YUGuW04CwG7Bx6biEHwxIjWGCzB4c,5670
9
+ tesla_fleet_api/tesla/fleet.py,sha256=zfmagXF4TbbVOPWcngCSKebaGB1daXbw8mTJ9o8einY,5432
10
10
  tesla_fleet_api/tesla/oauth.py,sha256=aWBsWmnM-QxzaU8W9TXVNxGsYn_LraXnpexwdE8wOqo,4104
11
11
  tesla_fleet_api/tesla/partner.py,sha256=e-l6sEP6-IupjFEQieSUjhhvRXF3aL4ebPNahcGFRCE,1238
12
- tesla_fleet_api/tesla/tesla.py,sha256=Jlz90-fM0nJbhnQN0k3ukNv59-9KqZZbyQ91IiLIbfo,2010
12
+ tesla_fleet_api/tesla/tesla.py,sha256=Gs8-L3OsEMhs1N_vdDx-E46bOHKGowXTBxmRiP8NKh4,2391
13
13
  tesla_fleet_api/tesla/user.py,sha256=w8rwiAOIFjuDus8M0RpZ0wucJtw8kYFKtJfYVk7Ekr0,1194
14
14
  tesla_fleet_api/tesla/vehicle/__init__.py,sha256=3A5_wTQHofRShof4pUNOtF78-7lUh62uz2jq2ecnmRY,381
15
- tesla_fleet_api/tesla/vehicle/bluetooth.py,sha256=25UlaAatKxu_NzbG5te5sKHeM9jAufj42LjGJaIKNHg,16476
15
+ tesla_fleet_api/tesla/vehicle/bluetooth.py,sha256=N4OHy1z_oAk8gOcub6AZ53Cpdi4PDur-5RAkWqi2hh0,16431
16
16
  tesla_fleet_api/tesla/vehicle/commands.py,sha256=zgfc2yo1UxEh8ePqSb-4h0UTK0RmpCG_9LZX44CES2c,51268
17
17
  tesla_fleet_api/tesla/vehicle/fleet.py,sha256=K9BVZj6CChJSDSMFroa7Cz0KrsYWj32ILtQumarkLaU,32080
18
18
  tesla_fleet_api/tesla/vehicle/signed.py,sha256=RUzVnZIfykz3YZW2gaxd1iaN1i8LkLaEoiXrbqZn9kg,1339
19
19
  tesla_fleet_api/tesla/vehicle/vehicle.py,sha256=BlmHjV5Hly8v0vWNVBUhdNvwsSSuCuF946D7zROUB3s,823
20
- tesla_fleet_api/tesla/vehicle/vehicles.py,sha256=axiH33YRnkYcbQmolbL85PF69SRI_5FA5T10v-cMmBc,1644
20
+ tesla_fleet_api/tesla/vehicle/vehicles.py,sha256=c1KFTAYDvuTVNjM5O23KvT54UbNwo3ofFVpfkY-Mq5Y,2640
21
21
  tesla_fleet_api/tesla/vehicle/proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  tesla_fleet_api/tesla/vehicle/proto/__init__.pyi,sha256=qFXWNIgl71wB260u-XPzaAwWAHL6krw21q-aXnBtop0,252
23
23
  tesla_fleet_api/tesla/vehicle/proto/car_server_pb2.py,sha256=v_eb4NDIkx_ZYPYW29_EFRky5vQ4b2q14gwuQSbouYw,29202
@@ -44,8 +44,8 @@ tesla_fleet_api/teslemetry/vehicles.py,sha256=9nybVg7VHKLa2woMG6fzMmQP6xJIE_jdAd
44
44
  tesla_fleet_api/tessie/__init__.py,sha256=9lhQJaB6X4PObUL9QdaaZYqs2BxiTidu3zmHcBESLVw,78
45
45
  tesla_fleet_api/tessie/tessie.py,sha256=uhg0oOIxpwDvlvdBhKHeF3AGR2PzmdBgzh2-_EkmSq0,2617
46
46
  tesla_fleet_api/tessie/vehicles.py,sha256=gfEatilI_ct-R4CM5xYhrlduqCR9IHlyc56WmJf7v7k,1149
47
- tesla_fleet_api-1.0.7.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
48
- tesla_fleet_api-1.0.7.dist-info/METADATA,sha256=8V2QJ6JsJYg745xq--pFzS1n8tm30avdLd-bEfmatkk,4382
49
- tesla_fleet_api-1.0.7.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
50
- tesla_fleet_api-1.0.7.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
51
- tesla_fleet_api-1.0.7.dist-info/RECORD,,
47
+ tesla_fleet_api-1.0.8.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
48
+ tesla_fleet_api-1.0.8.dist-info/METADATA,sha256=_Lo_vqVRgsfYm5-2kKVO0lT4BOplNA7fam0SQ6cjxwk,4382
49
+ tesla_fleet_api-1.0.8.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
50
+ tesla_fleet_api-1.0.8.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
51
+ tesla_fleet_api-1.0.8.dist-info/RECORD,,