tesla-fleet-api 1.0.8__py3-none-any.whl → 1.0.10__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.8"
6
+ VERSION = "1.0.10"
7
7
  LOGGER = logging.getLogger(__package__)
8
8
  SERVERS = {
9
9
  "na": "https://fleet-api.prd.na.vn.cloud.tesla.com",
@@ -65,6 +65,8 @@ SERVICE_UUID = "00000211-b2d1-43f0-9b88-960cebf8b91e"
65
65
  WRITE_UUID = "00000212-b2d1-43f0-9b88-960cebf8b91e"
66
66
  READ_UUID = "00000213-b2d1-43f0-9b88-960cebf8b91e"
67
67
  VERSION_UUID = "00000214-b2d1-43f0-9b88-960cebf8b91e"
68
+ NAME_UUID = "00002a00-0000-1000-8000-00805f9b34fb"
69
+ APPEARANCE_UUID = "00002a01-0000-1000-8000-00805f9b34fb"
68
70
 
69
71
  if TYPE_CHECKING:
70
72
  from tesla_fleet_api.tesla.tesla import Tesla
@@ -97,9 +99,12 @@ class VehicleBluetooth(Commands):
97
99
  if device is not None:
98
100
  self.device = device
99
101
 
100
- async def find_vehicle(self, name: str | None = None, address: str | None = None, scanner: BleakScanner = BleakScanner()) -> BLEDevice:
102
+ async def find_vehicle(self, name: str | None = None, address: str | None = None, scanner: BleakScanner | None = None) -> BLEDevice:
101
103
  """Find the Tesla BLE device."""
102
104
 
105
+ if scanner is None:
106
+ scanner = BleakScanner(service_uuids=[SERVICE_UUID])
107
+
103
108
  if address is not None:
104
109
  device = await scanner.find_device_by_address(address)
105
110
  elif name is not None:
@@ -126,7 +131,8 @@ class VehicleBluetooth(Commands):
126
131
  self.device,
127
132
  self.vin,
128
133
  max_attempts=max_attempts,
129
- ble_device_callback=self.get_device
134
+ #ble_device_callback=self.get_device,
135
+ services=[SERVICE_UUID]
130
136
  )
131
137
  await self.client.start_notify(READ_UUID, self._on_notify)
132
138
 
@@ -212,6 +218,40 @@ class VehicleBluetooth(Commands):
212
218
  if resp.HasField(requires):
213
219
  return resp
214
220
 
221
+ async def query_display_name(self, max_attempts=5) -> str | None:
222
+ """Read the device name via GATT characteristic if available"""
223
+ for i in range(max_attempts):
224
+ try:
225
+ # Standard GATT Device Name characteristic (0x2A00)
226
+ device_name = (await self.client.read_gatt_char(NAME_UUID)).decode('utf-8')
227
+ if device_name.startswith("🔑 "):
228
+ return device_name.replace("🔑 ","")
229
+ await asyncio.sleep(1)
230
+ LOGGER.debug(f"Attempt {i+1} to query display name failed, {device_name}")
231
+ except Exception as e:
232
+ LOGGER.error(f"Failed to read device name: {e}")
233
+
234
+ async def query_appearance(self) -> bytearray | None:
235
+ """Read the device appearance via GATT characteristic if available"""
236
+ try:
237
+ # Standard GATT Appearance characteristic (0x2A01)
238
+ return await self.client.read_gatt_char(APPEARANCE_UUID)
239
+ except Exception as e:
240
+ LOGGER.error(f"Failed to read device appearance: {e}")
241
+ return None
242
+
243
+ async def query_version(self) -> int | None:
244
+ """Read the device version via GATT characteristic if available"""
245
+ try:
246
+ # Custom GATT Version characteristic (0x2A02)
247
+ device_version = await self.client.read_gatt_char(VERSION_UUID)
248
+ # Convert the bytes to an integer
249
+ if device_version and len(device_version) > 0:
250
+ return int.from_bytes(device_version, byteorder='big')
251
+ except Exception as e:
252
+ LOGGER.error(f"Failed to read device version: {e}")
253
+ return None
254
+
215
255
  async def pair(self, role: Role = Role.ROLE_OWNER, form: KeyFormFactor = KeyFormFactor.KEY_FORM_FACTOR_CLOUD_KEY, timeout: int = 60):
216
256
  """Pair the key."""
217
257
 
@@ -183,7 +183,7 @@ class Session:
183
183
  self.counter = sessionInfo.counter
184
184
  self.epoch = sessionInfo.epoch
185
185
  self.delta = int(time.time()) - sessionInfo.clock_time
186
- if (not self.ready or self.publicKey != sessionInfo.publicKey):
186
+ if (not self.ready or getattr(self, "publicKey", "None") != sessionInfo.publicKey):
187
187
  self.publicKey = sessionInfo.publicKey
188
188
  self.sharedKey = self.parent.shared_key(sessionInfo.publicKey)
189
189
  self.hmac = hmac.new(self.sharedKey, "authenticated command".encode(), hashlib.sha256).digest()
@@ -18,9 +18,11 @@ class Vehicle:
18
18
  """Base class describing a Tesla vehicle."""
19
19
 
20
20
  vin: str
21
+ parent: Tesla
21
22
 
22
23
  def __init__(self, parent: Tesla, vin: str):
