adafruit / Adafruit_CircuitPython_BLE

Bluetooth Low Energy (BLE) library for CircuitPython
MIT License
127 stars 58 forks source link

How to register to be notify of changes in a remote BLE characteristics? #138

Closed ChrisDinhNZ closed 3 years ago

ChrisDinhNZ commented 3 years ago

Apologies if this is not the right channel for this.

I have a BLE peripheral device with a single service and a single characteristic. The characteristic holds an 8-bit uint which is set to 1 when the switch is on, 0 when the switch is off. The characteristic supports READ and NOTIFY.

Using nRF Connect I can see the NOTIFY part is working as the value is being updated as the state of the switch changes.

But what I really want to do is use a Raspberry Pi as the central device using Adafruit CircuitPython BLE.

Following the examples in this repository, I created a simple program below:

observe_ble_switch.py

#!/usr/bin/env python3

import asyncio
import time
from switch_service import SwitchService

from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import Advertisement

ble = BLERadio()

async def main():
    device_name = "My Arduino"
    device_found = False
    ble_device_connection = None

    print("Scanning for %r" % device_name)

    while not device_found:
        print("...")

        for adv in ble.start_scan(Advertisement, timeout=5):
            name = adv.complete_name
            if not name:
                continue

            if name.strip("\x00") == device_name:
                ble.stop_scan()
                device_found = True
                print("%r found!" % name)
                ble_device_connection = ble.connect(adv)
                break

    if ble_device_connection and ble_device_connection.connected:
        print("Connected to %r!" % name)

        if SwitchService in ble_device_connection:
            print("switch service available")
            switch_service = ble_device_connection[SwitchService]

            while ble_device_connection.connected:
                print("status %r" % switch_service.read_status())
                time.sleep(0.3)
        else:
            print("switch service not available")

if __name__ == "__main__":
    asyncio.run(main())

switch_service.py

from adafruit_ble.uuid import VendorUUID
from adafruit_ble import Service
from adafruit_ble.characteristics.int import Uint8Characteristic

class SwitchService(Service):
    """
    """

    uuid = VendorUUID('8158b2fd-94e4-4ff5-a99d-9a7980e998d7')

    switch_characteristic = Uint8Characteristic(
        uuid=VendorUUID("8158b2fe-94e4-4ff5-a99d-9a7980e998d7")
    )

    def __init__(self, service=None):
        super().__init__(service=service)
        self.status = self.switch_characteristic

    def read_status(self):
        return self.status

The problem I am having is that read_status() will always return whatever the state of the BLE switch is when the program first ran. It doesn't get notified of subsequent states changes of the BLE switch. My thought was that what I am missing is registering with the BLE switch to be notified of changes. I am struggling to find examples or reference to do this.

Thanks.

tannewt commented 3 years ago

The Adafruit forum: https://forums.adafruit.com/viewforum.php?f=60 or Discord chat are better places to get help: https://adafru.it/discord