[iBeacon] 1台のMacで複数のiBeacon端末をシュミレートする

2017.03.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

IBeaconは、Bluetoothデバイスが搭載されていれば、作ることができるので、MacやiPhoneをiBeacon端末にすることが可能です。


[iOS 7] [iBeacon] Mac を Beacon 端末にする
[iOS][OS X] Yosemite で Beacon アプリを動作させる
[iBeacon] Mac を iBeacon 端末にする(Swift3編)
iOSデバイスをビーコンとして利用する

しかし、iBeacon対応のアプリを開発するとなると、uuidやmajor,minorの違う、複数のiBeaconで試験したい場面もあると思います。

各所で紹介されている方法では、1つのiBeaconを用意するのに、1台のiPhoneやMacが必要になり、ちょっとコストが高くなります。そこで今回は、1台のMacで複数のiBeaconを作ってみました。

最初に、今回作成したアプリが動作してるようすです。

左のMacで動作しているのは、以前に作成したiBeaconのスキャナーです。
参考:iBeaconのスキャナーを作ってみた
そして、右のMacで動作しているのが、今回作成したアプリです。事前に登録した複数のiBeaconが一覧されており、チェックボックスでON/OFFを切り替えるようになっています。 ONとなった、iBeaconが、左のスキャナーで列挙されているのが分かります。

2 複数のBluetoothデバイスは利用できない

最初、Bluetoothデバイスを複数使用することで、この要求に答えようと考えたのですが、結果的に、複数のBluetoothデバイスの同時利用は、失敗しました。

(1) Linuxの場合

下図は、RasberyPiで2つのBluetoothドングルを使用しているようすです。

001

hciconfigで確認すると、hci0hci1がRUNNINGとなっています。

$ hciconfig
hci1:   Type: BR/EDR  Bus: USB
    BD Address: 00:1B:DC:06:B0:60  ACL MTU: 310:10  SCO MTU: 64:8
    UP RUNNING
    RX bytes:610 acl:0 sco:0 events:36 errors:0
    TX bytes:942 acl:0 sco:0 commands:36 errors:0

hci0:   Type: BR/EDR  Bus: USB
    BD Address: 00:1B:DC:06:88:55  ACL MTU: 310:10  SCO MTU: 64:8
    UP RUNNING
    RX bytes:628 acl:0 sco:0 events:39 errors:0
    TX bytes:1472 acl:0 sco:0 commands:39 errors:0

動作は、LinuxやMacでJavaScriptからBluetoothを利用可能にする有名なbleaconで確認させて頂きました。

https://github.com/sandeepmistry

002

Linux上では、デバイス番号の指定が可能です。 そして、デバイス番号を指定して使用してみましたが、まったく問題ありませんでした。 しかし、複数同時に使用すると安定して動作しませんでした。(私の間違いの可能性もありますので、お気づきの点が有りましたら、お知らせいただければ嬉しいです)

https://github.com/sandeepmistry/bleno/blob/master/lib/hci-socket/hci.jsより

Hci.prototype.init = function() {
  this._socket.on('data', this.onSocketData.bind(this));
  this._socket.on('error', this.onSocketError.bind(this));

  var deviceId = process.env.BLENO_HCI_DEVICE_ID ? parseInt(process.env.BLENO_HCI_DEVICE_ID) : undefined;


  if (process.env.HCI_CHANNEL_USER) {
    this._deviceId = this._socket.bindUser(deviceId);

    this._socket.start();

    this.reset();
  } else {
    this._deviceId = this._socket.bindRaw(deviceId);
    this._socket.start();

    this.pollIsDevUp();
  }
};

(2) Macの場合

Macの場合、元々、本体のBluetoothデバイスが使用可能ですが、USBに新たにデバイスを追加したりすると、最後に追加したものだけが有効になり、それしか利用できませんでした。

hciconfighcitoolというコマンドは、Macでは利用できず、デバイスが複数有効になっている事を見ることはできませんでした。

