今まではRaspberry PiをBLEのCentralとして他のデバイスへの接続などを試していましたが、今回はPeripheralとしてAdvertisementを送信してみました。
PythonでAdvertisementを送信している例があったので下記サイトを参考にさせてもらいました。
また、BLEについての下記サイトも参考にさせてもらいました。
インタフェースの確認と設定
Advertisementを送信するには、 org.bluez.LEAdvertisingManager1
の RegisterAdvertisement()
メソッドを使うようなので、まずはインタフェースを確認してみます。
irb(main):001:0> require 'dbus' irb(main):002:0> bus = DBus::SystemBus.instance irb(main):003:0> bluez = bus.service('org.bluez') irb(main):004:0> adapter = bluez.object('/org/bluez/hci0') irb(main):005:0> adapter.introspect 〜〜〜ここまでのアウトプットは省略〜〜〜 irb(main):006:0> adapter.interfaces => ["org.freedesktop.DBus.Introspectable", "org.bluez.Adapter1", "org.freedesktop.DBus.Properties", "org.bluez.GattManager1", "org.bluez.Media1", "org.bluez.NetworkServer1"]
該当のインタフェースが存在していない様子。試しに bluetoothctl
でも見てみます。
[bluetooth]# advertise on LEAdvertisingManager not found
やはりインタフェースがみつからないようです。
BlueZのドキュメントを確認してみます。
advertising-api.txt\doc - bluez.git - Bluetooth protocol stack for Linux
Service org.bluez
Interface org.bluez.LEAdvertisingManager1 [Experimental]
Object path /org/bluez/{hci0,hci1,…}
org.bluez.LEAdvertisingManager1
は Experimental となっているようです。
BlueZのインストール時の内容を確認してみましたが、 --enable-experimental
オプションは付けてビルドしてました。
bluetoothd
のプロセスを確認してみます。
pi@raspberrypi:~ $ ps aux | grep bluetoothd root 658 0.0 0.3 4780 3280 ? Ss 22:23 0:00 /usr/local/libexec/bluetooth/bluetoothd pi 1122 0.0 0.2 4276 2008 pts/3 S+ 22:54 0:00 grep --color=auto bluetoothd
下記記事を参照したところ、 --experimental
オプションを付けて bluetoothd を起動する必要があるようです。
/etc/systemd/system/bluetooth.target.wants/bluetooth.service
を下記のように編集します。
ExecStart=/usr/local/libexec/bluetooth/bluetoothd ↓ ExecStart=/usr/local/libexec/bluetooth/bluetoothd --experimental
編集後にRaspberry Piを再起動して、 bluetoothd
を再確認します。
pi@raspberrypi:~ $ ps aux | grep bluetoothd root 717 0.0 0.3 4780 3248 ? Ss 23:05 0:00 /usr/local/libexec/bluetooth/bluetoothd --experimental pi 910 0.0 0.1 4276 1812 pts/1 S+ 23:09 0:00 grep --color=auto bluetoothd
--experimental
オプション付きで bluetoothd
が起動しました。 bluetoothctl
で確認してみます。
[bluetooth]# advertise on Advertising object registered [bluetooth]# advertise off Advertising object unregistered Agent unregistered
bluetoothctl
でも advertise
コマンドが使えるようになりました。Rubyからも確認してみます
irb(main):006:0> adapter.interfaces => ["org.freedesktop.DBus.Introspectable", "org.bluez.Adapter1", "org.freedesktop.DBus.Properties", "org.bluez.GattManager1", "org.bluez.Media1", "org.bluez.NetworkServer1", "org.bluez.LEAdvertisingManager1"]
org.bluez.LEAdvertisingManager1
インタフェースが追加されました。
Advertisementの送信(bluetoothctl)
bluetoothctl
でPeripheralとしてAdvertisementを送信してみます。
pi@raspberrypi:~ $ sudo bluetoothctl [bluetooth]# advertise peripheral Advertising object registered
上記実行時のHCIの動作を hcidump
で確認すると下記のようになりました。
pi@raspberrypi:~ $ sudo hcidump -i hci0 HCI sniffer - Bluetooth packet analyzer ver 5.23 device: hci0 snap_len: 1500 filter: 0xffffffff < HCI Command: LE Set Advertising Parameters (0x08|0x0006) plen 15 min 1280.000ms, max 1280.000ms type 0x00 (ADV_IND - Connectable undirected advertising) ownbdaddr 0x00 (Public) directbdaddr 0x00 (Public) 00:00:00:00:00:00 channelmap 0x07 filterpolicy 0x00 (Allow scan from any, connection from any) > HCI Event: Command Complete (0x0e) plen 4 LE Set Advertising Parameters (0x08|0x0006) ncmd 1 status 0x00 < HCI Command: LE Set Advertise Enable (0x08|0x000a) plen 1 > HCI Event: Command Complete (0x0e) plen 4 LE Set Advertise Enable (0x08|0x000a) ncmd 1 status 0x00
PeripheralとしてAdvertisementを送信しているので、 ADV_IND - Connectable undirected advertising
となっており、他のデバイスからの接続が可能なタイプのAdvertisementになっていることがわかります。
ではLightBlueから接続してみます。
デバイスの一覧に raspberrypi
が表示され、タップして接続することができました。
次にBroadcastで送信してみます。
[bluetooth]# advertise broadcast Advertising object registered
hcidump
での出力は下記の通り。
< HCI Command: LE Set Advertising Data (0x08|0x0008) plen 32 > HCI Event: Command Complete (0x0e) plen 4 LE Set Advertising Data (0x08|0x0008) ncmd 1 status 0x00 < HCI Command: LE Set Random Address (0x08|0x0005) plen 6 bdaddr 32:DC:0C:A9:69:2B > HCI Event: Command Complete (0x0e) plen 4 LE Set Random Address (0x08|0x0005) ncmd 1 status 0x00 < HCI Command: LE Set Advertising Parameters (0x08|0x0006) plen 15 min 1280.000ms, max 1280.000ms type 0x03 (ADV_NONCONN_IND - Non connectable undirected advertising) ownbdaddr 0x01 (Random) directbdaddr 0x00 (Public) 00:00:00:00:00:00 channelmap 0x07 filterpolicy 0x00 (Allow scan from any, connection from any) > HCI Event: Command Complete (0x0e) plen 4 LE Set Advertising Parameters (0x08|0x0006) ncmd 1 status 0x00 < HCI Command: LE Set Advertise Enable (0x08|0x000a) plen 1 > HCI Event: Command Complete (0x0e) plen 4 LE Set Advertise Enable (0x08|0x000a) ncmd 1 status 0x00
今度は ADV_NONCONN_IND - Non connectable undirected advertising
となっており、他のデバイスからの接続はできない(Advertisementパケットの参照だけできる)タイプのAdvertisementになっていることがわかります。
とりあえず bluetoothctl
からAdvertisementを送信して他のデバイスから検知することができましたが、Rubyから送信することにはかなり調べたもののまだ成功していないので、今後実現していきたいと思います。