BLEタグでお手軽プレゼンス管理してみる?

昨今テレワークに代表される多様な働き方が導入されて、メンバーの居場所がわからなくて困っていると小耳に挟みました。

ちょうど(?)使ってなかったBLEタグが手元にあったので、お手軽に解決する方法を考えてみたいと思います。

構成

とりあえずはこんなイメージでしょうか。

f:id:hollyhockberry:20210823182842j:plain

それぞれの役割を列挙すると、

タグ: 個人を特定するIDを周囲にアドバタイジングする

ノード: 周囲に存在するタグを検出し、自らが設置された位置を特定するIDを添えてセントラルへ情報を通知する

セントラル: ノードから通知された最新のタグ位置を保持する

となります。シンプルですね。

今回はそれぞれ下記の構成で実装してみたいと思います。

タグ MAMORIO RE https://mamorio.jp/re
ノード M5ATOM LITE
セントラル M5Stack

実装

ESP-NOW

先程のイメージ図を素直に実装すると、各ノードからセントラルへの通知はWiFi経由で行えば簡単そうです。 ですが、WiFi環境がなかったり未登録の機器による接続に制限がある場合での運用を考慮したいと思います。

M5StackおよびM5Atomに載っているESP32ではESP-NOWというコネクションレスの無線通信が可能です。MACアドレスを指定するだけで送信できてとても便利なのでそちらを使ってみることにしましょう。

ESP-NOWはArduino core for the ESP32のスケッチ例を見ればなんとなくわかっちゃうのですが、一応説明すると

  • 初期化
  • 送信先のピアを登録(送信する場合)
  • コールバックの登録
  • (必要ならば)送信

の流れで実装すれば送受信できちゃいます。簡単ですね。

#include <esp_now.h>
#include <WiFi.h>

const uint8_t CHANNEL = 0;

const uint8_t target[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // 送信先のMACアドレス
};

void OnDataRecv(const uint8_t * mac, const uint8_t *recvData, int len) {
  // 受信した
}

void setup() {
  WiFi.mode(WIFI_STA);

  if (::esp_now_init() != ESP_OK) {
    return;
  }
  esp_now_peer_info_t peerInfo;
  ::memcpy(peerInfo.peer_addr, target, 6);
  peerInfo.channel = CHANNEL;
  peerInfo.encrypt = false;

  if (::esp_now_add_peer(&peerInfo) != ESP_OK) {
    return;
  }

  ::esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  static uint8_t i = 0;
  ::esp_now_send(target, &i, 1);
  i++;

  ::delay(5000);
}

MAMORIOのスキャン

MAMORIOはiBeaconデバイスらしいので、iBeaconをスキャンする実装をしていきます。

BLEのライブラリはNimBLE-Arduinoを使います。
スケッチ例のBLE_Beacon_Scanner.inoがドンピシャで今回やりたいことなのでほぼそのまま参考にできそうですね。

github.com

#include <NimBLEDevice.h>
#include <NimBLEBeacon.h>

const int scanDuration = 5;
NimBLEScan* bleScan;

void setup() {
  NimBLEDevice::init("");
  bleScan = NimBLEDevice::getScan();
  bleScan->setActiveScan(true);
  bleScan->setInterval(100);
  bleScan->setWindow(99);
}

void loop() {
  const auto begin = ::millis();
  auto foundDevices = bleScan->start(scanDuration, false);
  for (int i = 0; i < foundDevices.getCount(); ++i) {
    auto device = foundDevices.getDevice(i);
    // 見つかったデバイスであれこれする
  }
  bleScan->clearResults();
}

loop()内のコメントが挿入されている部分で見つかったiBeaconが対象のMAMORIOだった場合にセントラルへ送信すればいいわけです。

なお、MAMORIO

shima-nigoro.hatenablog.jp

こちらのブログによるとUUID "b9407f30-f5f8-466e-aff9-25556b57fe6e" とのこと。
無印MAMORIOの情報ですが、MAMORIO REでもUUIDは同じでした。

どの個体かを特定するのはMajorとMinorでするんだと思うんですが、手元には一つしかないのでよくわかりません。値段もお高いので今の所追加する予定もないので迷宮入りですね。ご存知の方はお教えいただけると助かります。

完成

iBeaconのスキャンとノード・セントラル間の通信ができるようになったので、あとは組み合わせて実装すれば完成です。

完成したコードはこちらになります。 github.com

今回セントラルはデータを集約するだけではなく表示も兼ねているのでちょっとごちゃっとしていますが、基本的には受け取ったデータを覚えて順次表示しているだけなので難しいところはないんじゃないかなと思います。

ノードを3つ用意して机上で動作確認してみました。なんとなくタグの移動を捉えていますね。

課題

なんとなく期待したような動作ができましたが、動作させてみると課題が見えてきちゃいました。

  1. BLEタグを全員に配るとお金が(ry
  2. ESP-NOWが届く範囲でM5ATOMを配置しなくてはならない

1.はこのシステムにどれだけの価値を見出すかにかかってくるので場合によっては問題にならなそうですが、2.は少し厄介です。 なんとか力技で解決できそうな気がしますが、別の方法を考えてみたいところです。

というわけでもうちょっと考えてみます(続く)