11from __future__ import annotations
22
33import hashlib
4- import hmac
5- import struct
6- from asyncio import Future , sleep , get_running_loop
7- from random import randbytes
8- from typing import TYPE_CHECKING , Any , List
4+ from asyncio import Future , get_running_loop
5+ from typing import TYPE_CHECKING
96from google .protobuf .message import DecodeError
107
118from bleak import BleakClient , BleakScanner
2219)
2320from ...exceptions import (
2421 MESSAGE_FAULTS ,
25- SIGNED_MESSAGE_INFORMATION_FAULTS ,
2622 WHITELIST_OPERATION_STATUS ,
27- TeslaFleetMessageFaultIncorrectEpoch ,
28- TeslaFleetMessageFaultInvalidTokenOrCounter ,
2923)
3024
3125# Protocol
32- from .proto .errors_pb2 import GenericError_E
3326from .proto .car_server_pb2 import (
3427 Response ,
3528)
3629from .proto .signatures_pb2 import (
37- SIGNATURE_TYPE_HMAC_PERSONALIZED ,
38- TAG_COUNTER ,
39- TAG_DOMAIN ,
40- TAG_END ,
41- TAG_EPOCH ,
42- TAG_EXPIRES_AT ,
43- TAG_PERSONALIZATION ,
44- TAG_SIGNATURE_TYPE ,
4530 SessionInfo ,
4631)
4732from .proto .universal_message_pb2 import (
48- DOMAIN_INFOTAINMENT ,
49- DOMAIN_VEHICLE_SECURITY ,
50- OPERATIONSTATUS_ERROR ,
51- OPERATIONSTATUS_WAIT ,
5233 Destination ,
5334 Domain ,
5435 RoutableMessage ,
5536)
5637from .proto .vcsec_pb2 import (
57- OPERATIONSTATUS_OK ,
5838 FromVCSECMessage ,
5939 KeyFormFactor ,
6040 KeyMetadata ,
6141 PermissionChange ,
6242 PublicKey ,
63- SignatureType ,
64- SignedMessage ,
65- ToVCSECMessage ,
6643 UnsignedMessage ,
6744 WhitelistOperation ,
68- WhitelistOperation_information_E ,
6945
7046)
7147
@@ -84,9 +60,9 @@ def prependLength(message: bytes) -> bytearray:
8460class VehicleBluetooth (Commands ):
8561 """Class describing the Tesla Fleet API vehicle endpoints and commands for a specific vehicle with command signing."""
8662
87- _ble_name : str
63+ ble_name : str
64+ client : BleakClient
8865 _device : BLEDevice
89- _client : BleakClient
9066 _futures : dict [Domain , Future ]
9167 _ekey : ec .EllipticCurvePublicKey
9268 _recv : bytearray = bytearray ()
@@ -97,24 +73,30 @@ def __init__(
9773 self , parent : Tesla , vin : str , key : ec .EllipticCurvePrivateKey | None = None
9874 ):
9975 super ().__init__ (parent , vin , key )
100- self ._ble_name = "S" + hashlib .sha1 (vin .encode ('utf-8' )).hexdigest ()[:16 ] + "C"
76+ self .ble_name = "S" + hashlib .sha1 (vin .encode ('utf-8' )).hexdigest ()[:16 ] + "C"
10177 self ._futures = {}
10278
10379 async def discover (self , scanner : BleakScanner = BleakScanner ()) -> BleakClient :
10480 """Find the Tesla BLE device."""
10581
106- device = await scanner .find_device_by_name (self ._ble_name )
82+ device = await scanner .find_device_by_name (self .ble_name )
10783 if not device :
108- raise ValueError (f"Device { self ._ble_name } not found" )
84+ raise ValueError (f"Device { self .ble_name } not found" )
10985 self ._device = device
110- self ._client = BleakClient (self ._device )
86+ self .client = BleakClient (self ._device , services = [ SERVICE_UUID ] )
11187 LOGGER .info (f"Discovered device { self ._device .name } { self ._device .address } " )
112- return self ._client
88+ return self .client
11389
114- async def connect (self ) :
90+ async def connect (self , mac : str | None = None ) -> None :
11591 """Connect to the Tesla BLE device."""
116- await self ._client .connect ()
117- await self ._client .start_notify (READ_UUID , self ._on_notify )
92+ if mac is not None :
93+ self .client = BleakClient (mac , services = [SERVICE_UUID ])
94+ await self .client .connect ()
95+ await self .client .start_notify (READ_UUID , self ._on_notify )
96+
97+ async def disconnect (self ) -> bool :
98+ """Disconnect from the Tesla BLE device."""
99+ return await self .client .disconnect ()
118100
119101 def _on_notify (self ,sender : BleakGATTCharacteristic ,data : bytearray ):
120102 """Receive data from the Tesla BLE device."""
@@ -126,19 +108,19 @@ def _on_notify(self,sender: BleakGATTCharacteristic,data : bytearray):
126108 LOGGER .debug (f"Received { len (self ._recv )} of { self ._recv_len } bytes" )
127109 while len (self ._recv ) > self ._recv_len :
128110 LOGGER .warn (f"Received more data than expected: { len (self ._recv )} > { self ._recv_len } " )
129- self ._on_message (self ._recv [:self ._recv_len ])
111+ self ._on_message (bytes ( self ._recv [:self ._recv_len ]) )
130112 self ._recv_len = int .from_bytes (self ._recv [self ._recv_len :self ._recv_len + 2 ], 'big' )
131113 self ._recv = self ._recv [self ._recv_len + 2 :]
132114 continue
133115 if len (self ._recv ) == self ._recv_len :
134- self ._on_message (self ._recv )
116+ self ._on_message (bytes ( self ._recv ) )
135117 self ._recv = bytearray ()
136118 self ._recv_len = 0
137119
138- def _on_message (self , data :bytearray ):
120+ def _on_message (self , data :bytes ):
139121 """Receive messages from the Tesla BLE data."""
140122 try :
141- msg = RoutableMessage .FromString (bytes ( data ) )
123+ msg = RoutableMessage .FromString (data )
142124 except DecodeError as e :
143125 LOGGER .error (f"Error parsing message: { e } " )
144126 return
@@ -165,12 +147,6 @@ def _on_message(self, data:bytearray):
165147 self ._futures [msg .from_destination .domain ].set_result (msg )
166148 return
167149
168-
169- async def disconnect (self ):
170- """Disconnect from the Tesla BLE device."""
171- await self ._client .stop_notify (READ_UUID )
172- await self ._client .disconnect ()
173-
174150 async def _create_future (self , domain : Domain ) -> Future :
175151 if (not self ._sessions [domain ].lock .locked ):
176152 raise ValueError ("Session is not locked" )
@@ -185,7 +161,9 @@ async def _send(self, msg: RoutableMessage) -> RoutableMessage:
185161 future = await self ._create_future (domain )
186162 payload = prependLength (msg .SerializeToString ())
187163 LOGGER .info (f"Payload: { payload } " )
188- await self ._client .write_gatt_char (WRITE_UUID , payload , False )
164+
165+ await self .client .write_gatt_char (WRITE_UUID , payload , True )
166+
189167 resp = await future
190168 LOGGER .info (f"Received message { resp } " )
191169
@@ -194,7 +172,7 @@ async def _send(self, msg: RoutableMessage) -> RoutableMessage:
194172
195173 return resp
196174
197- async def pair (self , role : Role = Role .ROLE_DRIVER , form : KeyFormFactor = KeyFormFactor .KEY_FORM_FACTOR_ANDROID_DEVICE ):
175+ async def pair (self , role : Role = Role .ROLE_OWNER , form : KeyFormFactor = KeyFormFactor .KEY_FORM_FACTOR_CLOUD_KEY ):
198176 """Pair the key."""
199177
200178 request = UnsignedMessage (
0 commit comments