33import logging
44import time
55import struct
6+ import asyncio
67from threading import Thread , Event
7- from meshtastic .mesh_interface import MeshInterface
8- from meshtastic .util import our_exit
98from bleak import BleakScanner , BleakClient
10- import asyncio
119
10+ from meshtastic .mesh_interface import MeshInterface
11+ from meshtastic .util import our_exit
1212
1313SERVICE_UUID = "6ba1b218-15a8-461f-9fa8-5dcae273eafd"
1414TORADIO_UUID = "f75c76d2-129e-4dad-a1dd-7866124401e7"
1717
1818
1919class BLEInterface (MeshInterface ):
20+ """MeshInterface using BLE to connect to devices"""
2021 class BLEError (Exception ):
22+ """An exception class for BLE errors"""
2123 def __init__ (self , message ):
2224 self .message = message
2325 super ().__init__ (self .message )
2426
25-
26- class BLEState ():
27+ class BLEState (): # pylint: disable=C0115
2728 THREADS = False
2829 BLE = False
2930 MESH = False
@@ -69,13 +70,14 @@ def __init__(self, address, noProto = False, debugOut = None):
6970 self .client .start_notify (FROMNUM_UUID , self .from_num_handler )
7071
7172
72- async def from_num_handler (self , _ , b ):
73+ async def from_num_handler (self , _ , b ): # pylint: disable=C0116
7374 from_num = struct .unpack ('<I' , bytes (b ))[0 ]
7475 logging .debug (f"FROMNUM notify: { from_num } " )
7576 self .should_read = True
7677
7778
7879 def scan (self ):
80+ "Scan for available BLE devices"
7981 with BLEClient () as client :
8082 return [
8183 (x [0 ], x [1 ]) for x in (client .discover (
@@ -86,27 +88,32 @@ def scan(self):
8688
8789
8890 def find_device (self , address ):
91+ "Find a device by address"
8992 meshtastic_devices = self .scan ()
9093
91- addressed_devices = list (filter (lambda x : address == x [1 ].local_name or address == x [0 ].name , meshtastic_devices ))
94+ addressed_devices = list (filter (lambda x : address in ( x [1 ].local_name , x [0 ].name ) , meshtastic_devices ))
9295 # If nothing is found try on the address
9396 if len (addressed_devices ) == 0 :
94- addressed_devices = list (filter (lambda x : BLEInterface ._sanitize_address (address ) == BLEInterface ._sanitize_address (x [0 ].address ), meshtastic_devices ))
97+ addressed_devices = list (filter (
98+ lambda x : BLEInterface ._sanitize_address (address ) == BLEInterface ._sanitize_address (x [0 ].address ),
99+ meshtastic_devices ))
95100
96101 if len (addressed_devices ) == 0 :
97102 raise BLEInterface .BLEError (f"No Meshtastic BLE peripheral with identifier or address '{ address } ' found. Try --ble-scan to find it." )
98103 if len (addressed_devices ) > 1 :
99104 raise BLEInterface .BLEError (f"More than one Meshtastic BLE peripheral with identifier or address '{ address } ' found." )
100105 return addressed_devices [0 ][0 ]
101106
102- def _sanitize_address (address ):
107+ def _sanitize_address (address ): # pylint: disable=E0213
108+ "Standardize BLE address by removing extraneous characters and lowercasing"
103109 return address \
104110 .replace ("-" , "" ) \
105111 .replace ("_" , "" ) \
106112 .replace (":" , "" ) \
107113 .lower ()
108114
109115 def connect (self , address ):
116+ "Connect to a device by address"
110117 device = self .find_device (address )
111118 client = BLEClient (device .address )
112119 client .connect ()
@@ -156,13 +163,14 @@ def close(self):
156163 if self .state .THREADS :
157164 self ._receiveThread_started .clear ()
158165 self ._receiveThread_stopped .wait (5 )
159-
166+
160167 if self .state .BLE :
161168 self .client .disconnect ()
162169 self .client .close ()
163170
164171
165172class BLEClient ():
173+ """Client for managing connection to a BLE device"""
166174 def __init__ (self , address = None , ** kwargs ):
167175 self ._eventThread = Thread (target = self ._run_event_loop )
168176 self ._eventThread_started = Event ()
@@ -177,47 +185,46 @@ def __init__(self, address = None, **kwargs):
177185 self .bleak_client = BleakClient (address , ** kwargs )
178186
179187
180- def discover (self , ** kwargs ):
188+ def discover (self , ** kwargs ): # pylint: disable=C0116
181189 return self .async_await (BleakScanner .discover (** kwargs ))
182190
183- def pair (self , ** kwargs ):
191+ def pair (self , ** kwargs ): # pylint: disable=C0116
184192 return self .async_await (self .bleak_client .pair (** kwargs ))
185193
186- def connect (self , ** kwargs ):
194+ def connect (self , ** kwargs ): # pylint: disable=C0116
187195 return self .async_await (self .bleak_client .connect (** kwargs ))
188196
189- def disconnect (self , ** kwargs ):
197+ def disconnect (self , ** kwargs ): # pylint: disable=C0116
190198 self .async_await (self .bleak_client .disconnect (** kwargs ))
191199
192- def read_gatt_char (self , * args , ** kwargs ):
200+ def read_gatt_char (self , * args , ** kwargs ): # pylint: disable=C0116
193201 return self .async_await (self .bleak_client .read_gatt_char (* args , ** kwargs ))
194202
195- def write_gatt_char (self , * args , ** kwargs ):
203+ def write_gatt_char (self , * args , ** kwargs ): # pylint: disable=C0116
196204 self .async_await (self .bleak_client .write_gatt_char (* args , ** kwargs ))
197205
198- def start_notify (self , * args , ** kwargs ):
206+ def start_notify (self , * args , ** kwargs ): # pylint: disable=C0116
199207 self .async_await (self .bleak_client .start_notify (* args , ** kwargs ))
200208
201-
202- def close (self ):
209+ def close (self ): # pylint: disable=C0116
203210 self .async_run (self ._stop_event_loop ())
204211 self ._eventThread_stopped .wait (5 )
205212
206213 def __enter__ (self ):
207214 return self
208215
209- def __exit__ (self , type , value , traceback ):
216+ def __exit__ (self , _type , _value , _traceback ):
210217 self .close ()
211218
212-
213- def async_await (self , coro , timeout = None ):
219+ def async_await (self , coro , timeout = None ): # pylint: disable=C0116
214220 return self .async_run (coro ).result (timeout )
215221
216- def async_run (self , coro ):
222+ def async_run (self , coro ): # pylint: disable=C0116
217223 return asyncio .run_coroutine_threadsafe (coro , self ._eventLoop )
218224
219225 def _run_event_loop (self ):
220- self ._eventLoop = asyncio .new_event_loop ()
226+ # I don't know if the event loop can be initialized in __init__ so silencing pylint
227+ self ._eventLoop = asyncio .new_event_loop () # pylint: disable=W0201
221228 self ._eventThread_started .set ()
222229 try :
223230 self ._eventLoop .run_forever ()
0 commit comments