Page 1 of 1

Reading Multiple Bluetooth Beacons

Posted: Mon Nov 04, 2019 2:30 am
by devnull
Have really been struggling with multiple connections to multiple devices and being able to asynchronously read the data from each beacon and return that data to other code for further processing.

Dealing with a single connection and a single read is pretty simple, but when you have multiple devices to read (with multiple open connections) and need to read multiple values from each device asynchronously it becomes very messy when using a global interrupt.

I guess that everyone will say that uasyncio is probably the way, but having to deal with a single interrupt for all connections is still going to need some workarounds !

And I don't really need for my code to do anything else while waiting for this data, as the data is crucial to the next step !

What is the recommended approach for this ??

Re: Reading Multiple Bluetooth Beacons

Posted: Mon Nov 04, 2019 4:56 am
by jimmo
So your beacons need you to connect to them? They're not just using advertising data?

I think the answer to this is fairly application specific, but the basic idea is that you'd make a Beacon class to track each beacon and route the irq method to the right instance based on address / conn_handle.

Here's a rough sketch of what that might look like?

Code: Select all

class Peripheral:
  def __init__(self, central, addr_type, addr):
    self._central = central
    self._addr_type = addr_type
    self._addr = addr
    self._conn_handle = None
    self._central._connecting_peripherals[(addr_type, addr)] = self
    self._central._ble.connect(addr_type, addr)

  def connected(self):

  def irq(self, event, data):

class Central:
  def __init__(self, ble):
    self._connecting_peripherals = {}
    self._connected_peripherals = {}
    self._ble = ble
    self._ble.irq(handler=self.irq, trigger=0xffff)

  def irq(self, event, data):
    if event == _IRQ_SCAN_RESULT:
      addr_type, addr, connectable, rssi, adv_data = data
      # e.g. create a Peripheral(self, addr_type, addr)
    elif event == _IRQ_SCAN_COMPLETE:
    elif event == _IRQ_PERIPHERAL_CONNECT:
      conn_handle, addr_type, addr = data
      key = (addr_type, addr,)
      if key in self._connecting_peripherals:
        p = self._connecting_peripherals[key]
        p._conn_handle = conn_handle
        del self._connecting_peripherals[key]
        self._connected_peripherals[conn_handle] = p
    else if data[0] in self._connected_peripherals:
        # All other events, data[0] is conn_handle.
        self._connected_peripherals[data[0]].irq(event, data)

Re: Reading Multiple Bluetooth Beacons

Posted: Mon Nov 04, 2019 11:08 pm
by devnull
Thanks Jimmo;

That works really well, I have expanded on it and fixed a couple of typos but it pretty much works out of the box.

But how can I disconnect a peripheral and destroy it's class instance, or allow disconnect & reconnect of an instance ?

Code: Select all

  def connect(self):
    self._central._connecting_peripherals[(self._addr_type, self._addr)] = self
    self._central._ble.gap_connect(self._addr_type, self._addr)      
  def disconnect(self):
I have added these into the peripheral class, disconnect works but I can never reconnect again.

Re: Reading Multiple Bluetooth Beacons

Posted: Mon Nov 04, 2019 11:19 pm
by jimmo
After calling p.irq(), check if the event is "disconnected" and del from the connected dict.