tesla-fleet-api 1.0.7__py3-none-any.whl → 1.0.9__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 +20 -16
- tesla_fleet_api/tesla/vehicle/commands.py +1 -1
- tesla_fleet_api/tesla/vehicle/vehicles.py +23 -1
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.9.dist-info}/METADATA +1 -1
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.9.dist-info}/RECORD +13 -13
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.9.dist-info}/LICENSE +0 -0
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.9.dist-info}/WHEEL +0 -0
- {tesla_fleet_api-1.0.7.dist-info → tesla_fleet_api-1.0.9.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,18 @@ 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
|
-
async def find_vehicle(self, name: str | None = None, address: str | None = None, scanner: BleakScanner =
|
100
|
+
async def find_vehicle(self, name: str | None = None, address: str | None = None, scanner: BleakScanner | None = None) -> BLEDevice:
|
101
101
|
"""Find the Tesla BLE device."""
|
102
|
-
|
103
|
-
|
104
|
-
|
102
|
+
|
103
|
+
if scanner is None:
|
104
|
+
scanner = BleakScanner(service_uuids=[SERVICE_UUID])
|
105
|
+
|
106
|
+
if address is not None:
|
105
107
|
device = await scanner.find_device_by_address(address)
|
108
|
+
elif name is not None:
|
109
|
+
device = await scanner.find_device_by_name(name)
|
106
110
|
else:
|
107
111
|
device = await scanner.find_device_by_name(self.ble_name)
|
108
112
|
if not device:
|
@@ -116,18 +120,17 @@ class VehicleBluetooth(Commands):
|
|
116
120
|
def get_device(self) -> BLEDevice:
|
117
121
|
return self.device
|
118
122
|
|
119
|
-
async def connect(self,
|
123
|
+
async def connect(self, max_attempts: int = MAX_CONNECT_ATTEMPTS) -> None:
|
120
124
|
"""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")
|
125
|
+
if not hasattr(self, 'device'):
|
126
|
+
raise ValueError(f"BLEDevice {self.ble_name} has not been found or set")
|
125
127
|
self.client = await establish_connection(
|
126
128
|
BleakClient,
|
127
129
|
self.device,
|
128
130
|
self.vin,
|
129
131
|
max_attempts=max_attempts,
|
130
|
-
ble_device_callback=self.get_device
|
132
|
+
#ble_device_callback=self.get_device,
|
133
|
+
services=[SERVICE_UUID]
|
131
134
|
)
|
132
135
|
await self.client.start_notify(READ_UUID, self._on_notify)
|
133
136
|
|
@@ -189,7 +192,7 @@ class VehicleBluetooth(Commands):
|
|
189
192
|
LOGGER.debug(f"Received response: {msg}")
|
190
193
|
await self._queues[msg.from_destination.domain].put(msg)
|
191
194
|
|
192
|
-
async def _send(self, msg: RoutableMessage, requires: str) -> RoutableMessage:
|
195
|
+
async def _send(self, msg: RoutableMessage, requires: str, timeout: int = 2) -> RoutableMessage:
|
193
196
|
"""Serialize a message and send to the vehicle and wait for a response."""
|
194
197
|
domain = msg.to_destination.domain
|
195
198
|
async with self._sessions[domain].lock:
|
@@ -203,7 +206,7 @@ class VehicleBluetooth(Commands):
|
|
203
206
|
await self.client.write_gatt_char(WRITE_UUID, payload, True)
|
204
207
|
|
205
208
|
# Process the response
|
206
|
-
async with asyncio.timeout(
|
209
|
+
async with asyncio.timeout(timeout):
|
207
210
|
while True:
|
208
211
|
resp = await self._queues[domain].get()
|
209
212
|
LOGGER.debug(f"Received message {resp}")
|
@@ -213,7 +216,8 @@ class VehicleBluetooth(Commands):
|
|
213
216
|
if resp.HasField(requires):
|
214
217
|
return resp
|
215
218
|
|
216
|
-
|
219
|
+
|
220
|
+
async def pair(self, role: Role = Role.ROLE_OWNER, form: KeyFormFactor = KeyFormFactor.KEY_FORM_FACTOR_CLOUD_KEY, timeout: int = 60):
|
217
221
|
"""Pair the key."""
|
218
222
|
|
219
223
|
request = UnsignedMessage(
|
@@ -236,7 +240,7 @@ class VehicleBluetooth(Commands):
|
|
236
240
|
),
|
237
241
|
protobuf_message_as_bytes=request.SerializeToString(),
|
238
242
|
)
|
239
|
-
resp = await self._send(msg, "protobuf_message_as_bytes")
|
243
|
+
resp = await self._send(msg, "protobuf_message_as_bytes", timeout)
|
240
244
|
respMsg = FromVCSECMessage.FromString(resp.protobuf_message_as_bytes)
|
241
245
|
if(respMsg.commandStatus.whitelistOperationStatus.whitelistOperationInformation):
|
242
246
|
if(respMsg.commandStatus.whitelistOperationStatus.whitelistOperationInformation < len(WHITELIST_OPERATION_STATUS)):
|
@@ -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
|
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()
|
@@ -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=6avk1nS7GL_OVZaiC1Cmy0a-QoZ3LNoXTUjxFNKiPWA,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=
|
16
|
-
tesla_fleet_api/tesla/vehicle/commands.py,sha256=
|
15
|
+
tesla_fleet_api/tesla/vehicle/bluetooth.py,sha256=SAzJL0GW8Gp5cCs_Gyc2qBJP9WVVwV_qwUFkQF8waTI,16561
|
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
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.9.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
48
|
+
tesla_fleet_api-1.0.9.dist-info/METADATA,sha256=bDVsevE52Rb5wKU46C2oUVlDHMmMp9zClJl2KQlRpjk,4382
|
49
|
+
tesla_fleet_api-1.0.9.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
50
|
+
tesla_fleet_api-1.0.9.dist-info/top_level.txt,sha256=jeNbog_1saXBFrGpom9WyPWmilxsyP3szL_G7JLWQfM,16
|
51
|
+
tesla_fleet_api-1.0.9.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|