Adafruit Python BluefruitLE が動きませんでした

「gatttool を使って NUS( Nordic UART Service ) とつなぐ実験」
https://qiita.com/nanbuwks/items/7c448837eedf439b8ee9

でやったことを、
Adafruit Python BluefruitLE
でやってみます。

# Adafruit Python BluefruitLE
https://github.com/adafruit/Adafruit_Python_BluefruitLE
は
Linux,Mac OSXで使えるPythonライブラリです。また、Linux では PC / Raspberry Pi 同様に動作します。

今回、Windows を除く限定的なマルチプラットフォームのツールを作る必要があったのでこれを試してみました。

# 余談

同じ名前を冠しているハードウェア

nRF52 Bluefruit LE

という製品もあります。nRF5x を Arduino で動かす系の開発環境では、これ用のものが一番うまくできている感じです。

# 環境

- Raspberry Pi + Raspbian GNU/Linux 9 

明示していませんが、PC 上の Ubuntu Linux 16.04 でも同様でした。

# インストール

ドキュメントを見ると、bluez 5.33が必要らしいです。

```
$ sudo apt-get install bluez
Reading package lists... Done
Building dependency tree       
Reading state information... Done
bluez is already the newest version (5.43-2+rpt2+deb9u2).
0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.

```

5.43が入ってますね。大丈夫かな？
ドキュネントによるとPython2.7用らしいですが、Python3で試してみます。


```
$ sudo pip3 install Adafruit-BluefruitLE
Collecting Adafruit-BluefruitLE
  Downloading https://www.piwheels.org/simple/adafruit-bluefruitle/Adafruit_BluefruitLE-0.9.10-py3-none-any.whl (49kB)
    100% |████████████████████████████████| 51kB 86kB/s 
Collecting future (from Adafruit-BluefruitLE)
  Downloading https://www.piwheels.org/simple/future/future-0.17.1-py3-none-any.whl (488kB)
    100% |████████████████████████████████| 491kB 161kB/s 
Installing collected packages: future, Adafruit-BluefruitLE
Successfully installed Adafruit-BluefruitLE-0.9.10 future-0.17.1
```


サンプルプログラムを取得します

```

 $ wget https://github.com/adafruit/Adafruit_Python_BluefruitLE/archive/master.zip
pi@raspberrypi:~ $ unzip master.zip 
pi@raspberrypi:~ $ cd Adafruit_Python_BluefruitLE-master/
pi@raspberrypi:~/Adafruit_Python_BluefruitLE-master $ ls
Adafruit_BluefruitLE  LICENSE  README.md  examples  setup.py
pi@raspberrypi:~/Adafruit_Python_BluefruitLE-master $ cd examples/
pi@raspberrypi:~/Adafruit_Python_BluefruitLE-master/examples $ ls
device_info.py  list_uarts.py  low_level.py  uart_service.py
```

実行してみます


```

pi@raspberrypi:~/Adafruit_Python_BluefruitLE-master/examples $ python3 uart_service.py 
ERROR:dbus.proxies:Introspect error on :1.3:/: dbus.exceptions.DBusException: org.freedesktop.DBus.Error.AccessDenied: Rejected send message, 2 matched rules; type="method_call", sender=":1.21" (uid=1000 pid=32656 comm="python3 uart_service.py ") interface="org.freedesktop.DBus.Introspectable" member="Introspect" error name="(unset)" requested_reply="0" destination=":1.3" (uid=0 pid=439 comm="/usr/lib/bluetooth/bluetoothd ")
Traceback (most recent call last):
  File "uart_service.py", line 85, in <module>
    ble.run_mainloop_with(main)
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 105, in run_mainloop_with
    raise_(self._exception[1], None, self._exception[2])
  File "/usr/local/lib/python3.5/dist-packages/future/utils/__init__.py", line 416, in raise_
    raise exc
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 120, in _user_thread_main
    self._return_code = target()
  File "uart_service.py", line 20, in main
    ble.clear_cached_data()
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 137, in clear_cached_data
    for device in self.list_devices():
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 170, in list_devices
    return map(BluezDevice, self._get_objects('org.bluez.Device1'))
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 181, in _get_objects
    for opath, interfaces in iteritems(self._bluez.GetManagedObjects()):
  File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 70, in __call__
    return self._proxy_method(*args, **keywords)
  File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 145, in __call__
    **keywords)
  File "/usr/lib/python3/dist-packages/dbus/connection.py", line 651, in call_blocking
    message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.AccessDenied: Rejected send message, 2 matched rules; type="method_call", sender=":1.21" (uid=1000 pid=32656 comm="python3 uart_service.py ") interface="org.freedesktop.DBus.ObjectManager" member="GetManagedObjects" error name="(unset)" requested_reply="0" destination=":1.3" (uid=0 pid=439 comm="/usr/lib/bluetooth/bluetoothd ")
```

