Raspberry Pi 3でBluetoothデバイス接続

 Raspberry Pi 3 からは標準でBluetoothモジュールが搭載されているということで、他のデバイスとの接続を試してみました。

BlueZインストール

 BlueZはオープンソースのBluetoothプロトコルスタックで、Linux上でBluetooth, BLEを扱う場合には標準的に使われているということなので、インストールします。

 まずはソースをダウンロードして解凍します。

pi@raspberrypi:~/tmp $ wget http://www.kernel.org/pub/linux/bluetooth/bluez-5.45.tar.xz
--2017-05-27 10:23:48--  http://www.kernel.org/pub/linux/bluetooth/bluez-5.45.tar.xz
Resolving www.kernel.org (www.kernel.org)... 147.75.110.187
Connecting to www.kernel.org (www.kernel.org)|147.75.110.187|:80... connected.
HTTP request sent, awaiting response... 301 Moved Permanently
Location: https://www.kernel.org/pub/linux/bluetooth/bluez-5.45.tar.xz [following]
--2017-05-27 10:23:48--  https://www.kernel.org/pub/linux/bluetooth/bluez-5.45.tar.xz
Connecting to www.kernel.org (www.kernel.org)|147.75.110.187|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1672404 (1.6M) [application/x-xz]
Saving to: ‘bluez-5.45.tar.xz’

bluez-5.45.tar.xz                                           100%[===========================================================================================================================================>]   1.59M  2.56MB/s   in 0.6s   

2017-05-27 10:23:49 (2.56 MB/s) - ‘bluez-5.45.tar.xz’ saved [1672404/1672404]

pi@raspberrypi:~/tmp $ xz -dv bluez-5.45.tar.xz 
bluez-5.45.tar.xz (1/1)
  100 %      1,633.2 KiB / 14.4 MiB = 0.111                                    
pi@raspberrypi:~/tmp $ tar -xf bluez-5.45.tar 
pi@raspberrypi:~/tmp $ cd bluez-5.45/

 ビルドに必要なライブラリをインストールします。configureしながら確認した結果、下記ライブラリをインストールしました。

pi@raspberrypi:~/tmp/bluez-5.45 $ sudo apt-get install -y libglib2.0-dev
pi@raspberrypi:~/tmp/bluez-5.45 $ sudo apt-get install -y libdbus-1-dev
pi@raspberrypi:~/tmp/bluez-5.45 $ sudo apt-get install -y libudev-dev
pi@raspberrypi:~/tmp/bluez-5.45 $ sudo apt-get install -y libical-dev

 そして下記コマンドでビルド、インストールします。

pi@raspberrypi:~/tmp/bluez-5.45 $ ./configure --enable-experimental
pi@raspberrypi:~/tmp/bluez-5.45 $ make
pi@raspberrypi:~/tmp/bluez-5.45 $ sudo make install

 無事にインストールできたらひとまずBluetoothデバイスをスキャンしてみます。hcitoolというコマンドを使って、Bluetoothデバイスを検索する場合は scan、BLEデバイスを検索する場合は lescan をオプションとして渡します。

pi@raspberrypi:~ $ hcitool
hcitool - HCI Tool ver 5.23
pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ sudo hcitool lescan
LE Scan ...
74:DE:1A:E6:4E:4F (unknown)
34:36:3B:C7:FB:E9 (unknown)
34:36:3B:C7:FB:E9 (unknown)
74:DE:1A:E6:4E:4F (unknown)
F9:D8:AA:9A:CF:96 (unknown)
F9:D8:AA:9A:CF:96 Charge HR
pi@raspberrypi:~ $ 
pi@raspberrypi:~ $ sudo hcitool scan                                                                                                                                                                                                          
Scanning ...
        FC:E9:98:21:23:B7       Akanuma_Hiroaki_iPhone
pi@raspberrypi:~ $ 

 とりあえずデバイスの検知は行えているようです。

Bluetooth関連の各種ツール

 下記サイトを参考に、各種ツールのインストールやバージョンの確認をしてみました。

Raspberry Pi 3に Bluetooth BlueZ Version 5.42 BLE (ラズパイで Bluetooth 4.0の BLE gatt通信を行なう TIの SensorTagや iBeacon実験など)

 BlueZをインストールすると対話型の設定ツールとしてbluetoothctlが使えるようになっていますので、バージョンを確認してみます。

pi@raspberrypi:~/tmp/bluez-5.45 $ bluetoothctl 
[NEW] Controller B8:27:EB:19:76:07 raspberrypi [default]
[bluetooth]# version
Version 5.23
[bluetooth]# quit
[DEL] Controller B8:27:EB:19:76:07 raspberrypi [default]

 Bluetoothデバイス間のトラフィックのキャプチャツールとして、bluez-hcidumpをインストールしておきます。

