Python Bluetooth LE (Low Energy) and GATT Library providing cross-platform BLE operations with multiple backends
—
Utility functions and classes for UUID conversion, device discovery, and USB serial device management. These utilities provide helper functionality for common BLE development tasks and hardware integration.
Convert between different UUID formats commonly used in BLE applications.
def uuid16_to_uuid(uuid16: int) -> UUID:
"""
Convert 16-bit UUID to full 128-bit UUID format.
Converts Bluetooth SIG assigned 16-bit UUIDs to their full 128-bit
representation using the Bluetooth base UUID.
Args:
uuid16: 16-bit UUID as integer (e.g., 0x180F for Battery Service)
Returns:
UUID: Full 128-bit UUID object
Example:
Battery Service UUID 0x180F becomes:
0000180F-0000-1000-8000-00805F9B34FB
"""Usage Example:
import pygatt
from pygatt.util import uuid16_to_uuid
# Convert standard Bluetooth service UUIDs
battery_service = uuid16_to_uuid(0x180F)
print(battery_service) # 0000180f-0000-1000-8000-00805f9b34fb
device_info_service = uuid16_to_uuid(0x180A)
print(device_info_service) # 0000180a-0000-1000-8000-00805f9b34fb
# Use converted UUID with pygatt
adapter = pygatt.BGAPIBackend()
adapter.start()
device = adapter.connect('01:23:45:67:89:ab')
# Read battery level using converted UUID
battery_level = device.char_read(str(battery_service))Discover and enumerate USB serial devices for BGAPI backend configuration.
def find_usb_serial_devices(vendor_id: int = None, product_id: int = None) -> list:
"""
Discover USB serial devices matching optional vendor/product ID filters.
Args:
vendor_id: USB vendor ID to filter by (e.g., 0x2458 for Silicon Labs)
product_id: USB product ID to filter by (e.g., 0x0001 for BLED112)
Returns:
list: List of USBSerialDeviceInfo objects for matching devices
Raises:
ImportError: If required USB enumeration libraries not available
"""
def extract_vid_pid(info_string: str) -> tuple:
"""
Extract vendor ID and product ID from USB device info string.
Args:
info_string: USB device information string from system
Returns:
tuple: (vendor_id: int, product_id: int) or (None, None) if not found
"""Usage Example:
import pygatt
from pygatt.backends.bgapi.util import find_usb_serial_devices, extract_vid_pid
# Find all USB serial devices
all_devices = find_usb_serial_devices()
for device in all_devices:
print(f"Device: {device.device_name}")
print(f"Port: {device.port_name}")
print(f"VID: 0x{device.vendor_id:04X}, PID: 0x{device.product_id:04X}")
# Find BLED112 devices specifically
bled112_devices = find_usb_serial_devices(
vendor_id=0x2458, # Silicon Labs
product_id=0x0001 # BLED112
)
if bled112_devices:
# Use first BLED112 found
device = bled112_devices[0]
adapter = pygatt.BGAPIBackend(serial_port=device.port_name)
print(f"Using BLED112 on {device.port_name}")
else:
print("No BLED112 devices found")
# Parse device info manually
info = "USB\\VID_2458&PID_0001\\12345"
vid, pid = extract_vid_pid(info)
if vid and pid:
print(f"Found device: VID=0x{vid:04X}, PID=0x{pid:04X}")Container class for USB serial device metadata and connection details.
class USBSerialDeviceInfo:
"""
Container for USB serial device information.
Attributes:
device_name: Human-readable device name
port_name: System port name for serial connection
vendor_id: USB vendor ID as integer
product_id: USB product ID as integer
"""
def __init__(self, device_name: str, port_name: str, vendor_id: int, product_id: int):
self.device_name = device_name
self.port_name = port_name
self.vendor_id = vendor_id
self.product_id = product_idUsage Example:
from pygatt.backends.bgapi.util import USBSerialDeviceInfo
# Create device info manually
device_info = USBSerialDeviceInfo(
device_name="Silicon Labs BLED112",
port_name="COM9", # Windows
vendor_id=0x2458,
product_id=0x0001
)
print(f"Device: {device_info.device_name}")
print(f"Connect via: {device_info.port_name}")
# Use with BGAPI backend
adapter = pygatt.BGAPIBackend(serial_port=device_info.port_name)Predefined constants for common BGAPI-compatible hardware identification.
# Silicon Labs BLED112 USB BLE adapter
BLED112_VENDOR_ID = 0x2458
BLED112_PRODUCT_ID = 0x0001
# Usage in device discovery
from pygatt.backends.bgapi.constants import BLED112_VENDOR_ID, BLED112_PRODUCT_ID
bled112_devices = find_usb_serial_devices(
vendor_id=BLED112_VENDOR_ID,
product_id=BLED112_PRODUCT_ID
)Handle cross-platform differences in USB device enumeration and serial port naming.
import pygatt
from pygatt.backends.bgapi.util import find_usb_serial_devices
# Windows-specific COM port handling
devices = find_usb_serial_devices()
for device in devices:
if device.port_name.startswith('COM'):
print(f"Windows COM port: {device.port_name}")
# Handle COM ports > 9 (Windows limitation)
if int(device.port_name[3:]) > 9:
print("Warning: COM ports >9 may require special handling")import pygatt
from pygatt.backends.bgapi.util import find_usb_serial_devices
# Unix-style device path handling
devices = find_usb_serial_devices()
for device in devices:
if device.port_name.startswith('/dev/'):
print(f"Unix device path: {device.port_name}")
# Common Linux patterns
if 'ttyACM' in device.port_name:
print("USB CDC ACM device (typical for BGAPI)")
elif 'ttyUSB' in device.port_name:
print("USB serial converter device")
elif 'cu.usbmodem' in device.port_name:
print("macOS USB modem device")Implement intelligent device selection for robust applications.
import pygatt
from pygatt.backends.bgapi.util import find_usb_serial_devices
from pygatt.backends.bgapi.constants import BLED112_VENDOR_ID, BLED112_PRODUCT_ID
def auto_select_bgapi_device():
"""
Automatically select best BGAPI device available.
Returns:
str: Serial port name for selected device
Raises:
pygatt.BGAPIError: No suitable devices found
"""
# First, look for known BGAPI devices
bgapi_devices = find_usb_serial_devices(
vendor_id=BLED112_VENDOR_ID,
product_id=BLED112_PRODUCT_ID
)
if bgapi_devices:
device = bgapi_devices[0] # Use first BLED112
print(f"Selected BLED112: {device.port_name}")
return device.port_name
# Fallback: look for any Silicon Labs device
siliconlabs_devices = find_usb_serial_devices(vendor_id=0x2458)
if siliconlabs_devices:
device = siliconlabs_devices[0]
print(f"Selected Silicon Labs device: {device.port_name}")
return device.port_name
# Last resort: let BGAPI backend auto-discover
print("No specific devices found, using auto-discovery")
return None
# Usage
try:
port = auto_select_bgapi_device()
adapter = pygatt.BGAPIBackend(serial_port=port)
adapter.start()
print("BGAPI backend initialized successfully")
except pygatt.BGAPIError as e:
print(f"Failed to initialize BGAPI: {e}")
print("Check USB connections and drivers")Monitor USB device health and connection stability.
import time
import threading
from pygatt.backends.bgapi.util import find_usb_serial_devices
class BGAPIDeviceMonitor:
"""
Monitor BGAPI device availability and health.
"""
def __init__(self, vendor_id=0x2458, product_id=0x0001):
self.vendor_id = vendor_id
self.product_id = product_id
self.monitoring = False
self.last_seen_devices = set()
def start_monitoring(self, callback=None):
"""
Start monitoring device availability.
Args:
callback: Function called on device changes: callback(added, removed)
"""
self.monitoring = True
def monitor_loop():
while self.monitoring:
current_devices = set()
try:
devices = find_usb_serial_devices(
vendor_id=self.vendor_id,
product_id=self.product_id
)
current_devices = {d.port_name for d in devices}
if current_devices != self.last_seen_devices:
added = current_devices - self.last_seen_devices
removed = self.last_seen_devices - current_devices
if callback:
callback(added, removed)
if added:
print(f"BGAPI devices added: {added}")
if removed:
print(f"BGAPI devices removed: {removed}")
self.last_seen_devices = current_devices
except Exception as e:
print(f"Device monitoring error: {e}")
time.sleep(2) # Check every 2 seconds
threading.Thread(target=monitor_loop, daemon=True).start()
def stop_monitoring(self):
self.monitoring = False
# Usage
def device_change_handler(added, removed):
if removed:
print("BGAPI device disconnected - applications may need restart")
if added:
print("New BGAPI device available")
monitor = BGAPIDeviceMonitor()
monitor.start_monitoring(callback=device_change_handler)
# Run for 30 seconds
time.sleep(30)
monitor.stop_monitoring()Handle common issues in device discovery and USB enumeration.
import pygatt
from pygatt.backends.bgapi.util import find_usb_serial_devices
def safe_device_discovery():
"""
Safely discover USB devices with comprehensive error handling.
"""
try:
devices = find_usb_serial_devices()
return devices
except ImportError as e:
print(f"USB enumeration not available: {e}")
print("Install: pip install pyusb or pip install pyserial")
return []
except PermissionError:
print("Permission denied accessing USB devices")
print("Try running with elevated privileges")
return []
except Exception as e:
print(f"Unexpected error in device discovery: {e}")
return []
# Usage with fallback
devices = safe_device_discovery()
if devices:
print(f"Found {len(devices)} USB serial devices")
else:
print("No devices found or discovery failed")
print("Specify serial port manually:")
print("adapter = pygatt.BGAPIBackend(serial_port='COM9')")Install with Tessl CLI
npx tessl i tessl/pypi-pygatt