BLEタグ資産追跡システムの構築は、適切なタグを選ぶことではありません。施設内に散在する数百〜数千のタグからデータを受信、フィルタリング、転送、保存するインフラストラクチャについてです。タグ自体は単なるブロードキャスタであり、知能はゲートウェイネットワーク、エッジプロセッサ、クラウドバックエンドに存在します。本記事では、病院、倉庫、製造現場での本番稼働データに基づき、無線受信からダッシュボードまでのフルシステムアーキテクチャを分解し、ハードウェア選定表、フィルタリングアルゴリズム、データパイプラインスキーマ、デプロイコストモデルを提示します。

1. システムアーキテクチャ概要

本番BLE資産追跡システムは4層構造で、各層に異なるレイテンシ、スループット、信頼性要件があります:

コンポーネント レイテンシ予算 データ量 障害影響
T1: タグ層 BLEタグ(数百〜数千) N/A(ブロードキャストのみ) ~30バイト/タグ/イベント 単一資産が消失
T2: ゲートウェイ層 BLEスキャナ(5-50台) 100-500 msスキャンサイクル ~50 KB/sピーク/GW ゾーンが消失(10-50タグ)
T3: エッジ層 ローカルサーバまたはエッジアプライアンス 1-5 s処理 ~200 KB/s集約 追跡遅延、データ消失なし
T4: クラウド層 バックエンド、DB、ダッシュボード 1-10 sエンドツーエンド ~500 KB/s持続 履歴データギャップ

最も一般的なアーキテクチャの間違いは、ゲートウェイを生BLEパケットをクラウドに転送する単なるリレーとして扱うことです。500タグ、1秒間隔、10ゲートウェイの場合、1秒間に5,000パケットがクラウドインジェストエンドポイントに到達し、それぞれにカバレッジゾーンが重複したRSSI読み取りが含まれます。エッジフィルタリングは最適化ではなく要件です。

2. ゲートウェイハードウェア選定

プラットフォーム BLEチップ CPU RAM 消費電力 BOMコスト 適用途
ESP32ベース ESP32(デュアルモード) 240 MHz Xtensa x2 520 KB SRAM 2.5W(WiFi+BLE) $3-5 小規模サイト、WiFiバックホール
Raspberry Pi + USBドングル nRF52840ドングル 1.4 GHz ARM A72 x4 1-4 GB 5-7W $45-60 R&D、プロトタイピング、小ロット
専用ゲートウェイ nRF52832/52840 + ESP32 ESP32 240MHz + nRF52 520KB + 256KB 2-3W $15-25 本番デプロイ
産業用ゲートウェイ(Linux) CC2640R2 + WiFi/LTE ARM Cortex-A7 1GHz 512 MB 5-15W $200-400 過酷な環境、セルラー

2.1 ESP32の能力と限界

ESP32はWiFiとBLEを内蔵するため、コスト重視のデプロイで最も一般的です。ただし、ESP32のBLEコントローラは2.4 GHz無線をWiFiとBLEで共有しており、WiFi送信中はBLEスキャンができません。この時分割多重によりスキャンギャップが発生します:

WiFi活動 BLEスキャンギャップ パケットロス(1s間隔) パケットロス(500ms)
アイドル(ビーコンのみ) 0 ms 0% 0%
MQTTパブリッシュ(5s毎) ~15 ms/ギャップ 0.3% 0.6%
WiFiストリーミング(連続) ~50 ms/ギャップ 1.0% 2.0%
OTAアップデート ~200 ms/ギャップ 5-8% 10-15%

2.2 専用ゲートウェイアーキテクチャ

本番ゲートウェイは通常、nRF52(専用BLEスキャナ)とESP32(WiFi/CPU)をペアにします。nRF52が連続アクティブスキャンを実行し、UART/SPIでESP32にパケットを転送し、ESP32がフィルタリング、バッファリング、クラウド通信を処理します。このデュアルチップ設計で無線の競合が完全に排除されます。

# nRF52側:連続BLEスキャナ
def ble_scan_callback(adv_report):
    packet = {
        "mac": adv_report.peer_addr,
        "rssi": adv_report.rssi,
        "adv_type": adv_report.type,
        "data": adv_report.data,
        "ts": get_timestamp_us(),
    }
    uart_send(json.dumps(packet))

