Skip to main content

BluePy BLE Guide for AutoPi Edge devices

Introduction#

AutoPi Core relies on BluePy and Bluez packages built into the Linux core on the device.

Prerequisites#

  • AutoPi TMU CM4 or AutoPi CAN-FD Pro device

Installation and Setup#

  1. Enable bluetooth from Advanced settings: Enable bluetoth

Using the built-in bluetooth extention#

It is possible to use the bluetooth.scan command to remote scanning for bluetooth device using the built in cloud terminal.

Custom software for basic BluePy usage#

A great example of using the AutoPi edge devices full functionality, is teh usage of creating custom services. Using this extendabilty of the devices you utilize the full functionality of the bluepy library on the device.

Scanning for Devices - Custom Code example#

from bluepy.btle import Scanner, DefaultDelegate
class ScanDelegate(DefaultDelegate):    def __init__(self):        DefaultDelegate.__init__(self)
    def handleDiscovery(self, dev, isNewDev, isNewData):        if isNewDev:            print(f"Discovered device {dev.addr}")        elif isNewData:            print(f"Received new data from {dev.addr}")
# Initialize scanner objectscanner = Scanner().withDelegate(ScanDelegate())
# Scan for devices (timeout in seconds)devices = scanner.scan(10.0)
# Print discovered devicesfor dev in devices:    print(f"Device {dev.addr} ({dev.addrType}), RSSI={dev.rssi} dB")    for (adtype, desc, value) in dev.getScanData():        print(f"  {desc}: {value}")

Connecting to a Device - Custom Code example#

from bluepy.btle import Peripheral, UUIDimport time
try:    # Connect to device    device = Peripheral("XX:XX:XX:XX:XX:XX")  # Replace with your device's address        # Get all services    services = device.getServices()        for service in services:        print(f"Service UUID: {service.uuid}")                # Get characteristics for this service        characteristics = service.getCharacteristics()                for char in characteristics:            print(f"  Characteristic UUID: {char.uuid}")            # Check if readable            if char.supportsRead():                print(f"    Value: {char.read()}")                except Exception as e:    print(f"Error: {str(e)}")finally:    device.disconnect()

Reading and Writing Characteristics - Custom Code example#

from bluepy.btle import Peripheral, UUID
class BLEDevice:    def __init__(self, address):        self.address = address        self.device = None        def connect(self):        self.device = Peripheral(self.address)            def read_characteristic(self, service_uuid, char_uuid):        service = self.device.getServiceByUUID(UUID(service_uuid))        char = service.getCharacteristics(UUID(char_uuid))[0]        return char.read()            def write_characteristic(self, service_uuid, char_uuid, data):        service = self.device.getServiceByUUID(UUID(service_uuid))        char = service.getCharacteristics(UUID(char_uuid))[0]        char.write(data)            def disconnect(self):        if self.device:            self.device.disconnect()
# Example usageif __name__ == "__main__":    device = BLEDevice("XX:XX:XX:XX:XX:XX")    try:        device.connect()        # Example UUIDs - replace with your device's UUIDs        service_uuid = "1800"        char_uuid = "2a00"                # Read value        value = device.read_characteristic(service_uuid, char_uuid)        print(f"Read value: {value}")                # Write value        device.write_characteristic(service_uuid, char_uuid, bytes([0x01]))    finally:        device.disconnect()

Handling Notifications - Custom Code example#

from bluepy.btle import DefaultDelegate, Peripheralimport time
class NotifyDelegate(DefaultDelegate):    def __init__(self):        DefaultDelegate.__init__(self)
    def handleNotification(self, cHandle, data):        print(f"Notification from handle {cHandle}: {data}")
class BLENotifyDevice:    def __init__(self, address):        self.device = Peripheral(address)        self.device.setDelegate(NotifyDelegate())        def enable_notifications(self, service_uuid, char_uuid):        service = self.device.getServiceByUUID(UUID(service_uuid))        char = service.getCharacteristics(UUID(char_uuid))[0]                # Enable notifications by writing to the CCCD        notify_handle = char.getHandle() + 1        self.device.writeCharacteristic(notify_handle, b"\x01\x00")        def wait_for_notifications(self, timeout=1.0):        self.device.waitForNotifications(timeout)        def disconnect(self):        self.device.disconnect()
# Example usageif __name__ == "__main__":    device = BLENotifyDevice("XX:XX:XX:XX:XX:XX")    try:        # Enable notifications for a characteristic        device.enable_notifications("service_uuid", "char_uuid")                # Wait for notifications        while True:            if device.wait_for_notifications(1.0):                continue            print("Waiting...")    finally:        device.disconnect()

Error Handling - Custom Code example#

from bluepy.btle import Peripheral, BTLEDisconnectError, BTLEGattError
class BLEDeviceManager:    def __init__(self, address):        self.address = address        self.device = None        self.max_retries = 3            def connect_with_retry(self):        for attempt in range(self.max_retries):            try:                self.device = Peripheral(self.address)                print("Connected successfully")                return True            except BTLEDisconnectError:                print(f"Connection failed, attempt {attempt + 1} of {self.max_retries}")                time.sleep(1)        return False        def safe_read_characteristic(self, service_uuid, char_uuid):        try:            service = self.device.getServiceByUUID(UUID(service_uuid))            char = service.getCharacteristics(UUID(char_uuid))[0]            return char.read()        except BTLEGattError as e:            print(f"GATT error: {str(e)}")        except BTLEDisconnectError:            print("Device disconnected")            self.connect_with_retry()        return None

Complete Application - Custom Code example#

from bluepy.btle import Scanner, Peripheral, DefaultDelegate, BTLEDisconnectErrorimport timeimport logging
logging.basicConfig(level=logging.INFO)logger = logging.getLogger(__name__)
class BLEDeviceManager:    def __init__(self, target_name):        self.target_name = target_name        self.device = None        self.target_address = None            def scan_for_device(self, timeout=10):        scanner = Scanner()        devices = scanner.scan(timeout)                for dev in devices:            for (adtype, desc, value) in dev.getScanData():                if desc == "Complete Local Name" and value == self.target_name:                    self.target_address = dev.addr                    logger.info(f"Found device: {self.target_address}")                    return True        return False        def connect(self):        if not self.target_address:            raise ValueError("No device address available")                    try:            self.device = Peripheral(self.target_address)            logger.info("Connected successfully")            return True        except BTLEDisconnectError as e:            logger.error(f"Connection failed: {str(e)}")            return False                def discover_services(self):        services = self.device.getServices()        for service in services:            logger.info(f"Service: {service.uuid}")            chars = service.getCharacteristics()            for char in chars:                logger.info(f"  Characteristic: {char.uuid}")                    def disconnect(self):        if self.device:            self.device.disconnect()            logger.info("Disconnected")
if __name__ == "__main__":    manager = BLEDeviceManager("MyDevice")  # Replace with your device name        try:        if manager.scan_for_device():            if manager.connect():                manager.discover_services()                # Add your device-specific operations here                time.sleep(5)  # Keep connection alive for 5 seconds    finally:        manager.disconnect()

This example provides a complete application structure that you can adapt for your specific needs.

Further Resources#

  1. BluePy Documentation