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 +1 -1
- tesla_fleet_api/exceptions.py +0 -3
- tesla_fleet_api/tesla/bluetooth.py +5 -20
- tesla_fleet_api/tesla/fleet.py +5 -10
- tesla_fleet_api/tesla/tesla.py +12 -0
- tesla_fleet_api/tesla/vehicle/bluetooth.py +13 -14
- tesla_fleet_api/tesla/vehicle/vehicles.py +23 -1
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.8.dist-info}/METADATA +1 -1
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.8.dist-info}/RECORD +12 -12
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.8.dist-info}/LICENSE +0 -0
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.8.dist-info}/WHEEL +0 -0
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.8.dist-info}/top_level.txt +0 -0
tesla_fleet_api/const.py
CHANGED
tesla_fleet_api/exceptions.py
CHANGED
@@ -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.
|
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
|
-
|
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."""
|
tesla_fleet_api/tesla/fleet.py
CHANGED
@@ -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."""
|
tesla_fleet_api/tesla/tesla.py
CHANGED
@@ -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:
|
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.
|
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
|
-
|
103
|
-
|
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,
|
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.
|
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(
|
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,23 +1,23 @@
|
|
1
1
|
tesla_fleet_api/__init__.py,sha256=3DZMoZ-5srW-7SooAjqcRubQDuZPY8rMKH7eqIp4qtg,392
|
2
|
-
tesla_fleet_api/const.py,sha256=
|
3
|
-
tesla_fleet_api/exceptions.py,sha256=
|
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=
|
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=
|
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=
|
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=
|
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=
|
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.
|
48
|
-
tesla_fleet_api-1.0.
|
49
|
-
tesla_fleet_api-1.0.
|
50
|
-
tesla_fleet_api-1.0.
|
51
|
-
tesla_fleet_api-1.0.
|
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,,
|
File without changes
|
File without changes
|
File without changes
|