[resolved] Issues with Bluetooth in multi-container setup

Hi guys,

I’m working on upgrading databat to support the new multi-container setup (along with some general updates). Unfortunately, I’ve run into issues with using Bluetooth in the new setup. In short, I’m trying to get bluepy to work, but so far I have been unable to do so.

The old Bluetooth documentation states that “Starting from balenaOS 2.9.3+rev1, bluetooth devices are controlled by the host operating system and available for all user containers. Just install the software tools that you require to talk to the bluetooth devices, and start using it.”

To my knowledge, I have annotated things properly, and the container is running in both network_mode: host and privileged: true, which from what I gather is all that should be needed (see [1], [2], and[3]).

When I try to either use blescan (which is just a wrapper), or call it directly from Python, I get the same issue:

$ blescan 
Scanning for devices...
Traceback (most recent call last):
  File "/usr/local/bin/blescan", line 10, in <module>
    sys.exit(main())
  File "/usr/local/lib/python3.7/dist-packages/bluepy/blescan.py", line 122, in main
    devices = scanner.scan(arg.timeout)
  File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 854, in scan
    self.stop()
  File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 803, in stop
    self._mgmtCmd(self._cmd()+"end")
  File "/usr/local/lib/python3.7/dist-packages/bluepy/btle.py", line 312, in _mgmtCmd
    raise BTLEManagementError("Failed to execute management command '%s'" % (cmd), rsp)
bluepy.btle.BTLEManagementError: Failed to execute management command 'scanend' (code: 11, error: Rejected)

Any pointers would be appreciated.

References

[1] docker-compose.yml:

version: '2'
services:
  lab:
    build: ./lab
    privileged: true
    network_mode: host
    labels:
      io.balena.features.dbus: "1"
      io.balena.features.kernel-modules: "1"
      io.balena.features.firmware: "1"

[2] Dockerfile:

FROM balenalib/raspberrypi3-python

ENV DBUS_SYSTEM_BUS_ADDRESS=unix:path=/host/run/dbus/system_bus_socket
ENV UDEV=1

RUN install_packages \
  build-essential \
  bluez \
  python-dbus \
  python-dev \
  libglib2.0-dev

COPY ./requirements.txt /requirements.txt

RUN pip install -r /requirements.txt --no-cache-dir

CMD sleep 3600

[3] requirements.txt:

bluepy==1.3.0

[4] Relevant (WIP) Sonar Pull Request

Hi @vpetersson, that does look like the right configuration and it seems this error can occur in various non-Balena situations on Pi. And in single-container mode, it just worked with docker run?

Hi @MBer - it kinda just “worked” (albeit uber hackish). Hence I was looking forward to remove those hacks.

I did see the GitHub issue you referenced, but unfortunately none of those tricks worked:

# hciconfig hci0 down 
# hciconfig hci0 up
Can't init device hci0: Connection timed out (110)
In [1]: from bluepy.btle import Scanner, DefaultDelegate
   ...: 
   ...: class ScanDelegate(DefaultDelegate):
   ...:     def __init__(self):
   ...:         DefaultDelegate.__init__(self)
   ...: 
   ...:     def handleDiscovery(self, dev, isNewDev, isNewData):
   ...:         if isNewDev:
   ...:             print "Discovered device", dev.addr
   ...:         elif isNewData:
   ...:             print "Received new data from", dev.addr
   ...: 
   ...: scanner = Scanner().withDelegate(ScanDelegate())
   ...: 

In [2]: devices = scanner.scan(10.0)
---------------------------------------------------------------------------
BTLEManagementError                       Traceback (most recent call last)
<ipython-input-2-4e8b06917a91> in <module>()
----> 1 devices = scanner.scan(10.0)

/usr/local/lib/python2.7/site-packages/bluepy/btle.pyc in scan(self, timeout, passive)
    852         self.start(passive=passive)
    853         self.process(timeout)
--> 854         self.stop()
    855         return self.getDevices()
    856 

/usr/local/lib/python2.7/site-packages/bluepy/btle.pyc in stop(self)
    801 
    802     def stop(self):
--> 803         self._mgmtCmd(self._cmd()+"end")
    804         self._stopHelper()
    805 

/usr/local/lib/python2.7/site-packages/bluepy/btle.pyc in _mgmtCmd(self, cmd)
    310         if rsp['code'][0] != 'success':
    311             self._stopHelper()
--> 312             raise BTLEManagementError("Failed to execute management command '%s'" % (cmd), rsp)
    313 
    314     @staticmethod

BTLEManagementError: Failed to execute management command 'scanend' (code: 11, error: Rejected)

In [3]: devices = scanner.scan(10.0, passive=True)
---------------------------------------------------------------------------
BTLEManagementError                       Traceback (most recent call last)
<ipython-input-3-e48dbe58d41b> in <module>()
----> 1 devices = scanner.scan(10.0, passive=True)

/usr/local/lib/python2.7/site-packages/bluepy/btle.pyc in scan(self, timeout, passive)
    852         self.start(passive=passive)
    853         self.process(timeout)
--> 854         self.stop()
    855         return self.getDevices()
    856 

/usr/local/lib/python2.7/site-packages/bluepy/btle.pyc in stop(self)
    801 
    802     def stop(self):
--> 803         self._mgmtCmd(self._cmd()+"end")
    804         self._stopHelper()
    805 

/usr/local/lib/python2.7/site-packages/bluepy/btle.pyc in _mgmtCmd(self, cmd)
    310         if rsp['code'][0] != 'success':
    311             self._stopHelper()
--> 312             raise BTLEManagementError("Failed to execute management command '%s'" % (cmd), rsp)
    313 
    314     @staticmethod

BTLEManagementError: Failed to execute management command 'pasvend'

I have not validated this on regular Raspbian with just a simple docker run, but since I need it to run in Balena (for OTA), I still need to crack this nut.

Just an update here:

I’ve added in the udev-rules and the bluetooth agent and hooked this up in the start script as follows:

[...]
    # Set the discoverable timeout here
    dbus-send --system --dest=org.bluez --print-reply /org/bluez/hci0 org.freedesktop.DBus.Properties.Set string:'org.bluez.Adapter1' string:'DiscoverableTimeout' variant:uint32:0 > /dev/null

    printf "Restarting bluetooth service\n"
    service bluetooth restart > /dev/null
    sleep 2

    # Redirect stdout to null, because it prints the old BT device name, which
    # can be confusing and it also hides those commands from the logs as well.
    printf "discoverable on\npairable on\nexit\n" | bluetoothctl > /dev/null

    # Start bluetooth and audio agent
    /usr/src/bluetooth-agent &
[...]

Unfortunately neither of this made a different with blescan.

Hi there, have you looked at https://github.com/balenalabs/balena-sound? What I would suggest doing is to start simple, get a minimal docker-compose + a single service to work, and then start adding features on top of it. Maybe you can try with a stripped-down version of balena-sound as the base and you modify it so it works for databat? Let us know if that helps and if we can assist in any other way.

Thanks, @sradevski. Actually, Balena-sound set me on a wild goose chase. As it turns out, it was a lot easier.

None of that udev stuff was needed. All that really was needed was echo "power on" | bluetoothctl.

I’m glad that you found out what the issue was :slight_smile: Have a nice day!