or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

data-structures.mddevice-discovery.mdexception-handling.mdgatt-client.mdindex.mduuid-utilities.md

data-structures.mddocs/

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

```