下記は、bleaconによるMacでの実装ですが、デバイス番号という概念自体が無いように見えます。

https://github.com/sandeepmistry/bleno/blob/master/lib/mac/bindings.jsより

var BlenoBindings = function() {
  this._xpcConnection = new XpcConnection('com.apple.blued');
  this._deviceUUID = null;

3 TSS (Time Sharing System)

複数のデバイスが利用できなかったので、TSSで実装することにしました。

もともと、省電力を追求したBLEでは、アドバタイズ間隔は、20 ms 〜 10.24 secとなっており、ずっと送信している必要もなさそうなので、複数のアドバタイズを順に発信することで、複数のiBeaconが動作しているように模擬することにしました。

以下は、コードの抜粋です。

var iBeacons: [Ibeacon] = []
iBeacons.append(Ibeacon(uuidString: "9297D8AC-DA28-47F8-AC3D-FEC26012CCC0",major: 1,minor: 1))
iBeacons.append(Ibeacon(uuidString: "9297D8AC-DA28-47F8-AC3D-FEC26012CCC0",major: 1,minor: 2))
iBeacons.append(Ibeacon(uuidString: "9297D8AC-DA28-47F8-AC3D-FEC26012CCC0",major: 1,minor: 3))
iBeacons.append(Ibeacon(uuidString: "9297D8AC-DA28-47F8-AC3D-FEC26012CCC0",major: 1,minor: 4))
iBeacons.append(Ibeacon(uuidString: "9297D8AC-DA28-47F8-AC3D-FEC26012CCC0",major: 1,minor: 5))
iBeacons.append(Ibeacon(uuidString: "F0BD940B-A408-4DAA-BD26-ACC848E63DDD",major: 200,minor: 1))
iBeacons.append(Ibeacon(uuidString: "F0BD940B-A408-4DAA-BD26-ACC848E63DDD",major: 201,minor: 1))
iBeacons.append(Ibeacon(uuidString: "7456723A-BE65-4559-9BC7-AE3E2F54656B",major: 1,minor: 1))
iBeacons.append(Ibeacon(uuidString: "93270F50-8CEA-4AFA-8C2C-92EE3C5468E1",major: 1,minor: 1))
iBeacons.append(Ibeacon(uuidString: "8476551A-ADB3-400C-B221-4D033BAE7660",major: 1,minor: 1))

iBeacons.forEach {
    if $0.power { // powerがONになっているものだけ発信する
        $0.start()
        usleep(20000) // 20ミリ秒
        $0.stop()
    }
}
func start() {
    let beaconData = BeaconData(proximityUUID: uuid, major: major, minor: minor, measuredPower: -50)
    manager?.startAdvertising(beaconData.advertisement as! [String : Any]?)
}

func stop() {
    manager?.stopAdvertising()
}

20ミリ秒の発信をループしていますが、どれぐらいの発信時間が適当なのか、また、いくつまで多重化しても大丈夫なのか、正直分かっていません。

セントラル側の実装にも関係すると思いますので、あくまで試験用ということで、調整しながら利用することにしました。

4 最後に

今回は、1台のMacで複数のiBeaconを発信するアプリを作成してみました。 複数のiBeaconを準備しなくても、簡単に試験環境が構築できそうな気がします。

なお、これは、あくまで正規のiBeaconではありませんので、最終的には、本物を使用して動作確認する必要があることを、あらかじめご了承ください。

コードを置きましたので、不明な点があればご参照ください。
github [GitHub] https://github.com/furuya02/iBeaconGenerator

5 参考リンク


iOS✕BLE Core Bluetooyth プログラミング 堤修一✕松村礼央=著
IoT技術の代表「BLE:Bluetooth Low Energy」の動作原理を理解してみよう
Raspberry Pi で iBeacon を試してみよう!
MacやLinuxでnodeを使ってiBeaconをつくれるとはどういうことなのか?
[iBeacon] Mac を iBeacon 端末にする(Swift3編)
iBeaconのスキャナーを作ってみた