エラー出ましたね。 bluetooth 関連は pi ユーザーだと使えないことが多いので、 sudo つけて実行してみます。

```

pi@raspberrypi:~/Adafruit_Python_BluefruitLE-master/examples $ sudo python3 uart_service.py 
Using adapter: raspberrypi
Disconnecting any connected UART devices...
Searching for UART device...
Connecting to device...
Discovering services...
Traceback (most recent call last):
  File "uart_service.py", line 85, in <module>
    ble.run_mainloop_with(main)
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 105, in run_mainloop_with
    raise_(self._exception[1], None, self._exception[2])
  File "/usr/local/lib/python3.5/dist-packages/future/utils/__init__.py", line 416, in raise_
    raise exc
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/provider.py", line 120, in _user_thread_main
    self._return_code = target()
  File "uart_service.py", line 59, in main
    uart = UART(device)
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/services/uart.py", line 50, in __init__
    self._tx = self._uart.find_characteristic(TX_CHAR_UUID)
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/interfaces/gatt.py", line 48, in find_characteristic
    for char in self.list_characteristics():
  File "/usr/local/lib/python3.5/dist-packages/Adafruit_BluefruitLE/bluez_dbus/gatt.py", line 56, in list_characteristics
    paths = self._props.Get(_SERVICE_INTERFACE, 'Characteristics')
  File "/usr/lib/python3/dist-packages/dbus/proxies.py", line 145, in __call__
    **keywords)
  File "/usr/lib/python3/dist-packages/dbus/connection.py", line 651, in call_blocking
    message, timeout)
dbus.exceptions.DBusException: org.freedesktop.DBus.Error.InvalidArgs: No such property 'Characteristics'
```

sudo つけると権限関係のエラーはクリアしたみたいですが、別のエラーが出ています。


BlueZ はディストリビューション付属のものですが、それを削除して ダウンロードした 5.50 版(最新)にしてみたり、Ubuntu の PC でやってみたりしましたが同様でした。

ダウンロードしたものは、
https://github.com/adafruit/Adafruit_Python_BluefruitLE
にあるような手順で行っています。
また、以下のように5.33にしてみたりしましたがうまいくいきませんでした。

```

sudo apt-get update
sudo apt-get -y install libusb-dev libdbus-1-dev libglib2.0-dev libudev-dev libical-dev libreadline-dev
wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.33.tar.gz
tar xvfz bluez-5.33.tar.gz
cd bluez-5.33
./configure --disable-systemd
make
sudo make install
sudo cp ./src/bluetoothd /usr/local/bin/
```

ディストリビューション付属のBlueZを削除すると、Ubuntuでは依存関係にあった unity-control-center も削除され、「システム設定」が出なくなってしまいました。これが原因と思わなかったのでしばらくあれれーということになりました。

RaspberryPiも似たような依存関係がありそうで、入れ替えるのはやめる方向で調べてみました。


ぐぐってみると、悩んでいる人は多そうです。

https://github.com/adafruit/Adafruit_Python_BluefruitLE/issues/23

これによると、BlueZ の 5.38 以降は  D-Bus Object Manager の仕様に準拠したため互換性がなくなっているようです。
ここに BluefruitLE へのパッチも示されてますが、それだけではうまくいきませんでした。

BlueZ の仕様変更に合わせて更に追求すれば動きそうですが、今回 Adafruit Python BluefruitLE を使うモチベーションは Linux と Mac で両対応することでした。この修正で Mac で動作するかどうかの検証に時間がかかりそう（Mac持ってない）ので、 Adafruit Python BluefruitLE を使うのはあきらめ Web-bluetooth を使う方法に乗り換えました。