# ESP32側:受信、フィルタ、バッチアップロード
rx_buffer = []
def uart_rx_callback(data):
    pkt = json.loads(data)
    if should_forward(pkt):
        rx_buffer.append(pkt)
    if len(rx_buffer) >= BATCH_SIZE or time_since_last_upload > UPLOAD_INTERVAL:
        upload_batch(rx_buffer)
        rx_buffer.clear()

2.3 ゲートウェイ配置とカバレッジ

精度階層 ゲートウェイ/100m2 典型間隔 コスト/m2 用途
プレゼンス(ルームレベル) 0.5-1.0 10-15 m $0.15-0.30 ゾーン別資産プレゼンス
粗位置(3-5 m) 2-4 5-8 m $0.60-1.20 倉庫通路追跡
高精度位置(1-2 m) 6-10 3-5 m $1.80-3.00 手術器具追跡
サブメートル(0.5 m) 15-25 2-3 m $4.50-7.50 高価値資産監査

3. BLEスキャン戦略

3.1 アクティブvsパッシブスキャン

パラメータ パッシブスキャン アクティブスキャン
SCAN_REQ送信 いいえ はい
SCAN_RSP受信 いいえ はい(最大31バイト追加)
消費電力 低(Rxのみ) 高(Tx + Rx)
タグ電力影響 なし 全スキャンに応答で+20-40%
取得データ 31バイト(Advのみ) 62バイト(Adv + Scan Rsp)

3.2 スキャンウィンドウと間隔

スキャン間隔 スキャンウィンドウ デューティサイクル 捕捉率(1sタグ) 捕捉率(500ms)
連続 連続 100% ~99.5% ~99.0%
1000 ms 1000 ms 100% ~99.5% ~99.0%
1000 ms 500 ms 50% ~50-65% ~50-65%
5000 ms 1000 ms 20% ~20-30% ~20-30%

3.3 無線レベルの重複フィルタリング

フィルタモード 重複報告 パケット/s(500タグ,1s,10GW) GW CPU負荷
フィルタなし 全て ~15,000
コントローラ重複排除 1/タグ/サイクル ~500
アプリ重複排除 1/タグ/ウィンドウ ~500 低-中

4. エッジフィルタリング

4.1 マルチゲートウェイ重複排除

DEDUP_WINDOW_MS = 2000

def deduplicate(raw_reports):
    by_tag = group_by_mac(raw_reports)
    result = []
    for mac, reports in by_tag.items():
        if len(reports) == 1:
            result.append(reports[0])
            continue
        best = max(reports, key=lambda r: score_report(r))
        result.append(best)
    return result

def score_report(r):
    rssi_score = (r.rssi + 100) / 70
    age_s = (now() - r.ts) / 1000
    fresh_score = max(0, 1 - age_s / 5)
    gw_reliability = gateway_stats[r.gw_id].uptime_pct
    return rssi_score * 0.6 + fresh_score * 0.2 + gw_reliability * 0.2

4.2 RSSI平滑化と外れ値除去

フィルタ ウィンドウ 追加レイテンシ 分散低減 実装複雑度
生(なし) 1サンプル 0 s 0% なし
移動平均 5サンプル 2-5 s ~55%
指数平滑 無限(重み付き) 1-3 s ~50%
メディアン 3-7サンプル 1-3 s ~65%
カルマン 適応 0.5-2 s ~70%
# 指数平滑(alpha = 0.3)
ALPHA = 0.3
smoothed_rssi = {}

def smooth_rssi(mac, raw_rssi):
    if mac not in smoothed_rssi:
        smoothed_rssi[mac] = raw_rssi
    else:
        smoothed_rssi[mac] = ALPHA * raw_rssi + (1 - ALPHA) * smoothed_rssi[mac]
    return round(smoothed_rssi[mac], 1)

4.3 イベントベース転送

転送戦略 パケット/タグ/時 クラウドBW(500タグ) 用途
毎スキャン(1s) 3,600 ~14 MB/h サブ秒更新RTLS
5s毎(バッチ) 720 ~2.8 MB/h 標準追跡
ゾーン変更のみ ~5-20 ~40 KB/h ルームレベルプレゼンス
閾値突破+ハートビート ~2-10 ~20 KB/h 温度/湿度アラート