23
24
  self.vin = vin
25
+ self.parent = parent
24
26
 
25
27
  @property
26
28
  def pre2021(self) -> bool:
@@ -1,12 +1,16 @@
1
1
  from __future__ import annotations
2
+ import asyncio
2
3
  from typing import TYPE_CHECKING
4
+ from bleak import BleakClient
3
5
  from bleak.backends.device import BLEDevice
6
+ from bleak_retry_connector import establish_connection
4
7
  from cryptography.hazmat.primitives.asymmetric import ec
5
8
 
6
9
  from tesla_fleet_api.tesla.vehicle.signed import VehicleSigned
7
- from tesla_fleet_api.tesla.vehicle.bluetooth import VehicleBluetooth
10
+ from tesla_fleet_api.tesla.vehicle.bluetooth import NAME_UUID, VehicleBluetooth
8
11
  from tesla_fleet_api.tesla.vehicle.fleet import VehicleFleet
9
12
  from tesla_fleet_api.tesla.vehicle.vehicle import Vehicle
13
+ from tesla_fleet_api.const import LOGGER
10
14
 
11
15
  if TYPE_CHECKING:
12
16
  from tesla_fleet_api.tesla.fleet import TeslaFleetApi
@@ -69,3 +73,27 @@ class VehiclesBluetooth(dict[str, Vehicle]):
69
73
  vehicle = self.Bluetooth(self._parent, vin, key, device)
70
74
  self[vin] = vehicle
71
75
  return vehicle
76
+
77
+ async def query_display_name(self, device: BLEDevice, max_attempts=5) -> str | None:
78
+ """Queries the name of a bluetooth vehicle."""
79
+ client = await establish_connection(
80
+ BleakClient,
81
+ device,
82
+ device.name or "Unknown",
83
+ max_attempts=max_attempts
84
+ )
85
+ name: str | None = None
86
+ for i in range(max_attempts):
87
+ try:
88
+ # Standard GATT Device Name characteristic (0x2A00)
89
+ device_name = (await client.read_gatt_char(NAME_UUID)).decode('utf-8')
90
+ if device_name.startswith("🔑 "):
91
+ name = device_name.replace("🔑 ","")
92
+ break
93
+ await asyncio.sleep(1)
94
+ LOGGER.debug(f"Attempt {i+1} to query display name failed, {device_name}")
95
+ except Exception as e:
96
+ LOGGER.error(f"Failed to read device name: {e}")
97
+
98
+ await client.disconnect()
99
+ return name
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: tesla_fleet_api
3
- Version: 1.0.8
3
+ Version: 1.0.10
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,5 +1,5 @@
1
1
  tesla_fleet_api/__init__.py,sha256=3DZMoZ-5srW-7SooAjqcRubQDuZPY8rMKH7eqIp4qtg,392
2
- tesla_fleet_api/const.py,sha256=677X3D-SV_9h-QyD0UM9cz8XHt5PY5TnHmkQzT1458Q,3748
2
+ tesla_fleet_api/const.py,sha256=iX1zonX_WX3NYpR_I9RAoVx3eM2iLHQjSD8C3QcBdTk,3749
3
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
@@ -12,12 +12,12 @@ tesla_fleet_api/tesla/partner.py,sha256=e-l6sEP6-IupjFEQieSUjhhvRXF3aL4ebPNahcGF
12
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=N4OHy1z_oAk8gOcub6AZ53Cpdi4PDur-5RAkWqi2hh0,16431
16
- tesla_fleet_api/tesla/vehicle/commands.py,sha256=zgfc2yo1UxEh8ePqSb-4h0UTK0RmpCG_9LZX44CES2c,51268
15
+ tesla_fleet_api/tesla/vehicle/bluetooth.py,sha256=CJgyE99Q4ezWjDjEaRD5hA6_-bHPpztXXdQcKQh9GZ0,18334
16
+ tesla_fleet_api/tesla/vehicle/commands.py,sha256=_LXAtuAIkeojJuw8k1QjEabAQQH2MLD5YZyUH58QoSg,51288
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
- tesla_fleet_api/tesla/vehicle/vehicle.py,sha256=BlmHjV5Hly8v0vWNVBUhdNvwsSSuCuF946D7zROUB3s,823
20
- tesla_fleet_api/tesla/vehicle/vehicles.py,sha256=c1KFTAYDvuTVNjM5O23KvT54UbNwo3ofFVpfkY-Mq5Y,2640
19
+ tesla_fleet_api/tesla/vehicle/vehicle.py,sha256=IBvRO6qGkUf4bi-pFongA9fIe9iScvz_wGXtzEJXilY,870
20
+ tesla_fleet_api/tesla/vehicle/vehicles.py,sha256=jLE_T_fWEwFjuYU5_AlJ0KhEvWAPx2wybENESksJ2R8,3777
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.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,,
47
+ tesla_fleet_api-1.0.10.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
48
+ tesla_fleet_api-1.0.10.dist-info/METADATA,sha256=Dr_QRBUiyoZ4PUgBBipQkoTBbqxW7qtE-vJ9GxzY8io,4383
49
+ tesla_fleet_api-1.0.10.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
50
+ tesla_fleet_api-1.0.10.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
51
+ tesla_fleet_api-1.0.10.dist-info/RECORD,,