CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-pygatt

Python Bluetooth LE (Low Energy) and GATT Library providing cross-platform BLE operations with multiple backends

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities

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.

Capabilities

UUID Conversion

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))

USB Device Discovery

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}")

USB Device Information

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_id

Usage 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)

BGAPI Hardware Constants

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
)

Platform-Specific Utilities

Handle cross-platform differences in USB device enumeration and serial port naming.

Windows COM Port Discovery

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")

Linux/macOS Device Path Discovery

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")

Automated Device Selection

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")

Device Health Monitoring

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()

Error Handling for Utilities

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

docs

backend-management.md

bgapi-backend.md

device-operations.md

error-handling.md

gatttool-backend.md

index.md

utilities.md

tile.json