5. データパイプライン設計

5.1 転送プロトコル比較

プロトコル オーバーヘッド 信頼性 レイテンシ GW電力 適用途
HTTP POST (JSON) ~400バイト TCP保証 100-500 ms 小規模、シンプルバックエンド
MQTT (QoS 1) ~20バイト TCP + ACK 50-200 ms 本番デプロイ
UDP (カスタム) ~8バイト なし 10-50 ms 最低 リアルタイムRTLS、ローカルLAN
LoRaWAN ~13バイト 確認ダウンリンク 1-10 s N/A WiFiなしの遠隔サイト

5.2 MQTTトピック構造

# MQTTトピック階層
# 形式: site/zone/gateway/tag/event

site-001/zone-A/gw-01/+/scan      # gw-01の全スキャン
site-001/zone-A/+/tag-005/scan    # zone-A内tag-005の全スキャン
site-001/+/+/tag-005/zone_change  # tag-005のゾーン変更イベント
site-001/+/+/+/battery_low         # サイト全体の電池アラート
site-001/+/+/+/temperature_alert   # 温度閾値突破

# ペイロード形式(JSON、~80バイト)
{
    "mac": "AA:BB:CC:DD:EE:01",
    "rssi": -67,
    "gw": "gw-01",
    "ts": 1722422400000,
    "bat": 85,
    "temp": 23.5,
    "seq": 4823
}

5.3 データスキーマとストレージ

ストア 技術 データ 保持 クエリパターン
時系列(ホット) InfluxDB / TimescaleDB 生スキャンイベント 7-30日 タグ+時間の範囲クエリ
時系列(コールド) S3 / Parquet 集約イベント 1-5年 バッチ分析、コンプライアンス
リレーショナル PostgreSQL / MySQL 資産メタデータ、ゾーン、ユーザー 永久 CRUD、結合
キャッシュ Redis 最終位置 TTL 5分 サブmsルックアップ

5.4 ストレージサイジング

# 500タグ、5s転送間隔のサイジング
tags = 500
events_per_tag_per_hour = 3600 / 5  # = 720
events_per_hour = tags * 720  # = 360,000
events_per_day = 360,000 * 24  # = 8,640,000
bytes_per_day = 8,640,000 * 80  # = 691 MB/day
bytes_per_year = 691 * 365  # = ~252 GB (生)
compressed_per_year = 252 / 5  # = ~50 GB (Parquet 5:1)
total_storage_year = 50 * 1.4  # = ~70 GB (DBオーバーヘッド込み)

6. エッジでの位置推定

アルゴリズム 最小GW数 精度 エッジCPU キャリブレーション 適用途
近接(最強RSSI) 1 ルームレベル(5-10m) 最小 なし シンプルプレゼンス
重み付き重心 3+ 3-5 m GW位置のみ 開放エリア
三辺測量 3+ 2-4 m ゾーン別パスロス指数 倉庫、廊下
フィンガープリント(kNN) 4+ 1-3 m 中-高 RF調査(数時間) 複雑屋内環境
BLE AoA 1(アレイアンテナ) 0.5-1 m アンテナ位相校正 高価値資産追跡

6.1 重み付き重心アルゴリズム

def estimate_position(reports, gateway_positions):
    total_weight = 0
    weighted_x = 0
    weighted_y = 0
    for r in reports:
        gw_id = r["gw_id"]
        if gw_id not in gateway_positions:
            continue
        weight = 10 ** (r["rssi"] / 10)
        gx, gy = gateway_positions[gw_id]
        weighted_x += weight * gx
        weighted_y += weight * gy
        total_weight += weight
    if total_weight == 0:
        return None
    return (weighted_x / total_weight, weighted_y / total_weight)

7. システム信頼性とフェイルオーバー

7.1 ゲートウェイヘルスモニタリング

メトリック 正常範囲 アラート閾値 確認間隔
パケット/分 50-500 < 10 or > 2000 60 s
CPU温度 40-65 C > 75 C 300 s
WiFi RSSI -30 to -65 dBm < -75 dBm 60 s
稼働率 > 99.5% < 99% 日次
最終ハートビート < 30 s前 > 120 s前 30 s

