Beaconアドバタイジングパケット設計とペイロード最適化
すべてのBluetoothビーコンはアドバタイジングパケットで命が決まります。パケットはビーコンの声であり、レガシーBLEでは31バイトのささやき、拡張アドバタイジングでは255バイトの叫びです。そのバイトをどう詰めるかで、受信機がビーコンを50msで検出するか500msかかるか、電池が18ヶ月持つか3年持つか、同じ部屋に200個のビーコンがあってもクリーンな信号か衝突だらけの混乱かが決まります。
レガシー31バイトアドバタイジングパケット
レガシーBLEアドバタイジングパケット(BLE 4.x)は正確に31バイトのペイロード空間を持ち、AD(Advertising Data)構造体に分割されます。各AD構造体は2バイトのオーバーヘッド(長さ+タイプ)を消費し、実際のデータには29バイト残ります — ただし単一のAD構造体を使用する場合のみ。実際には少なくとも2つが必要です:
| AD構造体 | タイプ | 目的 | 使用バイト |
|---|---|---|---|
| Flags | 0x01 | LE General Discoverable, BR/EDR非対応 | 3(2ヘッダ+1データ) |
| Manufacturer Specific | 0xFF | カンパニーID + カスタムペイロード | 2 + 2 + N |
| Complete Local Name | 0x09 | デバイス名文字列 | 2 + 名前長 |
| TX Power Level | 0x0A | 符号付きint8, -127〜+127 dBm | 3 |
| Service UUID (128-bit) | 0x07 | 完全な128-bit UUIDリスト | 18 |
Flags(3バイト)と必須のManufacturer Specificヘッダ(タイプ+長さ+カンパニーIDで4バイト)の後、実際のビーコンペイロードに24バイト残ります。これがUUID、メジャー、マイナー、TX電力、あらゆるセンサーデータの予算です。iBeaconフォーマットはUUID(16) + Major(2) + Minor(2) + TX Power(1) + reserved(3)で24バイトすべてを使用し、センサーデータの余地はゼロです。
フレームフォーマット比較
| フォーマット | カンパニーID | ペイロードレイアウト | センサーデータ? | エコシステム依存 |
|---|---|---|---|---|
| iBeacon | 0x004C (Apple) | UUID(16) + Major(2) + Minor(2) + TX(1) | 不可 — 固定21バイト | Appleエコシステムのみ |
| Eddystone-UID | 0x00AA (Google) | Namespace(10) + Instance(6) + TX(1) | 不可 — 固定17バイト | Google Nearby(廃止) |
| Eddystone-TLM | 0x00AA (Google) | Version(1) + Batt(2) + Temp(2) + AdvCnt(4) + SecCnt(4) | 可 — 電池・温度 | Googleエコシステム |
| カスタム(オープン) | 0xXXXX(割当) | 任意のレイアウト — スキーマを自由定義 | 可 — 柔軟 | なし — 独自受信機 |
ほとんどの展開での実用的な推奨:カスタムフレームフォーマットを使用する。24バイトを完全に制御でき、センサーデータをアドバタイジングパケットに直接埋め込め(GATT接続の必要性を排除)、エコシステムの廃止に縛られません(Googleが2021年にNearbyを廃止したように)。
カスタムペイロード設計:24バイトにセンサーを詰め込む
| フィールド | オフセット | サイズ | 範囲/分解能 | 説明 |
|---|---|---|---|---|
| Frame Version | 0 | 1バイト | 0–255 | 前方互換性用プロトコルバージョン |
| Device ID | 1 | 6バイト | 14兆ID | 固有デバイス識別子(MAC由来) |
| Battery Level | 7 | 1バイト | 0–100%(1%分解能) | 符号なし, 0xFF = 利用不可 |
| Temperature | 8 | 1バイト | -40〜+85°C(0.5°C) | Int8, raw = temp × 2 + 40 |
| Humidity | 9 | 1バイト | 0–100%(0.4%分解能) | 符号なし, raw = humidity × 2.55 |
| Accelerometer | 10 | 3バイト | ±16g(0.125g) | 3 × int8, XYZパック |
| Button / Event | 13 | 1バイト | 0–255イベント | ボタン押下/タンパーカウンタ |
| Tamper Flag | 14 | 1バイト | 0 = OK, 1 = tampered | 物理的タンパー状態 |
| TX Power | 15 | 1バイト | -127〜+127 dBm | 符号付きint8, RSSI@1m校正用 |
| Sequence Counter | 16 | 4バイト | 0〜40億 | リプレイ防止、稼働時間推定 |
| Reserved | 20 | 4バイト | — | 将来用/CRC/拡張 |
データを詰め込むエンコードテクニック:
// 温度: -40〜+85°Cを1バイトで(0.5°C分解能)
uint8_t encode_temp(float temp_c) {
int16_t raw = (int16_t)((temp_c + 40.0) * 2.0);
if (raw < 0) raw = 0;
if (raw > 250) raw = 250;
return (uint8_t)raw;
}
float decode_temp(uint8_t raw) {
return (raw / 2.0) - 40.0;
}
// 湿度: 0-100%を1バイトで(0.4%分解能)
uint8_t encode_humidity(float rh) {
return (uint8_t)(rh * 2.55);
}
// 加速度センサー: ±16gを3バイトで(0.125g/LSB)
void encode_accel(float x_g, float y_g, float z_g, uint8_t out[3]) {
out[0] = (uint8_t)(x_g / 0.125 + 128); // 128 = 0g
out[1] = (uint8_t)(y_g / 0.125 + 128);
out[2] = (uint8_t)(z_g / 0.125 + 128);
}
拡張アドバタイジング:BLE 5.0が31バイトの壁を突破
BLE 5.0は拡張アドバタイジングを導入し、ペイロードを31バイトから255バイトに拡張しました。これはセンサービーコンにとって画期的な変更であり、完全なテレメトリ、マルチセンサーデータ、暗号化ペイロード、さらにはファームウェア更新URLをGATT接続なしで単一パケットでブロードキャストできるようになります。
| 機能 | レガシー (4.x) | 拡張 (5.0+) |
|---|---|---|
| 最大ペイロード | 31バイト | 255バイト |
| PHYオプション | 1Mのみ | 1M, 2M, Coded (125k/500k) |
| アドバタイジングセット | 1 | 最大10同時 |
| TX電力レポート | 手動 | AUX_SYNC_INDで自動 |
| RSSI安定性 | ±4 dB標準 | Coded PHYで±2 dB |
ただし普及は限定的で、2025年時点でBLE 5.0拡張アドバタイジングスキャンをサポートするスマートフォンは約60%のみです。コンシューマー向けスマートフォンをターゲットとする場合、レガシーのフォールバックが依然として必要です。インフラグレードの展開(専用ゲートウェイ、RTLSアンカー)では、拡張アドバタイジングが明確な選択です。
アドバタイジング間隔:電池寿命の方程式
アドバタイジング間隔は電池寿命に最も影響するパラメータです。各送信パケットはエネルギーを消費し、間隔が1秒あたりのパケット数を決定します:
// nRF52シリーズのアドバタイジングイベントごとの消費電力
// (3チャネル × 1M PHY, 0 dBm TX電力)
const float TX_CURRENT_MA = 4.6; // 0 dBmでのTX電流
const float TX_TIME_MS = 0.376; // チャネルあたり376 µs
const float SLEEP_CURRENT_UA = 1.5; // System OFF + RTC
// アドバタイジングイベントごとのエネルギー(3チャネル)
float energy_per_event_uC = (TX_CURRENT_MA * 1000) * (TX_TIME_MS * 3 / 1000);
// = 5.19 µC per event
// 100 ms間隔の平均電流(10イベント/秒)
float avg_current_100ms_uA = (5.19 * 10) + 1.5;
// = 53.4 µA
// 1000 ms間隔の平均電流(1イベント/秒)
float avg_current_1s_uA = (5.19 * 1) + 1.5;
// = 6.69 µA
// CR2477電池: 1000 mAh
// 100 ms間隔: 約781日
// 1000 ms間隔: 約6235日(理論値)
| 間隔 | 平均電流 | CR2477 (1000 mAh)寿命 | 検出レイテンシ | 用途 |
|---|---|---|---|---|
| 100 ms | 53.4 µA | 約26ヶ月 | ≤100 ms | RTLS, リアルタイム追跡 |
| 300 ms | 18.8 µA | 約71ヶ月 | ≤300 ms | 小売, インタラクティブ |
| 1000 ms | 6.7 µA | 約6年* | ≤1 s | 資産追跡, テレメトリ |
| 5000 ms | 2.5 µA | 約16年* | ≤5 s | コールドチェーン, 低消費電力 |
*理論値 — CR電池の自己放電により、実用的な寿命は電流消費に関わらず5〜7年に制限されます。
重要な洞察:間隔を倍にしても電池寿命は半分になりません。スリープ電流(1.5 µA)は固定のフロアです。100 msではTXが支配的(51.9 µA vs 1.5 µA)。5000 msではスリープが支配的(1.0 µA TX vs 1.5 µA)。TX電流がスリープ電流と等しくなるクロスオーバーポイントは約3.5秒で、それを超えると間隔延長の効果は逓減します。
衝突確率:ビーコンが多すぎる時
密集展開(倉庫、病院、カンファレンスホール)では、数百のビーコンが同じ3つのアドバタイジングチャネル(37, 38, 39)を共有します。各ビーコンは3チャネルすべてで同時に送信します。2つの送信が同じチャネルで時間的に重なると、両方のパケットが破損します — 衝突です。
衝突確率は修正ALOHAモデルに従います:
import math
def collision_prob(n_beacons, interval_ms, packet_time_us=376):
T = packet_time_us / 1e6
I = interval_ms / 1e3
load = n_beacons * T / I
p_collision = 1 - math.exp(-2 * load)
return p_collision
# 例:
# 50ビーコン, 1000 ms間隔: P = 3.7%
# 200ビーコン, 1000 ms間隔: P = 14.0%
# 200ビーコン, 300 ms間隔: P = 39.7%
# 500ビーコン, 1000 ms間隔: P = 31.3%
| ビーコン数 | 間隔 | チャネル負荷 | P(衝突) | P(1回スキャンで受信)* |
|---|---|---|---|---|
| 50 | 1000 ms | 1.9% | 3.7% | 96.3% |
| 200 | 1000 ms | 7.5% | 14.0% | 86.0% |
| 200 | 300 ms | 25.1% | 39.7% | 60.3% |
| 500 | 1000 ms | 18.8% | 31.3% | 68.7% |
| 500 | 300 ms | 62.7% | 71.5% | 28.5% |
*1秒間のスキャンウィンドウ中に少なくとも1つのクリーンパケットを受信する確率。
密集展開の緩和戦略:
- ランダムジッター:各ビーコンの間隔に±20%のランダムジッターを追加。送信タイミングを非相関化し、周期的衝突パターンを打破。実際のP(衝突)を30〜50%削減。
- 適応間隔:ビーコンが混雑を検出し(隣接ビーコンからの受信パケット数でカウント)、バックオフ。CSMA/CAに類似するがコネクションレス広告向け。
- チャネル優先:一部の実装はチャネル37(Wi-Fiチャネル1との重複で最も混雑)をスキップし、38+39のみで広告。検出確率を犠牲にWi-Fi干渉を削減。
- 拡張アドバタイジング:BLE 5.0セカンダリチャネルは37のデータチャネルのいずれかで動作し、3つのプライマリチャネルよりはるかに薄く負荷を分散。
マルチフレームアドバタイジング:ペイロードのローテーション
単一の31バイトパケットに収まらないデータをブロードキャストする場合や、検出レイテンシとテレメトリ鮮度のバランスを取りたい場合、フレームローテーションを使用します。ビーコンは連続するアドバタイジングイベントで異なるフレームタイプを循環します:
| スロット | フレームタイプ | 内容 | 目的 |
|---|---|---|---|
| 1(毎回) | IDフレーム | Device ID + TX + seq | 高速検出, RSSI測距 |
| 2(3回に1回) | テレメトリ | 電池 + 温度 + 湿度 | 環境モニタリング |
| 3(10回に1回) | 加速度 | XYZ + イベントカウンタ + タンパー | 移動/衝撃検出 |
| 4(30回に1回) | 情報 | FWバージョン + 設定ハッシュ | OTA管理, フリート監査 |
1000 msベース間隔で、IDフレームは毎秒、テレメトリは3秒ごと、加速度は10秒ごと、情報は30秒ごとに送信されます。3秒間リスニングするスキャナはIDとテレメトリの両方を捕捉し、10秒スキャンで情報フレーム以外のすべてを捕捉します。このアプローチは実質的に4つの論理ビーコンを1つの物理デバイスに多重化し、電池オーバーヘッドを最小限に抑えます。
結論
アドバタイジングパケット設計はビーコン展開で最もレバレッジの高いエンジニアリング決定です。よく設計されたペイロードはGATT接続を排除し、スキャナの滞留時間を短縮し、電池寿命を桁違いに延ばします。原則はシンプルです:IDとテレメトリを可能な限り小さなフットプリントに詰め込み、オーバーフローにはフレームローテーションを使用し、密集展開に耐えるためジッターを追加し、レイテンシ予算に合う間隔を選択する — 早すぎない間隔を。
ほとんどの資産追跡・環境モニタリング展開にとって、最適値は1000 ms間隔で±20%ジッター、4スロットフレームローテーションを備えたカスタム24バイトレガシーフレームです。この構成は6秒の検出レイテンシ(99パーセンタイル)、CR2477で5年以上の電池寿命、ゾーンあたり200ビーコンまで5%未満の衝突率を実現します — 市販のiBeacon構成では到達できない数値です。
BLEビーコンは、ブロードキャストするバイト数と同じだけの効果しかありません。展開を設計する前にパケットを設計してください。