お手軽プレゼンス管理、リトライ! その1 (Beacon編)

前回のエントリで実験したプレゼンス管理、要求を満たした動作はしましたがいくつか問題点が見えました。

  • BLEタグが人数分欲しい
  • ESP-NOWが届く範囲にM5Atomを配置する必要がある
  • セントラルもWiFiに繋げてないので情報を見にこないといけない

イメージ

ESP-NOWだけで通信していることが大きな縛りになっているので、やはり素直にWiFiつかってサーバへ送ると問題点の大半が解決しそうです。

オフィスだとノートPCで仕事する人が多いので、そもそもWiFiに繋がったデバイスを持ち歩いていることになります。位置を検出して送信する仕事はPCに任せてしまいましょう。

f:id:hollyhockberry:20210829151653p:plain

必要な要素は以下の感じですかね。

  • 位置情報を保持するDB
  • 位置ビーコン
  • 位置検出と送信するアプリケーション
  • 収集した情報を表示する仕組み

あとビーコンやユーザー情報のDBも必要でしょう。

  • 位置ビーコン情報を保持するDB
  • ユーザー情報を保持するDB

この構成にすれば位置の判定から情報の送信まで、素直に実装できそう。

構成

手持ちの機材をやりくりして下記の構成で作ってみます。

位置ビーコン M5Atom LITE
位置情報DB Raspberry pi 3B+
表示アプリ
位置ビーコン情報DB
ユーザー情報DB
位置検出と送信するアプリ WindowsPC

位置ビーコン

ビーコンはiBeaconデバイスとして作成します。

iBeaconは言わずと知れたAppleのBLEビーコンの仕様で、下記のサイトによるとBLEのアドバタイズパケット内にのっけたUUID, Major値, Minor値で個体を特定するようです。

techweb.rohm.co.jp

何やらややこしそうですが、前回も利用した NimBLE-Arduinoライブラリのサンプルがほぼそのまま参考になりそうです。

github.com

サンプルでは

  1. ブートアップ
  2. 100ms間アドバタイジング
  3. 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として検出されています。

f:id:hollyhockberry:20210829172158p:plain

長くなってきたので次回に続きます!