Python Bluetooth LE (Low Energy) and GATT Library providing cross-platform BLE operations with multiple backends
—
Core BLE device connection operations including characteristic reading, writing, and subscription management. The BLEDevice class provides the interface for all device-level operations once a connection is established.
Manage device connection state, bonding, and signal strength monitoring.
def bond(self, permanent: bool = False):
"""
Create a bonded (encrypted) connection with the device.
Args:
permanent: Store bond permanently for future connections
Raises:
BLEError: Bonding failed or not supported
NotConnectedError: Device not connected
"""
def disconnect(self):
"""
Disconnect from the device.
After calling this method, the BLEDevice instance becomes unusable.
Must call BLEBackend.connect() again to establish a new connection.
"""
def get_rssi(self) -> int:
"""
Get the Received Signal Strength Indicator (RSSI) from the device.
Returns:
int: RSSI value in dBm, or None if unavailable
"""Usage Example:
import pygatt
adapter = pygatt.BGAPIBackend()
adapter.start()
device = adapter.connect('01:23:45:67:89:ab')
# Create encrypted connection
device.bond(permanent=True)
# Monitor signal strength
rssi = device.get_rssi()
if rssi:
print(f"Signal strength: {rssi} dBm")
# Clean disconnect
device.disconnect()Read data from BLE characteristics using UUID or handle-based access with support for both standard and long reads.
def char_read(self, uuid: str) -> bytearray:
"""
Read a characteristic value by UUID.
Args:
uuid: Characteristic UUID as string (e.g., 'a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b')
Returns:
bytearray: Characteristic value data
Raises:
BLEError: Characteristic not found or read failed
NotConnectedError: Device not connected
"""
def char_read_handle(self, handle: int) -> bytearray:
"""
Read a characteristic value by handle.
Args:
handle: Characteristic handle as integer
Returns:
bytearray: Characteristic value data
"""
def char_read_long(self, uuid: str) -> bytearray:
"""
Read a long characteristic value by UUID.
Used for characteristics longer than MTU size.
Note: Only supported by BGAPI backend.
Args:
uuid: Characteristic UUID as string
Returns:
bytearray: Complete characteristic value data
"""
def char_read_long_handle(self, handle: int) -> bytearray:
"""
Read a long characteristic value by handle.
Args:
handle: Characteristic handle as integer
Returns:
bytearray: Complete characteristic value data
"""Usage Example:
import pygatt
adapter = pygatt.BGAPIBackend()
adapter.start()
device = adapter.connect('01:23:45:67:89:ab')
# Read by UUID
battery_level = device.char_read('00002a19-0000-1000-8000-00805f9b34fb')
print(f"Battery level: {battery_level[0]}%")
# Read by handle (if known)
value = device.char_read_handle(42)
# Read long characteristic (BGAPI only)
long_data = device.char_read_long('custom-long-uuid')Write data to BLE characteristics with configurable response handling and support for both standard and long writes.
def char_write(self, uuid: str, value: bytearray, wait_for_response: bool = True):
"""
Write data to a characteristic by UUID.
Args:
uuid: Characteristic UUID as string
value: Data to write as bytearray
wait_for_response: Wait for write confirmation (default: True)
False uses GATT "command" (no acknowledgment)
Raises:
BLEError: Write failed or characteristic not found
NotConnectedError: Device not connected
"""
def char_write_handle(self, handle: int, value: bytearray, wait_for_response: bool = True):
"""
Write data to a characteristic by handle.
Args:
handle: Characteristic handle as integer
value: Data to write as bytearray
wait_for_response: Wait for write confirmation
"""
def char_write_long(self, uuid: str, value: bytearray, wait_for_response: bool = False):
"""
Write long data to a characteristic by UUID.
Used for data longer than MTU size.
Note: Only supported by BGAPI backend.
Args:
uuid: Characteristic UUID as string
value: Data to write as bytearray
wait_for_response: Wait for write confirmation
"""
def char_write_long_handle(self, handle: int, value: bytearray, wait_for_response: bool = False):
"""
Write long data to a characteristic by handle.
Args:
handle: Characteristic handle as integer
value: Data to write as bytearray
wait_for_response: Wait for write confirmation
"""Usage Example:
import pygatt
adapter = pygatt.GATTToolBackend()
adapter.start()
device = adapter.connect('01:23:45:67:89:ab')
# Write command to device
device.char_write('a1e8f5b1-696b-4e4c-87c6-69dfe0b0093b',
bytearray([0x01, 0x02, 0x03]))
# Fast write without waiting for response
device.char_write('command-uuid',
bytearray([0xFF]),
wait_for_response=False)
# Write configuration to handle
device.char_write_handle(45, bytearray([0x01, 0x00]))Subscribe to characteristic changes for real-time data streaming with callback-based event handling.
def subscribe(self, uuid: str, callback=None, indication: bool = False, wait_for_response: bool = True):
"""
Subscribe to notifications or indications for a characteristic.
Args:
uuid: Characteristic UUID as string
callback: Function called when data received: callback(handle, value)
handle: int, characteristic handle
value: bytearray, notification data
indication: Use indications (ACKed) instead of notifications
More reliable but slower
wait_for_response: Wait for subscription confirmation
Raises:
BLEError: Subscription failed or characteristic not found
"""
def unsubscribe(self, uuid: str, wait_for_response: bool = True):
"""
Unsubscribe from notifications for a characteristic.
Args:
uuid: Characteristic UUID as string
wait_for_response: Wait for unsubscription confirmation
"""
def subscribe_handle(self, handle: int, callback=None, indication: bool = False, wait_for_response: bool = True):
"""
Subscribe to notifications using characteristic handle.
Args:
handle: Characteristic handle as integer
callback: Notification callback function
indication: Use indications instead of notifications
wait_for_response: Wait for subscription confirmation
"""
def unsubscribe_handle(self, handle: int, wait_for_response: bool = True):
"""
Unsubscribe from notifications using characteristic handle.
Args:
handle: Characteristic handle as integer
wait_for_response: Wait for unsubscription confirmation
"""
def resubscribe_all(self):
"""
Reenable all previous subscriptions after reconnection.
Must be called after connection loss and subsequent reconnect
to restore notification subscriptions.
"""Usage Example:
import pygatt
import time
from binascii import hexlify
adapter = pygatt.GATTToolBackend()
def sensor_callback(handle, value):
"""Handle sensor data notifications"""
print(f"Sensor data on handle {handle}: {hexlify(value)}")
# Parse sensor data based on your device protocol
if len(value) >= 4:
temperature = int.from_bytes(value[:2], 'little') / 100.0
humidity = int.from_bytes(value[2:4], 'little') / 100.0
print(f"Temperature: {temperature}°C, Humidity: {humidity}%")
try:
adapter.start()
device = adapter.connect('01:23:45:67:89:ab')
# Subscribe to sensor notifications
device.subscribe('environmental-sensor-uuid',
callback=sensor_callback,
indication=False)
# Keep program running to receive notifications
print("Listening for notifications... Press Ctrl+C to stop")
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Stopping...")
finally:
adapter.stop()Discover and map available characteristics on the connected device.
def get_handle(self, char_uuid: str) -> int:
"""
Look up and return the handle for a characteristic by UUID.
Automatically discovers characteristics if not already cached.
Args:
char_uuid: Characteristic UUID as string
Returns:
int: Characteristic handle
Raises:
BLEError: Characteristic not found
"""
def discover_characteristics(self) -> dict:
"""
Discover all characteristics available on the device.
Returns:
dict: Mapping of UUID to Characteristic objects
{UUID('uuid-string'): Characteristic(uuid, handle)}
"""Usage Example:
import pygatt
adapter = pygatt.BGAPIBackend()
adapter.start()
device = adapter.connect('01:23:45:67:89:ab')
# Discover all characteristics
characteristics = device.discover_characteristics()
for uuid, char in characteristics.items():
print(f"Characteristic {uuid}: handle={char.handle}")
# Get specific handle
battery_handle = device.get_handle('00002a19-0000-1000-8000-00805f9b34fb')
print(f"Battery service handle: {battery_handle}")Negotiate Maximum Transmission Unit size for larger data transfers.
def exchange_mtu(self, mtu: int) -> int:
"""
Request MTU (Maximum Transmission Unit) exchange with device.
Args:
mtu: Requested MTU size in bytes
Returns:
int: Negotiated MTU size as accepted by device
Raises:
BLEError: MTU exchange failed
NotImplementedError: Backend doesn't support MTU exchange
"""Usage Example:
# Request larger MTU for bigger data transfers
new_mtu = device.exchange_mtu(512)
print(f"Negotiated MTU: {new_mtu} bytes")Common device operation errors:
Install with Tessl CLI
npx tessl i tessl/pypi-pygatt