Beaconの検知距離を計測してみた

# はじめに

会社でBeaconを使ったiOSアプリを開発する機会がいくつかありました。
実際にアプリを動かして検知のテストを何度か実施したのですが、
Beacon設定で表示されている検知範囲よりも遠くで反応したり、逆に近づいても反応しなかったりと
検知の精度が安定しないこと多々・・・

そこでBeaconの設定で変えられる電波強度（送信範囲）はだいたい合っているのか
検証してみたいと思います！



# 今回使うBeacon
今回の検証は、このBeaconを使用して検証します。

 『[サンワサプライ社のBeacon](https://www.sanwa.co.jp/product/syohin.asp?code=MM-BLEBC1)』

　　　　　　　　<img width="229" alt="スクリーンショット 2019-12-10 9.32.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278063/f770310e-7d35-d228-2299-95379742fdd9.png">

Beaconの電源を手動でON/OFFできるので、検証にはもってこいです。

# 検証前の準備
### まずはiOS検知アプリをさくっと作ります

##### Xcodeで新規プロジェクトを作成

プロジェクトができたら、ファイルの中にある『Info.plist』に以下を追記します。

|    key    | value    |   
|:-----------------|:------------------|
| Privacy - Bluetooth Always Usage Description※| ビーコンの接続に使用します   |
| Privacy - Location Always and When In Use Usage Description| Beacon を観測するために使用します|
| Privacy - Location When In Use Usage Description| Beacon を観測するために使用します|
※「Privacy - Bluetooth Always Usage Description」はiOS13から必須です。

##### Main.storyboardに検知した際に文字を出すラベルをおきます
<img width="1440" alt="スクリーンショット 2019-12-10 8.52.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278063/99cb0cc7-6c0f-da94-eb55-9209c1cd94e6.png">

ラベルを配置したら、アシスタントマネージャーで接続をします。

##### 検知するプログラムをかきます

以下、全体ソースです。

```swift:BeaconTestApp
import UIKit
import CoreLocation

class ViewController: UIViewController,CLLocationManagerDelegate{

    @IBOutlet weak var regionLabel: UILabel!

    //beaconの値取得関係の変数
    var LocationManager : CLLocationManager!
    var beaconRegion : CLBeaconRegion!

    //beacon変数
    var uuid: UUID = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
    
    let UUIDList = [
        "持っているBeaconのUUIDを入力"]
    
    override func viewDidAppear(_ animated: Bool) {
       //位置情報の確認
       setLocationInfo()
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // ロケーションマネージャを作成する
        LocationManager = CLLocationManager();

        LocationManager.delegate = self;
        
        // セキュリティ認証のステータスを取得
        let status = CLLocationManager.authorizationStatus()
        // まだ認証が得られていない場合は、認証ダイアログを表示
        if(status == CLAuthorizationStatus.notDetermined) {
            LocationManager.requestWhenInUseAuthorization()
        }

        // 位置情報使用確認のステータスを取得
        let locationStatus = CLLocationManager.authorizationStatus()
        if locationStatus == CLAuthorizationStatus.notDetermined {
            LocationManager.requestAlwaysAuthorization()
        }
        startMyMonitoring()
    }
    
    func startMyMonitoring() {
        
        for i in 0 ..< UUIDList.count {
            let uuid: UUID = UUID(uuidString: "\(String(describing: UUIDList[i]).lowercased())")!
            
            // リージョン検知のインスタンスを作成
            beaconRegion = CLBeaconRegion(proximityUUID: uuid, identifier: "beacon\(i)")
            
            // リージョン検知開始
            LocationManager.startMonitoring(for: beaconRegion)
        }
    }
    //①観測の開始に成功すると呼ばれる
    func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
        //観測開始に成功したら、領域内にいるかどうかの判定をおこなう。→（didDetermineState）へ
        LocationManager.requestState(for: self.beaconRegion)
    }

    //②領域内にいるかどうかを判定する
    func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for inRegion: CLRegion) {
 
        switch (state) {
             case .inside: 
                    regionLabel.text = "inside"
                    LocationManager.startRangingBeacons(in: inRegion as! CLBeaconRegion)
                 break

             case .outside:
                    regionLabel.text = "outside"
                 break

             case .unknown:
                
                 break
        }
    }

    //③領域に入った時
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
        self.LocationManager.startRangingBeacons(in: self.beaconRegion)
    }
    //④領域内にいるので測定をする
    func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion){
        
        //Beaconの数をカウントする
        if beacons.count == 0 { return }
        
        //みつけたBeacon数まわす
         for beacon in beacons {
            if beacon.rssi != 0 {
               //フォアグラウンドの時の検知で以下使用。
               switch (beacon.proximity) {
                   case .unknown:
                       //regionLabel.text = "unknown"
                       break
                   case .immediate:
                       //regionLabel.text = "immediate"
                       break
                   case .near:
                       //regionLabel.text = "unknearnown"
                       break
                   case .far:
                       //regionLabel.text = "far"
                       break
               }
            }
        }
    }
    
    //領域から出た時
    func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
         regionLabel.text = "outside"   
         //測定を停止する
         self.LocationManager.stopRangingBeacons(in: self.beaconRegion)
    }
    
    //位置情報の許可　常に許可を確認する
    func setLocationInfo() {
        let locationStatus = CLLocationManager.authorizationStatus()
        if locationStatus == CLAuthorizationStatus.authorizedAlways {
            // 常に許可
            print("常に許可")
        } else if locationStatus == CLAuthorizationStatus.authorizedWhenInUse {
            // このAppの使用中のみ許可
            print("このAppの使用中のみ許可")
        } else if locationStatus == CLAuthorizationStatus.denied {
            // 許可しない
            print("許可しない")
        }
    }
}
```
##### アプリを実行します。
　Beaconの検知範囲に入ると、ブルーのラベルに”inside”と表示され、逆に検知範囲から離れると”outside”と表示される簡単なアプリができました。

# 検証してみましょう

Beaconの設定画面を開き、現在のBeacon送信強度を確認します。

サンワサプライ社のBeacon設定画面はこんな感じ
![IMG_0686.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278063/ac59f126-c5a8-3ea4-4e4d-5a5df5ec90c1.jpeg)



検証は各送信強度を変更しながら、3回ずつ検知させます。
”outside”が”inside”になった場所からBeaconとの距離を計測します。
（この検証で参考になるデータが取れるかはわかりませんが・・・）

今回は-30dBmから-8dBmまでを計測したいとおもいます。

# 計測結果

| 送信強度(検知距離) | Beaconとの距離　１回目 |  Beaconとの距離　２回目 | Beaconとの距離　3回目 |   
|:-----------------|:------------------|:------------------|:------------------|
| -30dBm (2m) | 0.22 m   | 0.43 m  | 0.42 m  |
| -20dBm (7m) | 2.1 m   |  3.29 m  | 3.12 m  |
| -16dBm (10m) | 6.63 m   |  5.12 m  | 7.73 m  |
| -12dBm (15m) | 14.43 m   |  12.55 m  | 13.50 m  |
| -8dBm (22m) | 14.74 m   |  13.83 m  | 12.12m  |


距離の計測は以下の無料計測アプリ（[CamToPlan](https://apps.apple.com/jp/app/camtoplan-計測-3d-定規/id1292176208)）を使用させていただきました。

# まとめ

今回検証してBeaconの電波強度は設定画面で表示されている最大検知距離よりも短めの距離で反応することがわかりました。
-12dBmはだいたい設定と同じくらいでしたが、-30dBm〜-16dBmは半径？と考えるくらい距離が違っていました。
-8dBmは、-12dBmの検知距離とほぼ変わらない結果となりました。
ただ私が検証した環境や、同じフロアにBeaconだらけ（UUIDはどれも違うので影響はないかと思いますが・・）なので、検証が果たして正しいのかはわかりません。
ですが、今後のBeaconアプリ開発に役立てるような結果が得られたので検証してよかったなと思います。