前回のエントリで実験したプレゼンス管理、要求を満たした動作はしましたがいくつか問題点が見えました。
- BLEタグが人数分欲しい
- ESP-NOWが届く範囲にM5Atomを配置する必要がある
- セントラルもWiFiに繋げてないので情報を見にこないといけない
イメージ
ESP-NOWだけで通信していることが大きな縛りになっているので、やはり素直にWiFiつかってサーバへ送ると問題点の大半が解決しそうです。
オフィスだとノートPCで仕事する人が多いので、そもそもWiFiに繋がったデバイスを持ち歩いていることになります。位置を検出して送信する仕事はPCに任せてしまいましょう。
必要な要素は以下の感じですかね。
- 位置情報を保持するDB
- 位置ビーコン
- 位置検出と送信するアプリケーション
- 収集した情報を表示する仕組み
あとビーコンやユーザー情報のDBも必要でしょう。
- 位置ビーコン情報を保持するDB
- ユーザー情報を保持するDB
この構成にすれば位置の判定から情報の送信まで、素直に実装できそう。
構成
手持ちの機材をやりくりして下記の構成で作ってみます。
位置ビーコン | M5Atom LITE |
位置情報DB | Raspberry pi 3B+ |
表示アプリ | ↑ |
位置ビーコン情報DB | ↑ |
ユーザー情報DB | ↑ |
位置検出と送信するアプリ | WindowsPC |
位置ビーコン
ビーコンはiBeaconデバイスとして作成します。
iBeaconは言わずと知れたAppleのBLEビーコンの仕様で、下記のサイトによるとBLEのアドバタイズパケット内にのっけたUUID, Major値, Minor値で個体を特定するようです。
何やらややこしそうですが、前回も利用した NimBLE-Arduinoライブラリのサンプルがほぼそのまま参考になりそうです。
サンプルでは
- ブートアップ
- 100ms間アドバタイジング
- deep sleep
のループで動作し、ブートアップした回数をMajor値とMinor値に割り当てるようになっています。
位置を特定するビーコンを作るのでMarjor値もMinor値も固定で実装するだけです。 UUIDは uuidgen で生成した値、MajorとMinorはとりあえず0x1000 にしています。
const char* UUID = "7626EE90-9058-4BA7-B28B-A4E3B1C81583"; const uint16_t MAJOR = 0x1000; const uint16_t MINOR = 0x1000; void setBeacon(BLEAdvertising* advertising) { BLEBeacon oBeacon = BLEBeacon(); // fake Apple 0x004C LSB (ENDIAN_CHANGE_U16!) oBeacon.setManufacturerId(0x4C00); oBeacon.setProximityUUID(BLEUUID(UUID)); oBeacon.setMajor(MAJOR); oBeacon.setMinor(MINOR); BLEAdvertisementData oAdvertisementData = BLEAdvertisementData(); BLEAdvertisementData oScanResponseData = BLEAdvertisementData(); oAdvertisementData.setFlags(0x04); std::string strServiceData = ""; strServiceData += static_cast<char>(26); strServiceData += static_cast<char>(0xFF); strServiceData += oBeacon.getData(); oAdvertisementData.addData(strServiceData); advertising->setAdvertisementData(oAdvertisementData); advertising->setScanResponseData(oScanResponseData); advertising->setAdvertisementType(BLE_GAP_CONN_MODE_NON); }
あとは setup()
でBLEの初期化とアドバタイジングを開始すればOKです。
アドバタイジングとスリープの周期はそれぞれ10秒に変更しておきました。
void setup() { BLEDevice::init(""); BLEAdvertising* advertising = BLEDevice::getAdvertising(); setBeacon(advertising); advertising->start(); ::delay(ADVERTISING_SEC*1000); advertising->stop(); ::esp_deep_sleep(SLEEP_TIME_SEC*1000*1000LL); } void loop() { }
BLE Scannerというアプリで確認したところ、設定した値のiBeaconとして検出されています。
長くなってきたので次回に続きます!