0
# pygatt
1
2
Python Bluetooth LE (Low Energy) and GATT Library that provides a Pythonic API for reading and writing GATT descriptors on BLE devices such as fitness trackers, sensors, and standard GATT-compliant devices. The library wraps two different backends to provide cross-platform compatibility: BlueZ (Linux-based using gatttool) and Bluegiga's BGAPI (compatible with USB adapters like BLED112).
3
4
## Package Information
5
6
- **Package Name**: pygatt
7
- **Language**: Python
8
- **Installation**: `pip install pygatt`
9
- **GATT Tool Backend**: `pip install "pygatt[GATTTOOL]"` (Linux only, requires pexpect)
10
11
## Core Imports
12
13
```python
14
import pygatt
15
```
16
17
Main components:
18
19
```python
20
from pygatt import BGAPIBackend, GATTToolBackend, BLEAddressType, BLEError, BLEDevice
21
from pygatt.backends import Characteristic
22
```
23
24
## Basic Usage
25
26
### BGAPI Backend (Cross-platform)
27
28
```python
29
import pygatt
30
31
# Initialize BGAPI backend for USB dongle (BLED112, etc.)
32
adapter = pygatt.BGAPIBackend()
33
34
try:
35
adapter.start()
36
device = adapter.connect('01:23:45:67:89:ab')
37
38
# Read a characteristic
39
value = device.char_read("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b")
40
print(f"Read value: {value.hex()}")
41
42
# Write to a characteristic
43
device.char_write("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b", bytearray([0x01, 0x02]))
44
45
finally:
46
adapter.stop()
47
```
48
49
### GATTTool Backend (Linux only)
50
51
```python
52
import pygatt
53
54
# Initialize GATTTool backend for BlueZ
55
adapter = pygatt.GATTToolBackend()
56
57
try:
58
adapter.start()
59
device = adapter.connect('01:23:45:67:89:ab')
60
value = device.char_read("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b")
61
finally:
62
adapter.stop()
63
```
64
65
### Notifications and Indications
66
67
```python
68
import pygatt
69
from binascii import hexlify
70
71
adapter = pygatt.GATTToolBackend()
72
73
def handle_data(handle, value):
74
"""
75
Callback function for notifications
76
handle -- integer, characteristic handle
77
value -- bytearray, the notification data
78
"""
79
print(f"Received data on handle {handle}: {hexlify(value)}")
80
81
try:
82
adapter.start()
83
device = adapter.connect('01:23:45:67:89:ab')
84
85
# Subscribe to notifications
86
device.subscribe("a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b", callback=handle_data)
87
88
# Keep program running to receive notifications
89
import time
90
while True:
91
time.sleep(1)
92
93
finally:
94
adapter.stop()
95
```
96
97
## Architecture
98
99
pygatt uses a backend abstraction pattern to support different BLE communication methods:
100
101
- **BLEBackend**: Abstract base class defining the adapter interface
102
- **BLEDevice**: Abstract base class defining the device connection interface
103
- Backend implementations provide concrete implementations for specific hardware/OS combinations
104
- All backends expose the same high-level API for consistent cross-platform development
105
106
## Capabilities
107
108
### Backend Management
109
110
Core backend lifecycle and configuration operations for initializing and managing BLE adapters.
111
112
```python { .api }
113
class BLEBackend:
114
def start(self): ...
115
def stop(self): ...
116
def supports_unbonded(self) -> bool: ...
117
def connect(self, address: str, timeout: float = 5.0, **kwargs) -> BLEDevice: ...
118
def scan(self, *args, **kwargs) -> list: ...
119
def filtered_scan(self, name_filter: str = "", *args, **kwargs) -> list: ...
120
def clear_bond(self, address: str = None): ...
121
```
122
123
[Backend Management](./backend-management.md)
124
125
### Device Operations
126
127
Core BLE device connection operations including characteristic reading, writing, and subscription management.
128
129
```python { .api }
130
class BLEDevice:
131
def bond(self, permanent: bool = False): ...
132
def disconnect(self): ...
133
def get_rssi(self) -> int: ...
134
def char_read(self, uuid: str) -> bytearray: ...
135
def char_read_handle(self, handle: int) -> bytearray: ...
136
def char_read_long(self, uuid: str) -> bytearray: ...
137
def char_read_long_handle(self, handle: int) -> bytearray: ...
138
def char_write(self, uuid: str, value: bytearray, wait_for_response: bool = True): ...
139
def char_write_handle(self, handle: int, value: bytearray, wait_for_response: bool = True): ...
140
def char_write_long(self, uuid: str, value: bytearray, wait_for_response: bool = False): ...
141
def char_write_long_handle(self, handle: int, value: bytearray, wait_for_response: bool = False): ...
142
def subscribe(self, uuid: str, callback=None, indication: bool = False, wait_for_response: bool = True): ...
143
def unsubscribe(self, uuid: str, wait_for_response: bool = True): ...
144
def subscribe_handle(self, handle: int, callback=None, indication: bool = False, wait_for_response: bool = True): ...
145
def unsubscribe_handle(self, handle: int, wait_for_response: bool = True): ...
146
def get_handle(self, char_uuid: str) -> int: ...
147
def discover_characteristics(self) -> dict: ...
148
def exchange_mtu(self, mtu: int) -> int: ...
149
def resubscribe_all(self): ...
150
```
151
152
[Device Operations](./device-operations.md)
153
154
### BGAPI Backend
155
156
BGAPI-specific backend implementation for USB dongles with advanced configuration options and low-level protocol access.
157
158
```python { .api }
159
class BGAPIBackend(BLEBackend):
160
def __init__(self, serial_port: str = None, receive_queue_timeout: float = 0.1): ...
161
def start(self, reset: bool = True, delay_after_reset_s: float = 1): ...
162
def get_mac(self) -> str: ...
163
def scan(self, timeout: int = 10, scan_interval: int = 75, scan_window: int = 50, active: bool = True, **kwargs): ...
164
def set_bondable(self, bondable: bool): ...
165
def discover_characteristics(self, connection_handle: int, timeout: int = 30) -> dict: ...
166
```
167
168
[BGAPI Backend](./bgapi-backend.md)
169
170
### GATTTool Backend
171
172
GATTTool-specific backend implementation for Linux BlueZ with CLI integration and advanced debugging capabilities.
173
174
```python { .api }
175
class GATTToolBackend(BLEBackend):
176
def __init__(self, hci_device: str = "hci0", gatttool_logfile: str = None, cli_options: list = None, search_window_size: int = None, max_read: int = None): ...
177
def start(self, reset_on_start: bool = True, initialization_timeout: int = 3): ...
178
def scan(self, timeout: int = 10, run_as_root: bool = False) -> list: ...
179
def reset(self): ...
180
def sendline(self, command: str): ...
181
```
182
183
[GATTTool Backend](./gatttool-backend.md)
184
185
### Error Handling
186
187
Exception classes and error management for comprehensive BLE error handling and debugging.
188
189
```python { .api }
190
class BLEError(Exception): ...
191
class NotConnectedError(BLEError): ...
192
class NotificationTimeout(BLEError):
193
def __init__(self, msg: str = None, gatttool_output: str = None): ...
194
class BGAPIError(Exception): ...
195
class ExpectedResponseTimeout(BGAPIError):
196
def __init__(self, expected_packets, timeout): ...
197
```
198
199
[Error Handling](./error-handling.md)
200
201
### Utilities
202
203
Utility functions and classes for UUID conversion, device discovery, and USB serial device management.
204
205
```python { .api }
206
def uuid16_to_uuid(uuid16: int) -> UUID: ...
207
def find_usb_serial_devices(vendor_id: int = None, product_id: int = None) -> list: ...
208
def extract_vid_pid(info_string: str) -> tuple: ...
209
```
210
211
[Utilities](./utilities.md)
212
213
## Types
214
215
```python { .api }
216
from enum import Enum
217
from uuid import UUID
218
from collections import defaultdict
219
220
class BLEAddressType(Enum):
221
public = "public"
222
random = "random"
223
224
class Characteristic:
225
def __init__(self, uuid: UUID, handle: int):
226
self.uuid = uuid
227
self.handle = handle
228
self.descriptors = {}
229
230
def add_descriptor(self, uuid: str, handle: int): ...
231
232
class USBSerialDeviceInfo:
233
def __init__(self, device_name: str, port_name: str, vendor_id: int, product_id: int):
234
self.device_name = device_name
235
self.port_name = port_name
236
self.vendor_id = vendor_id
237
self.product_id = product_id
238
```