0
# Data Structures and Models
1
2
Bleak provides comprehensive data structures representing BLE devices, advertisement data, and the complete GATT hierarchy including services, characteristics, and descriptors. These models provide a consistent interface across all supported platforms.
3
4
## Capabilities
5
6
### BLE Device Representation
7
8
Core representation of discovered BLE devices with address, name, and platform-specific details.
9
10
```python { .api }
11
class BLEDevice:
12
"""A simple wrapper class representing a BLE server detected during scanning."""
13
14
__slots__ = ("address", "name", "details")
15
16
def __init__(self, address: str, name: Optional[str], details: Any, **kwargs: Any):
17
"""
18
Initialize BLE device representation.
19
20
Args:
21
address: Bluetooth address of the device on this machine (UUID on macOS)
22
name: Operating system name of the device (not necessarily the local name
23
from advertising data), suitable for display to the user
24
details: OS native details required for connecting to the device
25
**kwargs: Deprecated additional arguments (no effect)
26
"""
27
28
address: str # The Bluetooth address of the device on this machine (UUID on macOS)
29
name: Optional[str] # The operating system name of the device, suitable for display
30
details: Any # The OS native details required for connecting to the device
31
32
def __str__(self) -> str:
33
"""String representation showing address and name."""
34
35
def __repr__(self) -> str:
36
"""Detailed string representation for debugging."""
37
```
38
39
### Advertisement Data Container
40
41
Structured container for BLE advertisement data received during device discovery.
42
43
```python { .api }
44
class AdvertisementData(NamedTuple):
45
"""Container for BLE advertisement data from device discovery."""
46
47
local_name: Optional[str]
48
"""Device local name or None if not included in advertising data."""
49
50
manufacturer_data: dict[int, bytes]
51
"""
52
Dictionary of manufacturer data from advertising.
53
Keys are Bluetooth SIG Company Identifiers, values are data bytes.
54
"""
55
56
service_data: dict[str, bytes]
57
"""
58
Dictionary of service data from advertising.
59
Keys are service UUIDs, values are associated data bytes.
60
"""
61
62
service_uuids: list[str]
63
"""List of service UUIDs advertised by the device."""
64
65
tx_power: Optional[int]
66
"""TX Power Level in dBm from advertising data, or None if not present."""
67
68
rssi: int
69
"""Radio Receive Signal Strength Indicator (RSSI) in dBm."""
70
71
platform_data: tuple[Any, ...]
72
"""
73
Tuple of platform-specific data.
74
This is not a stable API and may change between releases.
75
"""
76
77
def __repr__(self) -> str:
78
"""Detailed string representation showing all available data."""
79
```
80
81
### GATT Service Collection
82
83
Container managing the complete GATT service hierarchy for a connected device.
84
85
```python { .api }
86
class BleakGATTServiceCollection:
87
"""Simple data container for storing the peripheral's service complement."""
88
89
def __init__(self) -> None:
90
"""Initialize empty service collection."""
91
92
def __getitem__(
93
self, item: Union[str, int, UUID]
94
) -> Optional[Union[BleakGATTService, BleakGATTCharacteristic, BleakGATTDescriptor]]:
95
"""Get service, characteristic, or descriptor by UUID or handle."""
96
97
def __iter__(self) -> Iterator[BleakGATTService]:
98
"""Returns an iterator over all BleakGATTService objects."""
99
100
@property
101
def services(self) -> dict[int, BleakGATTService]:
102
"""Returns dictionary of handles mapping to BleakGATTService."""
103
104
@property
105
def characteristics(self) -> dict[int, BleakGATTCharacteristic]:
106
"""Returns dictionary of handles mapping to BleakGATTCharacteristic."""
107
108
@property
109
def descriptors(self) -> dict[int, BleakGATTDescriptor]:
110
"""Returns a dictionary of integer handles mapping to BleakGATTDescriptor."""
111
112
def get_service(
113
self, specifier: Union[int, str, UUID]
114
) -> Optional[BleakGATTService]:
115
"""
116
Get service by handle (int) or UUID (str or uuid.UUID).
117
118
Args:
119
specifier: Service handle (int) or UUID (str/UUID)
120
121
Returns:
122
BleakGATTService if found, None otherwise
123
124
Raises:
125
BleakError: If multiple services have the same UUID
126
"""
127
128
def get_characteristic(
129
self, specifier: Union[int, str, UUID]
130
) -> Optional[BleakGATTCharacteristic]:
131
"""
132
Get characteristic by handle (int) or UUID (str or uuid.UUID).
133
134
Args:
135
specifier: Characteristic handle (int) or UUID (str/UUID)
136
137
Returns:
138
BleakGATTCharacteristic if found, None otherwise
139
140
Raises:
141
BleakError: If multiple characteristics have the same UUID
142
"""
143
144
def get_descriptor(self, handle: int) -> Optional[BleakGATTDescriptor]:
145
"""
146
Get descriptor by handle.
147
148
Args:
149
handle: Descriptor handle
150
151
Returns:
152
BleakGATTDescriptor if found, None otherwise
153
"""
154
```
155
156
### GATT Service Representation
157
158
Representation of a GATT service containing characteristics and metadata.
159
160
```python { .api }
161
class BleakGATTService:
162
"""Representation of a GATT service."""
163
164
def __init__(self, obj: Any, handle: int, uuid: str) -> None:
165
"""
166
Initialize GATT service.
167
168
Args:
169
obj: Platform-specific service object
170
handle: Service handle
171
uuid: Service UUID
172
"""
173
174
def __str__(self) -> str:
175
"""String representation showing UUID, handle, and description."""
176
177
@property
178
def handle(self) -> int:
179
"""Handle of this service."""
180
181
@property
182
def uuid(self) -> str:
183
"""UUID of this service."""
184
185
@property
186
def description(self) -> str:
187
"""Human-readable description of this service."""
188
189
@property
190
def characteristics(self) -> list[BleakGATTCharacteristic]:
191
"""List of characteristics belonging to this service."""
192
193
def get_characteristic(
194
self, uuid: Union[str, UUID]
195
) -> Union[BleakGATTCharacteristic, None]:
196
"""
197
Get characteristic by UUID.
198
199
Args:
200
uuid: Characteristic UUID to match
201
202
Returns:
203
First matching BleakGATTCharacteristic or None
204
"""
205
```
206
207
### GATT Characteristic Representation
208
209
Representation of a GATT characteristic with properties, descriptors, and metadata.
210
211
```python { .api }
212
class BleakGATTCharacteristic:
213
"""Representation of a GATT characteristic."""
214
215
def __init__(
216
self,
217
obj: Any,
218
handle: int,
219
uuid: str,
220
properties: list[CharacteristicPropertyName],
221
max_write_without_response_size: Callable[[], int],
222
service: BleakGATTService,
223
):
224
"""
225
Initialize GATT characteristic.
226
227
Args:
228
obj: Platform-specific characteristic object
229
handle: Characteristic handle
230
uuid: Characteristic UUID
231
properties: List of characteristic properties
232
max_write_without_response_size: Function returning max write size
233
service: Parent service
234
"""
235
236
def __str__(self) -> str:
237
"""String representation showing UUID, handle, and description."""
238
239
@property
240
def service_uuid(self) -> str:
241
"""UUID of the service containing this characteristic."""
242
243
@property
244
def service_handle(self) -> int:
245
"""Handle of the service containing this characteristic."""
246
247
@property
248
def handle(self) -> int:
249
"""Handle of this characteristic."""
250
251
@property
252
def uuid(self) -> str:
253
"""UUID of this characteristic."""
254
255
@property
256
def description(self) -> str:
257
"""Human-readable description of this characteristic."""
258
259
@property
260
def properties(self) -> list[CharacteristicPropertyName]:
261
"""List of properties supported by this characteristic."""
262
263
@property
264
def max_write_without_response_size(self) -> int:
265
"""
266
Maximum size for write-without-response operations.
267
268
Note: May return default value (20) initially and update later.
269
BlueZ versions < 5.62 always return 20.
270
"""
271
272
@property
273
def descriptors(self) -> list[BleakGATTDescriptor]:
274
"""List of descriptors belonging to this characteristic."""
275
276
def get_descriptor(
277
self, specifier: Union[int, str, UUID]
278
) -> Union[BleakGATTDescriptor, None]:
279
"""
280
Get descriptor by handle or UUID.
281
282
Args:
283
specifier: Descriptor handle (int) or UUID (str/UUID)
284
285
Returns:
286
BleakGATTDescriptor if found, None otherwise
287
"""
288
```
289
290
### GATT Descriptor Representation
291
292
Representation of a GATT descriptor with metadata and parent characteristic reference.
293
294
```python { .api }
295
class BleakGATTDescriptor:
296
"""Representation of a GATT descriptor."""
297
298
def __init__(
299
self, obj: Any, handle: int, uuid: str, characteristic: BleakGATTCharacteristic
300
):
301
"""
302
Initialize GATT descriptor.
303
304
Args:
305
obj: Platform-specific descriptor object
306
handle: Descriptor handle
307
uuid: Descriptor UUID
308
characteristic: Parent characteristic
309
"""
310
311
def __str__(self) -> str:
312
"""String representation showing UUID, handle, and description."""
313
314
@property
315
def characteristic_uuid(self) -> str:
316
"""UUID of the characteristic this descriptor belongs to."""
317
318
@property
319
def characteristic_handle(self) -> int:
320
"""Handle of the characteristic this descriptor belongs to."""
321
322
@property
323
def uuid(self) -> str:
324
"""UUID of this descriptor."""
325
326
@property
327
def handle(self) -> int:
328
"""Handle of this descriptor."""
329
330
@property
331
def description(self) -> str:
332
"""Human-readable description of this descriptor."""
333
```
334
335
### Characteristic Properties and Flags
336
337
Enumeration and utilities for GATT characteristic properties.
338
339
```python { .api }
340
class GattCharacteristicsFlags(enum.Enum):
341
"""Enumeration of GATT characteristic property flags."""
342
343
broadcast = 0x0001
344
read = 0x0002
345
write_without_response = 0x0004
346
write = 0x0008
347
notify = 0x0010
348
indicate = 0x0020
349
authenticated_signed_writes = 0x0040
350
extended_properties = 0x0080
351
reliable_write = 0x0100
352
writable_auxiliaries = 0x0200
353
354
def gatt_char_props_to_strs(
355
props: int,
356
) -> frozenset[CharacteristicPropertyName]:
357
"""
358
Convert characteristic properties bitmask to set of property names.
359
360
Args:
361
props: Properties bitmask
362
363
Returns:
364
Frozenset of property name strings
365
"""
366
```
367
368
## Usage Examples
369
370
### Working with Discovered Devices
371
372
```python
373
import asyncio
374
from bleak import BleakScanner
375
376
async def analyze_discovered_devices():
377
# Discover devices with advertisement data
378
discovered = await BleakScanner.discover(timeout=10.0, return_adv=True)
379
380
for address, (device, adv_data) in discovered.items():
381
print(f"Device: {device}")
382
print(f" Address: {device.address}")
383
print(f" Name: {device.name}")
384
385
print(f" Advertisement Data:")
386
print(f" Local Name: {adv_data.local_name}")
387
print(f" RSSI: {adv_data.rssi} dBm")
388
print(f" TX Power: {adv_data.tx_power}")
389
print(f" Service UUIDs: {adv_data.service_uuids}")
390
391
# Process manufacturer data
392
for company_id, data in adv_data.manufacturer_data.items():
393
print(f" Manufacturer {company_id:04x}: {data.hex()}")
394
395
# Process service data
396
for service_uuid, data in adv_data.service_data.items():
397
print(f" Service {service_uuid}: {data.hex()}")
398
399
asyncio.run(analyze_discovered_devices())
400
```
401
402
### Exploring GATT Hierarchy
403
404
```python
405
import asyncio
406
from bleak import BleakClient
407
408
async def explore_gatt_structure():
409
address = "00:11:22:33:44:55" # Replace with actual device address
410
411
async with BleakClient(address) as client:
412
services = client.services
413
414
print(f"Device has {len(services.services)} services")
415
print(f"Total characteristics: {len(services.characteristics)}")
416
print(f"Total descriptors: {len(services.descriptors)}")
417
418
# Iterate through service collection
419
for service in services:
420
print(f"\nService: {service}")
421
print(f" Handle: {service.handle}")
422
print(f" UUID: {service.uuid}")
423
print(f" Description: {service.description}")
424
425
for char in service.characteristics:
426
print(f" Characteristic: {char}")
427
print(f" Handle: {char.handle}")
428
print(f" UUID: {char.uuid}")
429
print(f" Properties: {char.properties}")
430
print(f" Max write size: {char.max_write_without_response_size}")
431
432
for desc in char.descriptors:
433
print(f" Descriptor: {desc}")
434
print(f" Handle: {desc.handle}")
435
print(f" UUID: {desc.uuid}")
436
437
asyncio.run(explore_gatt_structure())
438
```
439
440
### Finding Specific Services and Characteristics
441
442
```python
443
import asyncio
444
from bleak import BleakClient
445
446
async def find_specific_elements():
447
address = "00:11:22:33:44:55" # Replace with actual device address
448
449
async with BleakClient(address) as client:
450
services = client.services
451
452
# Find Generic Access service
453
gap_service = services.get_service("00001800-0000-1000-8000-00805f9b34fb")
454
if gap_service:
455
print(f"Found GAP service: {gap_service.description}")
456
457
# Find device name characteristic within the service
458
device_name_char = gap_service.get_characteristic(
459
"00002a00-0000-1000-8000-00805f9b34fb"
460
)
461
if device_name_char:
462
print(f"Found device name characteristic: {device_name_char.description}")
463
464
# Find characteristic by UUID across all services
465
battery_char = services.get_characteristic("00002a19-0000-1000-8000-00805f9b34fb")
466
if battery_char:
467
print(f"Found battery level characteristic: {battery_char.description}")
468
print(f" Service UUID: {battery_char.service_uuid}")
469
print(f" Properties: {battery_char.properties}")
470
471
# Find descriptor by handle
472
desc = services.get_descriptor(42) # Replace with actual handle
473
if desc:
474
print(f"Found descriptor: {desc.description}")
475
print(f" Characteristic UUID: {desc.characteristic_uuid}")
476
477
asyncio.run(find_specific_elements())
478
```
479
480
### Working with Characteristic Properties
481
482
```python
483
from bleak.assigned_numbers import gatt_char_props_to_strs
484
485
def analyze_characteristic_properties():
486
# Example properties bitmask
487
props_mask = 0x12 # read (0x02) + notify (0x10)
488
489
# Convert to property names
490
properties = gatt_char_props_to_strs(props_mask)
491
print(f"Properties: {properties}")
492
493
# Check for specific properties
494
if "read" in properties:
495
print("Characteristic supports reading")
496
497
if "notify" in properties:
498
print("Characteristic supports notifications")
499
500
if "write" in properties:
501
print("Characteristic supports write-with-response")
502
503
if "write-without-response" in properties:
504
print("Characteristic supports write-without-response")
505
506
analyze_characteristic_properties()
507
```
508
509
## Types
510
511
```python { .api }
512
# Characteristic property names
513
CharacteristicPropertyName = Literal[
514
"broadcast",
515
"read",
516
"write-without-response",
517
"write",
518
"notify",
519
"indicate",
520
"authenticated-signed-writes",
521
"extended-properties",
522
"reliable-write",
523
"writable-auxiliaries",
524
"encrypt-read",
525
"encrypt-write",
526
"encrypt-authenticated-read",
527
"encrypt-authenticated-write",
528
"authorize",
529
]
530
531
# Advertisement data type enumeration
532
class AdvertisementDataType(IntEnum):
533
FLAGS = 0x01
534
INCOMPLETE_LIST_SERVICE_UUID16 = 0x02
535
COMPLETE_LIST_SERVICE_UUID16 = 0x03
536
INCOMPLETE_LIST_SERVICE_UUID32 = 0x04
537
COMPLETE_LIST_SERVICE_UUID32 = 0x05
538
INCOMPLETE_LIST_SERVICE_UUID128 = 0x06
539
COMPLETE_LIST_SERVICE_UUID128 = 0x07
540
SHORTENED_LOCAL_NAME = 0x08
541
COMPLETE_LOCAL_NAME = 0x09
542
TX_POWER_LEVEL = 0x0A
543
CLASS_OF_DEVICE = 0x0D
544
SERVICE_DATA_UUID16 = 0x16
545
SERVICE_DATA_UUID32 = 0x20
546
SERVICE_DATA_UUID128 = 0x21
547
MANUFACTURER_SPECIFIC_DATA = 0xFF
548
549
# Property mapping for internal use
550
CHARACTERISTIC_PROPERTIES: dict[int, CharacteristicPropertyName] = {
551
0x1: "broadcast",
552
0x2: "read",
553
0x4: "write-without-response",
554
0x8: "write",
555
0x10: "notify",
556
0x20: "indicate",
557
0x40: "authenticated-signed-writes",
558
0x80: "extended-properties",
559
0x100: "reliable-write",
560
0x200: "writable-auxiliaries",
561
}
562
```