pi@raspberrypi:~/tmp/bluez-5.45 $ sudo apt-get install bluez-hcidump
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages were automatically installed and are no longer required:
  libbison-dev libsigsegv2 m4
Use 'apt-get autoremove' to remove them.
The following NEW packages will be installed:
  bluez-hcidump
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 157 kB of archives.
After this operation, 490 kB of additional disk space will be used.
Get:1 http://archive.raspberrypi.org/debian/ jessie/main bluez-hcidump armhf 5.23-2+rpi2 [157 kB]
Fetched 157 kB in 1s (91.8 kB/s)                          
Selecting previously unselected package bluez-hcidump.
(Reading database ... 36730 files and directories currently installed.)
Preparing to unpack .../bluez-hcidump_5.23-2+rpi2_armhf.deb ...
Unpacking bluez-hcidump (5.23-2+rpi2) ...
Processing triggers for man-db (2.7.0.2-5) ...
Setting up bluez-hcidump (5.23-2+rpi2) ...
pi@raspberrypi:~/tmp/bluez-5.45 $ 
pi@raspberrypi:~/tmp/bluez-5.45 $ hcidump
HCI sniffer - Bluetooth packet analyzer ver 5.23
device: hci0 snap_len: 1500 filter: 0xffffffff

 hciconfigではBluetoothインタフェースの状態が確認できます。

pi@raspberrypi:~/tmp/bluez-5.45 $ hciconfig
hci0:   Type: BR/EDR  Bus: UART
        BD Address: B8:27:EB:19:76:07  ACL MTU: 1021:8  SCO MTU: 64:1
        UP RUNNING 
        RX bytes:710 acl:0 sco:0 events:41 errors:0
        TX bytes:1496 acl:0 sco:0 commands:41 errors:0

iBeacon化してiPhoneから検知

 BlueZを使ってiBeacon化するためのツールとして下記が公開されているので、Raspberry Pi上で動かしてiPhoneから検知してみます。

github.com

 まずはソースをダウンロードして解凍します。

pi@raspberrypi:~/tmp $ git clone https://github.com/carsonmcdonald/bluez-ibeacon.git
Cloning into 'bluez-ibeacon'...
remote: Counting objects: 77, done.
remote: Total 77 (delta 0), reused 0 (delta 0), pack-reused 77
Unpacking objects: 100% (77/77), done.
Checking connectivity... done.
pi@raspberrypi:~/tmp $ 
pi@raspberrypi:~/tmp $ cd bluez-ibeacon/bluez-beacon/

 ビルドに必要なライブラリをインストール。

pi@raspberrypi:~/tmp/bluez-ibeacon/bluez-beacon $ sudo apt-get -y install libbluetooth-dev

 そしてビルドします。

pi@raspberrypi:~/tmp/bluez-ibeacon/bluez-beacon $ make
cc -g -o ibeacon ibeacon.c -lbluetooth

 無事ビルドできたら起動してみます。オプションはとりあえずサンプルと同じにしています。

pi@raspberrypi:~/tmp/bluez-ibeacon/bluez-beacon $ sudo ./ibeacon 200 e2c56db5dffb48d2b060d0f5a71096e0 1 1 -29                                                                                                                                 
Hit ctrl-c to stop advertising

 これでRaspberry Pi側はiBeaconとして動作しているはずなので、iPhoneに下記アプリをインストールしてiBeaconを検知してみます。

Locate Beacon

Locate Beacon

  • Radius Networks
  • Utilities
  • Free

f:id:akanuma-hiroaki:20170528203456p:plain:w300f:id:akanuma-hiroaki:20170528203505p:plain:w300

 距離の表示はだいぶずれてますが、ひとまず検知はされて、RSSIの情報も表示されました。

Bluetoothデバイスとペアリング&接続

 自宅にBluetooth接続のキーボードがあったのでペアリング&接続してみます。まずは bluetoothctl を起動して、デフォルトagentを設定します。

pi@raspberrypi:~ $ sudo bluetoothctl --agent=DisplayYesNo
[NEW] Controller B8:27:EB:19:76:07 raspberrypi [default]
[NEW] Device FC:E9:98:21:23:B7 Akanuma_Hiroaki_iPhone
Agent registered
[Akanuma_Hiroaki_iPhone]# default-agent
Default agent request successful

 続いてBluetoothデバイスのスキャンを開始します。Bluetooth 3.0 Keyboard が検知されたらスキャンを停止します。

