M5Stack Atom LiteをBLEのビーコン端末にする

## 要約
M5StackのAtom Liteで以下のコードを実行しました。

```c:sketch.ino
#include <BLEDevice.h>
#define BLE_DEVICE_NAME "MyDevice"

void setup() {
  Serial.begin(115200);

  BLEDevice::init(BLE_DEVICE_NAME);
  BLEDevice::startAdvertising();

  Serial.println("startAdvertising");
}

void loop() {}
```

## 背景
ハッカソンでの開発で**マイコン同士をBLEで通信させたい**というときがありました。それに向けて、まずは自身をBLE端末として起動し接続を待つ信号を出し続ける、いわば**BLEビーコン**のような機能を実装することにしました。

今回使うマイコンはより小型な方が望ましいということで、**M5StackのAtom Lite**（以下、Atomと呼称）という端末を使っています。非常に小型なのに、**Wi-FiもBluetoothもどちらも対応**している優れものです。お値段も1,500円程度と良心的です。

https://www.switch-science.com/products/6262

この記事ではBLEビーコンの端末を実装しています。クライアント側のスマホアプリの実装を[別の記事](https://qiita.com/mochi_2225/items/0ee6bb46b41cb49ad9d4)に書いていますので、こちらも合わせてご参照ください。

## BLEの仕組み

https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-1/

先に簡単なBLEの仕組みだけ確認しておきます。上記のサイトの一連の説明がわかりやすかったので、詳細はこちらをぜひご覧ください。

BLEには親機と子機のような分類が存在し、**親機をセントラル**、**子機をペリフェラル**と呼ぶそうです。Bluetoothイヤホンでいえばイヤホンが子機、スマホが親機に対応するでしょうか。今回のBLEビーコンで言えばビーコン側の端末（＝M5Stack Atom Lite）が子機にあたります。

この子機端末は**親機からの接続待ちの間アドバタイズという信号を発信**し続けます。親機は**このアドバタイズを検知して、特定の端末とデータ通信を行うための接続要求を行う**と言った流れだそうです。

また、このアドバタイズの電波受信強度を**RSSI**と言います。より近くにある端末ほど電波強度が強く、遠くにある端末ほど弱くなるということになります。

今回の**BLEビーコン**はこの**アドバタイズ信号を常時出し続けていて**、それを親機で検知しその強度から親機の位置や周囲の状況を把握するという仕組みになっています。

たとえばビーコン側が固定されているならば、周囲のデバイスの受信強度から親機が今どこにいるのかを推定できます。忘れ物タグのようなビーコン側が動く状況なら、**受信強度が高いほど端末が近くにある**ことが分かります。

ビーコン用途の利用の場合は実際のデータ通信や接続要求は行わないので、ここまでの理解でやりたいことの全体像は掴めました。

## 実装
上で述べたようなビーコン端末の挙動を実際にAtomで実装していきます。ここでの方針として、**できるだけ簡単に、最低限必要な箇所のみ記述する**ということを意識しています。今回目指すのは**ビーコン端末**なので、**データ通信に関係する処理は記述していません**。そう言った内容は、参考にあげている記事などを参考にしてください。

と、思って参考にしたソースコードの要らなそうな箇所を削っていたら、本当に少ない中身になってしまいました。それでも、最低限これだけでビーコンとしての動作は実現できそうです。各ビーコンの識別は、`BLE_DEVICE_NAME`という定数で指定している**端末名**で行う想定です。

以下がソースコードの全文です。

```c:sketch.ino
#include <BLEDevice.h>
#define BLE_DEVICE_NAME "MyDevice"

void setup() {
  Serial.begin(115200);

  BLEDevice::init(BLE_DEVICE_NAME);
  BLEDevice::startAdvertising();

  Serial.println("startAdvertising");
}

void loop() {}
```

私自身も仕様を把握できているわけではないので、メソッド名などからの推測になりますが、無難に`BLEDevice::init(BLE_DEVICE_NAME)`でデバイスを初期化し、`BLEDevice::startAdvertising()`でアドバタイズを開始しているのでしょう。

### 書き込み
上記のようなプログラムを書いたら、Arduino IDEを使ってAtomにコードを書き込みます。私の場合は**Boardに`ESP32 PICO-D4`を設定**し、**`Upload Speed`を`"115200"`にする**ことで書き込みができました。デフォルトの設定だと`Upload Speed`がもっと大きな値になっているのですが、どうもそれでは書き込みができないようでした。

https://qiita.com/noco/items/1677633def84eaa005cc

https://forum.arduino.cc/t/esp32-a-fatal-error-occurred-unable-to-verify-flash-chip-connection-no-serial-data-received-failed-uploading-uploading-error-exit-status-2/1250126

## 動作確認
ビーコンを利用したアプリの実装は別の記事でまた書こうと思っています。今回は簡易的な動作確認として、ストアにある**BLEデバイスを検出する既存アプリ**を使ってデバイスの存在を確認していきます。私は[BLE Scanner](https://apps.apple.com/jp/app/ble-scanner-4-0/id1221763603)というアプリを利用しました。

デバイスを一覧してみると、先ほど`MyDevice`と名付けた端末が見えました。「connect」を押すと詳細が見え、ここにも`Device Local Name`の項目で設定した端末名が見えています。

![ble-device-1.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351104/cf941291-3bca-ac1f-3806-8a5ff03326f4.jpeg)

![ble-device-2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/351104/2631b13a-a074-6659-ebed-4cd24206056b.jpeg)

ただ、接続後の処理を書いていないためか、一度「connect」を押して詳細を見ると、その後**デバイス一覧にビーコンが表示されなくなってしまいました**。ビーコン用途であれば接続することはまず無いのでこれでも大丈夫かなとは思いますが、必要に応じて再度アドバタイズする処理を書いたほうがいいのかもしれません。

## 終わりに
非常にシンプルなプログラムで**BLEビーコン**を実装することができました。ライブラリ様々です。

このハッカソンでは本来データ通信をする予定だったのですがそれにはだいぶ手こずってしまい、完全には実装しきることができませんでした。その内容も、さらに理解が深まったら、また別の記事でまとめたいなと思います。

## 参考

https://www.musen-connect.co.jp/blog/course/trial-production/ble-beginner-1/

https://qiita.com/yutaka_m/items/283126079ec6f4052f0e

https://qiita.com/Teach/items/629c338da05a3134a1eb

https://zenn.dev/luup_developers/articles/iot-yamaguchi-20221204