ESP32のBLEのRSSIを調べてみた

# ESP32のBLEのRSSIを調べてみた

研究の一環として，ESP-WROOM-32を用いてRSSI値の測定をやってみました．

## 使用機材
- [ESP32-DevKitC](https://akizukidenshi.com/catalog/g/gM-11819/) 4台
- Mac book Pro (Big Sur)

## 環境構築
筆者は日頃Python3を用いてコードを書いているので，今回はmicropythonを使っています．
ESP32でmicropythonを使う場合は[こちらを参照](https://micropython-docs-ja.readthedocs.io/ja/latest/esp32/tutorial/intro.html)してください．
>https://micropython-docs-ja.readthedocs.io/ja/latest/esp32/tutorial/intro.html

エディタやIDEはお好みで大丈夫ですが，作成したコードをESP32に焼く際は[esp-idf](https://github.com/espressif/esp-idf)を用いるのが楽だと感じました．
クイックリファレンスがGithubに上がっていますので，興味がある方はぜひ．
>https://github.com/espressif/esp-idf

## BLEのRSSI取得方法
[公式のGithubのコード](https://github.com/micropython/micropython)を参考にさせていただきました．
>https://github.com/micropython/micropython

参考にさせていただいたのは，`example > bluetooth`内のコードです．

### 送信側の処理
送信側は`ble_advertising.py`と`ble_temperature.py`をそのまま使用しています．


### 受信側の処理
まず，`ble_advertising.py`の`demo()`を自分の環境に合わせて変更してください．

```python
def demo():
    payload = advertising_payload(
        name="micropython",
        services=[bluetooth.UUID(0x181A), bluetooth.UUID("XXXX")],
    ) #送信側のUUIDに設定
```

筆者はMongoDBにデータを格納しているので以下のようなコードになりました．
`xxx`の部分は適時変更してください．

```python
import ubluetooth
import utime
import ubinascii
import urequests
import ujson
import network, urequests, utime
from machine import Pin, RTC
from micropython import const

_IRQ_SCAN_RESULT                     = const(5)
_IRQ_SCAN_DONE                       = const(6)

def send_db(name,addr,rssi):
    url = 'http://xxxxxxx'
    now = get_jst()
    payload = {
        "db": "xxx",
        "collection": "xxx",
        "datetime": now,
        "data": {
            "name": name,
            "addr": ubinascii.hexlify(addr),
            "rssi": rssi,
        }
    }
    header = {
            'Content-Type' : 'application/json'
            }
    res = urequests.post(
        url,
        data = ujson.dumps(payload).encode("utf-8"),
        headers = header
    )
    res.close()

def get_jst():
    rtc = RTC()
    url_jst = "http://worldtimeapi.org/api/timezone/Asia/Tokyo"
    retry_delay = 5000
    response = urequests.get(url_jst)
    parsed = response.json()
    datetime_str = str(parsed["datetime"])
    year = int(datetime_str[0:4])
    month = int(datetime_str[5:7])
    day = int(datetime_str[8:10])
    hour = int(datetime_str[11:13])
    minute = int(datetime_str[14:16])
    second = int(datetime_str[17:19])
    subsecond = int(round(int(datetime_str[20:26]) / 10000))
    rtc.datetime((year, month, day, 0, hour, minute, second, subsecond))
    daysOfTheWeek = "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"
    tm = utime.localtime(utime.mktime(utime.localtime()))
    date_str = "{0:4d}/{1:02d}/{2:02d}".format(*rtc.datetime())
    time_str = "{4:02d}:{5:02d}:{6:02d}".format(*rtc.datetime())
    date_ok = date_str + " " + time_str
    return date_ok

ble=ubluetooth.BLE()

if ble.active()== False:
    ble.active(True)

def bt_irq(event, data):
    if event == _IRQ_SCAN_RESULT:
        addr_type, addr, connectable, rssi, adv_data = data
        name = "xxx"
        addr_hex = ubinascii.hexlify(addr)
        if '{}'.format(ubinascii.hexlify(addr)) == 'b\'xxxxx\'':
            print('addr:{} rssi:{} '.format(ubinascii.hexlify(addr), rssi ))
            send_db(name, str(addr_hex), rssi)
    elif event == _IRQ_SCAN_DONE:
        print('Scan compelete')
        pass

ble.irq(bt_irq)
ble.gap_scan(600000, 30000, 30000)
```

`ble.gap_scan()`に関する詳しい説明は[ubluetoothのリファレンス](https://micropython-docs-ja.readthedocs.io/ja/latest/library/ubluetooth.html)を読んでみてください．
>https://micropython-docs-ja.readthedocs.io/ja/latest/library/ubluetooth.html

## RSSIの測定
受信側，送信側それぞれをESP32に焼き，実行してみましょう．
筆者はWebREPLを使用しています．
![Screen Shot 2021-07-25 at 22.21.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266405/0923347c-34b0-c699-2d34-7cddf3992634.png)
### WebREPLの使用手順
①左上のIPアドレスを変更し，Connect！
②右上からファイルを選択し，Send to device！
③以下のコマンドを実行！

```shell
>>> execfile("xxx.py")
```

### 3つのビーコンで測定
各ビーコンで1mの時をそれぞれ測定すると以下のような分布になりました！
なお，縦軸は取得回数，横軸はRSSI値です．
![Picture1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266405/085f3a32-4533-f6f3-b4fd-2141e3967f86.png)
![Picture2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266405/0764c4f7-459d-8f1a-b79e-94865bfc56f1.png)
![Picture3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266405/e3b5cca1-ba6f-9929-bf54-a048167b5aa8.png)

しっかり測定はできましたが，それぞれで誤差がかなりありそうですね．．．

##おわりに
ESP32は機器ごとにも誤差が大きいようで，しっかりとした基準値をうまく決めないと使えないようですね...
位置精度の改善や座標の特定など色々な用途に使用できそうですね！