[Akanuma_Hiroaki_iPhone]# scan on
Discovery started
[CHG] Controller B8:27:EB:19:76:07 Discovering: yes
[NEW] Device 34:36:3B:C7:FB:E9 34-36-3B-C7-FB-E9
[NEW] Device 20:16:06:23:98:85 20-16-06-23-98-85
[CHG] Device 20:16:06:23:98:85 LegacyPairing: no
[CHG] Device 20:16:06:23:98:85 Name: Bluetooth 3.0 Keyboard
[CHG] Device 20:16:06:23:98:85 Alias: Bluetooth 3.0 Keyboard
[CHG] Device 20:16:06:23:98:85 LegacyPairing: yes
[CHG] Device 34:36:3B:C7:FB:E9 RSSI: -65
[Akanuma_Hiroaki_iPhone]# scan off
[CHG] Device 20:16:06:23:98:85 RSSI is nil
[CHG] Device 34:36:3B:C7:FB:E9 RSSI is nil
Discovery stopped
[CHG] Controller B8:27:EB:19:76:07 Discovering: no

 対象のデバイスのMACアドレスを指定してペアリングします。

[Akanuma_Hiroaki_iPhone]# pair 20:16:06:23:98:85
Attempting to pair with 20:16:06:23:98:85
[CHG] Device 20:16:06:23:98:85 Connected: yes
[CHG] Device 20:16:06:23:98:85 Modalias: usb:v05ACp023Cd0102
[CHG] Device 20:16:06:23:98:85 UUIDs: 00001124-0000-1000-8000-00805f9b34fb
[CHG] Device 20:16:06:23:98:85 UUIDs: 00001200-0000-1000-8000-00805f9b34fb
[CHG] Device 20:16:06:23:98:85 ServicesResolved: yes
[CHG] Device 20:16:06:23:98:85 Paired: yes
Pairing successful
[CHG] Device 20:16:06:23:98:85 ServicesResolved: no
[CHG] Device 20:16:06:23:98:85 Connected: no
[Akanuma_Hiroaki_iPhone]# connect 20:16:06:23:98:85
Attempting to connect to 20:16:06:23:98:85
[CHG] Device 20:16:06:23:98:85 Connected: yes
Connection successful
[CHG] Device 20:16:06:23:98:85 ServicesResolved: yes
[DEL] Device 34:36:3B:C7:FB:E9 34-36-3B-C7-FB-E9
[DEL] Device 74:DE:1A:E6:4E:4F 74-DE-1A-E6-4E-4F
[CHG] Device 20:16:06:23:98:85 ServicesResolved: no
[CHG] Device 20:16:06:23:98:85 Connected: no

 そして接続してみます。

[bluetooth]# connect 20:16:06:23:98:85
Attempting to connect to 20:16:06:23:98:85
Failed to connect: org.bluez.Error.Failed
[bluetooth]# connect 20:16:06:23:98:85
Attempting to connect to 20:16:06:23:98:85
[CHG] Device 20:16:06:23:98:85 Connected: yes
Connection successful
[CHG] Device 20:16:06:23:98:85 ServicesResolved: yes

 無事接続できたようです。正しく通信できているか確認するために、evtest というインプットイベントのモニタツールを使ってみます。

evtest
~whot/evtest - Simple tool for input event debugging.

 インストールした後で下記のように実行します。evtestを起動した状態でキーボード入力してみたところ、下記のように検知され、正しく通信できていることが確認できました。

pi@raspberrypi:~/tmp/evtest $ evtest
No device specified, trying to scan all of /dev/input/event*
Not running as root, no devices may be available.
Available devices:
/dev/input/event0:      FC:E9:98:21:23:B7
/dev/input/event1:      Bluetooth 3.0 Keyboard
Select the device event number [0-1]: 1
Input driver version is 1.0.1
Input device ID: bus 0x5 vendor 0x5ac product 0x23c version 0x102
Input device name: "Bluetooth 3.0 Keyboard"
Supported events:
  Event type 0 (EV_SYN)
  Event type 1 (EV_KEY)
    Event code 1 (KEY_ESC)
    Event code 2 (KEY_1)
    Event code 3 (KEY_2)
    Event code 4 (KEY_3)
    Event code 5 (KEY_4)
    Event code 6 (KEY_5)
    Event code 7 (KEY_6)
    Event code 8 (KEY_7)
    Event code 9 (KEY_8)
    Event code 10 (KEY_9)
    Event code 11 (KEY_0)
    Event code 12 (KEY_MINUS)
    Event code 13 (KEY_EQUAL)
    Event code 14 (KEY_BACKSPACE)
    Event code 15 (KEY_TAB)
