RSSIで近くの端末に接続する

複数人でBluetooth通信のアプリを操作する際いろんなデバイスに繋がってしまい検証が困難になってしまいます。

AndroidのBluetoothにはMacIDが用意されているので自分の検証用端末のIDで絞れるのですが、iOSのBleutoothにMacIDは存在しません。

そのためiOSで端末を制御する際はRSSIを使って電波強度の強いものに接続するのが良いです。※電波強度==距離ではありません

RSSIとは

RSSIは-の値で取得することができます。0に近いほど電波強度が強いようです。

RSSIは、主に無線LANBluetoothなどの無線通信において、送信範囲制御などの目的利用されている。これは、あまりに出力が強いと不必要に距離の離れ箇所までカバーすることになり、電力の無駄や盗聴危険性が生じるためである。

https://www.weblio.jp/content/RSSI

信号強度は以下のような感じらしいです。-30が最高で-90がかなり弱いノイズのような値らしいです。

検証している過程で-25、-95の値を取得したので限界値が-30, -90というわけではないようです。

信号強度TL;DR 説明必須
-30 dBm素晴らしい達成可能な最大信号強度。クライアントは、これを実現するには、APから僅か数フィートである必要があります。現実的には一般的ではなく、望ましいものでもありませんN/A
-67 dBm良好非常に信頼性の高く、データパケットのタイムリーな伝送を必要とするアプリケーションのための最小信号強度VoIP/VoWiFi, ストリーミングビデオ
-70 dBmOkay信頼できるパケット伝送に必要な最小信号強度Email, web
-80 dBmよくない基本的なコネクティビティに必要な最小信号強度。パケット伝送は信頼できない可能性がありますN/A
-90 dBm使用不可ノイズレベルに近いかそれ以下の信号強度。殆ど機能しないN/A

引用: https://www.ibsjapan.co.jp/tech/details/metageek-solution/understanding-rssi.html

コード

スキャンしてペリフェラルを発見すると呼ばれるfunc centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any],rssi RSSI: NSNumber)メソッドの引数としてRSSIを保持しています。

RSSIをラベルに表示する小さなアプリをさくせいしました。デバイスを指定しないと物凄い数のペリフェラルを検出してしまうため、検証デバイスとしてtoio core cubeを使用しました。

通常の設定では同じデバイスを重複して取得しないようになっていますが、scanForPeripheralsのoption, CBCentralManagerScanOptionAllowDuplicatesKeyの値をtrueに設定することで同じデバイスを何度も取得することができます。

import UIKit
import CoreBluetooth

class ViewController: UIViewController, CBCentralManagerDelegate {
    @IBOutlet weak var label: UILabel!
    
    var manager : CBCentralManager!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        manager = CBCentralManager(delegate: self, queue: nil)
        
    }
    
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        if central.state == .poweredOn {
            central.scanForPeripherals(withServices: nil, options:  [CBCentralManagerScanOptionAllowDuplicatesKey : true])
        }
    }
    
    func centralManager(_ central: CBCentralManager,
                        didDiscover peripheral: CBPeripheral,
                        advertisementData: [String : Any],
                        rssi RSSI: NSNumber) {

        if peripheral.name != "toio Core Cube"{
            return
        }
        print(RSSI)
        label.text = String(Int(truncating: RSSI))
    }
}

電波強度が-50以下でない場合returnする処理を記述しておけば同じ部屋で開発を行っていてもある程度は自分のデバイスに繋がるようになります!

検証動画

スキャンを行なっているデバイスを名前で絞って一件のみにし、デバイスを近づけたり遠ざけたりしています。-30付近の値が表示される際はiPhoneの真上にデバイスがいる時です。

広い敷地があればBluetoothデバイスをたくさん配置して、迷路や謎解きゲームなんかに使えそうだなと思いました。

参考文献

RSSI

Wi-Fiの知識 - RSSIの理解