7.2 エッジ-クラウド接続断時のバッファ

最大ダウンタイム バッファサイズ(500タグ,5s) ストレージ
15分 ~4.3 MB RAM
1時間 ~17 MB RAM/SD
4時間 ~69 MB SD/eMMC
24時間 ~415 MB SSD/eMMC

8. デプロイコストモデル

10,000 m2施設、500資産の完全BLE資産追跡システム:

コンポーネント 数量 単価 小計 %
BLEタグ(CR2032、3年寿命) 500 $8 $4,000 18%
専用ゲートウェイ 20 $120 $2,400 11%
エッジサーバ 1 $800 $800 4%
ネットワーク機器+配線 1 $1,500 $1,500 7%
クラウドインフラ(1年目) 1 $3,600 $3,600 16%
ソフトウェアライセンス(1年目) 1 $5,000 $5,000 23%
設置+コミッショニング 1 $3,000 $3,000 14%
予備タグ+GW(10%) $640 3%
RF調査+校正 1 $1,200 $1,200 5%
1年目合計 $22,140 100%

追跡資産あたりコスト:$22,140 / 500 = $44.28(1年目)、$8,640 / 500 = $17.28/年(経常)。RFID方式($60-120/資産)やWi-Fi RTLS($80-150/資産)と比較して有利です。

9. 本番パフォーマンスベンチマーク

メトリック 病院(200タグ,8GW) 倉庫(500タグ,20GW) 工場(1000タグ,15GW)
スキャン捕捉率 98.2% 96.5% 94.1%
位置精度(中央値) 3.2 m 4.8 m 5.5 m
エンドツーエンドレイテンシ(p95) 2.8 s 4.1 s 5.3 s
GW稼働率 99.7% 99.2% 98.8%
クラウドデータ/月 4.2 GB 18.7 GB 24.3 GB
誤ゾーン変更率 0.8% 2.1% 3.5%
タグ電池寿命(中央値) 31ヶ月 28ヶ月 26ヶ月

10. スケーリング考慮事項

規模 タグ GW エッジ クラウド 課題
1-100 1-5 単一GW 単一VPS コスト効率
100-1,000 5-30 専用エッジ VPS+Redis+TSDB カバレッジギャップ
1,000-5,000 30-100 複数エッジ LBクラスタ エッジ間調整
エンタープライズ 5,000-50,000 100-500 地域エッジクラスタ K8s+分散TSDB マルチサイト集約

11. 一般的なアーキテクチャの間違い

間違い 症状 原因 修正
クラウドが全処理 高レイテンシ、高コスト エッジフィルタなし エッジで重複排除+平滑化
ゾーン1GWのみ カバレッジホール GW数を最小化 30-50%カバレッジ重複
全パケットHTTP CPUスパイク、パケットロス TCPハンドシェイク MQTT永続接続
オフラインバッファなし ネットワーク断でデータギャップ Fire-and-forget SQLiteバッファ+リプレイ
生RSSIで位置 5-10mランダム跳躍 平滑化なし 指数平滑(alpha=0.3)
ドエルタイマなし 境界で誤ゾーン変更 カバレッジ重複フリッカ 30s最小ドエル
GW過剰プロビジョニング 冗長データ、高コスト 多いほど良い誤解 30-50%重複を目標
タグ在庫管理なし ゴーストタグ 死タグ未削除 24h沈黙で自動アーカイブ

13. まとめ

本番BLE資産追跡システムの成功または失敗はインフラストラクチャで決まり、タグではありません。BLEタグはスタック中最も安価でシンプルなコンポーネントです。ゲートウェイネットワーク、エッジフィルタリングパイプライン、データ転送、クラウドバックエンドが、システムが2秒レイテンシで3メートル精度を提供するか、30秒レイテンシで10メートル精度にとどまるかを決定します。アーキテクチャ原則は明確です:エッジで早期かつ積極的にフィルタし、転送にはMQTTを使用し、オフライン動作のためにバッファし、ゾーンごとに位置推定を校正します。デモで動くシステムと本番で動くシステムの違いは、完全にこの4層のエンジニアリングにあります。