〜〜〜中略〜〜〜
    Event code 217 (KEY_SEARCH)
    Event code 240 (KEY_UNKNOWN)
    Event code 374 (KEY_KEYBOARD)
    Event code 581 (?)
  Event type 3 (EV_ABS)
    Event code 40 (ABS_MISC)
      Value      0
      Min        0
      Max      255
    Event code 41 (?)
      Value      0
      Min        0
      Max        1
    Event code 42 (?)
      Value      0
      Min        0
      Max        1
    Event code 43 (?)
      Value      0
      Min        0
      Max        1
  Event type 4 (EV_MSC)
    Event code 4 (MSC_SCAN)
  Event type 17 (EV_LED)
    Event code 0 (LED_NUML)
    Event code 1 (LED_CAPSL)
    Event code 2 (LED_SCROLLL)
    Event code 3 (LED_COMPOSE)
    Event code 4 (LED_KANA)
  Event type 20 (EV_REP)
Properties:
Testing ... (interrupt to exit)
Event: time 1495901204.274595, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1495901204.274595, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1495901204.274595, -------------- SYN_REPORT ------------
Event: time 1495901204.323288, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70004
Event: time 1495901204.323288, type 1 (EV_KEY), code 30 (KEY_A), value 0
Event: time 1495901204.323288, -------------- SYN_REPORT ------------
Event: time 1495901206.455897, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70005
Event: time 1495901206.455897, type 1 (EV_KEY), code 48 (KEY_B), value 1
Event: time 1495901206.455897, -------------- SYN_REPORT ------------
Event: time 1495901206.568359, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70005
Event: time 1495901206.568359, type 1 (EV_KEY), code 48 (KEY_B), value 0
Event: time 1495901206.568359, -------------- SYN_REPORT ------------
Event: time 1495901208.728378, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006
Event: time 1495901208.728378, type 1 (EV_KEY), code 46 (KEY_C), value 1
Event: time 1495901208.728378, -------------- SYN_REPORT ------------
Event: time 1495901208.818369, type 4 (EV_MSC), code 4 (MSC_SCAN), value 70006
Event: time 1495901208.818369, type 1 (EV_KEY), code 46 (KEY_C), value 0
Event: time 1495901208.818369, -------------- SYN_REPORT ------------

RubyでBluetoothデバイスとペアリング&接続

 Bluetoothデバイスの検知、ペアリング、接続までをRubyでやってみます。RubyからBLEデバイスを操作するための gem として、ruby-bleというのがあるようなのでそちらを使ってみます。

github.com

Documentation for ble (0.1.0)

 Gemfileに下記エントリを追加して、bundle installしておきます。

gem 'ble'

   今回はとりあえずirbで試してみます。irbを起動して'ble'をrequireします。warningメッセージが気になるところですが、今回はスルー。

pi@raspberrypi:~ $ sudo bundle exec irb
irb(main):001:0> require 'ble'
/home/pi/vendor/bundle/ruby/2.4.0/gems/ruby-dbus-0.13.0/lib/dbus/marshall.rb:299: warning: constant ::Fixnum is deprecated
=> true

 BLEアダプタのリストを表示してみます。

irb(main):002:0> BLE::Adapter.list
/home/pi/vendor/bundle/ruby/2.4.0/gems/ruby-dbus-0.13.0/lib/dbus/marshall.rb:299: warning: constant ::Fixnum is deprecated
=> ["hci0"]

 hci0というアダプタが見つかるので、インスタンスを作成します。

irb(main):003:0> adapter = BLE::Adapter.new('hci0')

 Bluetoothデバイスの検知を開始します。目的のBLEデバイスのMACアドレスが検知されたら停止します。

irb(main):008:0* adapter.start_discovery
=> true
irb(main):011:0> adapter.devices
=> ["20:16:06:23:98:85", "34:36:3B:C7:FB:E9", "43:19:24:21:00:5F", "74:DE:1A:E6:4E:4F", "FC:E9:98:21:23:B7"]
irb(main):012:0> adapter.stop_discovery
=> true

 該当のBluetoothデバイスのオブジェクトを取得します。

irb(main):013:0> kb = adapter['20:16:06:23:98:85']

 デバイス名等を確認してみます。

irb(main):015:0* kb.name
=> "Bluetooth 3.0 Keyboard"
irb(main):016:0> kb.alias
=> "Bluetooth 3.0 Keyboard"
irb(main):017:0> kb.address
=> "20:16:06:23:98:85"

 続けてペアリングします。

irb(main):020:0> kb.pair
=> true
irb(main):021:0> kb.is_paired?
=> true

 そして接続してみます。

irb(main):026:0> kb.connect
=> true
irb(main):027:0> kb.is_connected?
=> true

 無事接続できたようです。この状態で evtest を実行すると、 bluetoothctl から接続した時と同じように、キーボードの入力内容が確認できます。

 ここまでだとまだBluetoothクラシックのデバイスと接続したところまでなので、次回以降でBLEデバイスとの通信を試してみたいと思います。