Seeed Studio XIAO ESP32C6 でBLEビーコンを試してみる(6)

この記事では、Seeed Studio XIAO ESP32C6を使って、MicroPythonからBluetooth Low Energy(BLE)のiBeacon形式のBLEビーコンを発信し、スマートフォンからビーコンを検出してみます。

この記事で学べること

  • iBeaconとは?
  • UUID、Major、Minor
  • MicroPythonのコード例
  • スマートフォンでの確認方法

ステップごとの解説

  1. iBeacon形式のBLEビーコンを作ってみる
    前回は、XIAO ESP32C6からManufacturer Specific Dataを使って、独自のデータをBLE Advertisingとして発信しました。
    今回はさらに一歩進めて、BLEビーコンでよく使われるiBeacon形式のAdvertisingをXIAO ESP32C6から発信してみます。

    iBeaconとは?
    iBeaconは、Appleが提供するBLEを利用したビーコンの仕組みです。
    iBeaconでは、BLE AdvertisingのManufacturer Specific Dataに、ビーコンを識別するための情報を格納して発信します。
    iBeaconの識別には、主に次の3つの値を使用します。
    ・UUID
    ・Major
    ・Minor
    Appleの資料では、UUID、Major、Minorによってビーコンを階層的に識別する方法が説明されています。
    例えば、
UUID
└── 店舗全体

Major
└── 店舗

Minor
└── 店舗内のエリア

というような使い方ができます。

  1. iBeaconのAdvertisingデータ
    iBeaconは、前回使用したManufacturer Specific Dataを利用します。
    Manufacturer Specific DataのAD Typeは、
FF

です。
そして、その中にiBeacon用のデータを格納します。
iBeaconの基本的なデータ構造は次のようになっています。

Company ID
iBeacon Type
UUID
Major
Minor
TX Power

Advertising Data全体として見ると、

Length
AD Type
Company ID
iBeacon Type
UUID
Major
Minor
TX Power

という構造になります。

  1. iBeaconのデータ構造
    今回使用するデータを具体的に見てみます。
    例えば、次のような値を設定します。
UUID  : 12345678-1234-1234-1234-123456789ABC
Major : 1
Minor : 1
TX Power : -59

すると、Manufacturer Specific Dataは概念的に、

4C 00
02 15
12 34 56 78 12 34 12 34 12 34 12 34 56 78 9A BC
00 01
00 01
C5

となります。
それぞれの意味は次のとおりです。

データ

サイズ

内容

4C 00

2 bytes

Apple Compnay ID

02 15

2 bytes

iBeacon識別子

UUID

16 bytes

ビーコンを識別するUUID

Major

2 bytes

グループ識別用

Minor

2 bytes

個別識別用

TX Power

1 byte

基準となる送信電力

AppleのiBeaconでは、Manufacturer Specific Dataの先頭にAppleのCompany Identifier 0x004Cが入り、iBeaconの識別情報としてUUID、Major、Minor、TX Powerが続きます。

  1. Apple Company ID
    最初の
4C 00

は、AppleのCompany Identifierです。
ここは少し注意が必要です。
Company Identifierとしては、

0x004C

ですが、Advertisingデータでは、

4C 00

というバイト順で格納されます。
そのため、nRF ConnectなどでManufacturer Dataを見ると、

4C 00

と表示されます。

  1. iBeacon Type
    続く、
02 15

は、iBeaconを識別するための固定値です。

02 15

を見つけることで、スキャナなどはAdvertisingデータをiBeacon形式として解釈できます。
つまり、

4C 00
02 15

の部分を見ると、

Apple
  ↓
iBeacon

というデータであることが分かります。

  1. UUID
    次の16バイトがUUIDです。
    今回は、
12345678-1234-1234-1234-123456789ABC

を使用します。
UUIDはiBeaconを大きなグループとして識別するために使用できます。
例えば、会社が複数の店舗にビーコンを設置する場合、

UUID
↓
会社全体

Major
↓
店舗

Minor
↓
店舗内の場所

というような階層構造にできます。
UUID、Major、Minorの具体的な意味は、ビーコンを利用する側が決めることができます。

  1. MajorとMinor
    MajorとMinorは、それぞれ2バイトの値です。
    今回は、
Major = 1
Minor = 1

とします。
16進数では、

Major
00 01

Minor
00 01

となります。
例えば、次のように設定することもできます。

UUID
会社

Major
店舗番号

Minor
エリア番号

このようにすると、同じUUIDを使用していても、MajorとMinorによって個々のビーコンを区別できます。

  1. TX Power
    最後の1バイトがTX Powerです。
    例えば、
-59

を設定すると、符号付き8ビット値として、

C5

になります。
この値は、ビーコンから約1m離れた位置で受信した場合のRSSIを基準とする**測定送信電力(Measured Power)**として利用され、受信側が距離の目安を推定するために使われます。
ただし、RSSIは周囲の環境やアンテナの向きなどによって変化するため、これだけで正確な距離を測定できるわけではありません。

  1. Seeed Studio XIAO ESP32C6をPCに接続する
    Seeed Studio XIAO ESP32C6とPCをUSBケーブルで接続します。接続できているか確認します。
ls -l /dev/tty.usbmodem*
crw-rw-rw-  1 root  wheel  0x9000004 10月 10 14:43 /dev/tty.usbmodem11101
  1. VSCodeで以前、作ったプロジェクトを選択する
    VSCodeを起動して、以前、作ったプロジェクトを選択します。
  1. エディタで新しいファイルを作成する
    左側のエクスプローラにて右クリックして、「新しいファイル」を選択します。ファイル名を入力する欄が表示されるので、適当に名前を入力します。今回は、「ibeacon.py」としました。
  1. XIAO ESP32C6からiBeaconを発信する
    それでは、実際にXIAO ESP32C6からiBeacon形式のAdvertisingを発信してみます。
    MicroPythonでは、bluetooth.BLE()でBLEを初期化し、gap_advertise()でAdvertisingを開始できます。gap_advertise()のAdvertising間隔はマイクロ秒単位で指定します。
    今回使用する設定は次のとおりです。
UUID
12345678-1234-1234-1234-123456789ABC

Major
1

Minor
1

TX Power
-59
  1. 下記コードをエディターで記入する
    「ibeacon.py」を選択すると、エディター画面が開くので、下記コードを記入して保存します。
import bluetooth
import time

# BLEを初期化
ble = bluetooth.BLE()
ble.active(True)

# iBeacon parameters
uuid = bytes.fromhex(
    "12345678123412341234123456789ABC"
)

major = 1
minor = 1
tx_power = -59

# iBeacon Manufacturer Specific Data
ibeacon_data = bytearray()

# Apple Company ID
ibeacon_data += b"\x4C\x00"

# iBeacon type and length
ibeacon_data += b"\x02\x15"

# UUID
ibeacon_data += uuid

# Major
ibeacon_data += major.to_bytes(2, "big")

# Minor
ibeacon_data += minor.to_bytes(2, "big")

# TX Power
ibeacon_data += bytes([tx_power & 0xFF])

# Advertising Data
adv_data = bytearray()

# Flags
adv_data += b"\x02\x01\x06"

# Manufacturer Specific Data
adv_data += bytes([len(ibeacon_data) + 1, 0xFF])
adv_data += ibeacon_data

# Advertising開始
ble.gap_advertise(
    100000,
    adv_data=adv_data
)

print("iBeacon Advertising started")

while True:
    time.sleep(1)
  1. プログラムを確認する
    今回のプログラムでは、まず、
uuid = bytes.fromhex(
    "12345678123412341234123456789ABC"
)

で、UUIDを16バイトのデータに変換しています。
次に、

ibeacon_data += b"\x4C\x00"

で、AppleのCompany IDを追加します。
続いて、

ibeacon_data += b"\x02\x15"

でiBeaconの識別情報を追加します。
その後、

ibeacon_data += uuid

で、UUIDを追加します。
MajorとMinorは、

ibeacon_data += major.to_bytes(2, "big")
ibeacon_data += minor.to_bytes(2, "big")

として、それぞれ2バイトのビッグエンディアンで追加しています。
最後に、

ibeacon_data += bytes([tx_power & 0xFF])

でTX Powerを追加します。

  1. Advertisingデータを確認する
    今回のiBeaconデータは、Manufacturer Specific Dataとして、
4C 00
02 15
12 34 56 78 12 34 12 34 12 34 12 34 56 78 9A BC
00 01
00 01
C5

となります。
これを1行にすると、

4C 00 02 15 12 34 56 78 12 34 12 34 12 34 12 34 56 78 9A BC 00 01 00 01 C5

です。
このデータは25バイトあります。

Apple Company ID   2 bytes
iBeacon identifier 2 bytes
UUID               16 bytes
Major              2 bytes
Minor              2 bytes
TX Power           1 byte
────────────────────────────
合計               25 bytes

さらにAdvertisingのAD TypeであるFFが1バイトあるため、Lengthは、

25 + 1 = 26

となります。
26を16進数で表すと、

1A

です。
したがって、Advertising Data全体の該当部分は、

1A FF 4C 00 02 15
12 34 56 78 12 34 12 34 12 34 12 34 56 78 9A BC
00 01
00 01
C5

となります。
ここまで分かると、前回のManufacturer Specific Dataの記事で説明した、

Length
AD Type
Manufacturer Data

という構造が、iBeaconでもそのまま使われていることが分かります。

  1. 「ibeacon.py」を実行する
    左のエクスプローラにて、「ibeacon.py」を選択して、右クリックから、「Run current file on Pico」をクリックすると、REPL画面に下記のように、iBeacon Advertising startedが表示されます。
MicroPython v1.29.0 on 2026-08-24; Seeed XIAO ESP32C6 with ESP32-C6
Type "help()" for more information or .help for custom vREPL commands.

>>> 
iBeacon Advertising started
  1. nRF Connectで確認する
    XIAO ESP32C6でプログラムを実行したら、スマートフォンのnRF ConnectでBLE機器をスキャンします。

AppleのCompany IDである 0x004C を使用してiBeaconのAdvertisingデータを送信しました。Advertisingデータは正常に生成されており、データ長は30バイトでした。しかし、iOS版では、Manufacturer Dataは表示されませんでした。
そこで、切り分けのためにCompany IDを実験用の 0x1234 に変更し、再度確認しました。

その結果、iOS版nRF ConnectでもManufacturer Dataが表示され、UUID、Major、Minorなどのデータを確認できました。
一方、Android版nRF Connectでは、下図のとおり、Company IDに 0x004C を使用した場合でも、iBeaconとして正しく解析されることを確認できました。

このデバイスをタップすると、下図のように設定したManufacturer Dataが表示されることを確認しました。

<004C> 0215 ← <Company ID> ibeacon識別情報
12345678 1234 1234 1234 123456789ABC ← UUID
0001 ← Major
0001 ← Minor
C5 ← RSSI

のような内容です。
今回の実験では、Company IDの変更によってiOS版での表示結果に違いが生じました。ただし、その原因がCompany ID自体にあるのか、アプリ側の解析・表示処理などにあるのかは、今回の実験だけでは特定できていません。
なお、0x1234 は今回の動作確認に使用した実験用の値です。実際のiBeaconでは、AppleのCompany IDである 0x004C を使用します。

  1. iOS版nRF Connectで表示されなかった原因について
    今回、AppleのCompany ID(0x004C)を使用したiBeaconデータは、Android版nRF Connectでは正常に解析されましたが、iOS版では期待した情報が表示されませんでした。
    この現象について調べたところ、Nordic DevZoneにも、AppleのCompany ID 0x004C を使用するとiOS版nRF ConnectでiBeaconの情報が表示されず、別のCompany IDでは表示されるという報告がありました。
    回答では、iOSが特定のアプリに対してデータをフィルタリングしている可能性が指摘されています。
    今回の実験でも、Company IDを 0x1234 に変更するとiOS版でManufacturer Dataが表示されました。このことから、送信データの生成だけでなく、受信アプリ側の解析・表示処理も確認する必要があると考えられます。
    ただし、今回の実験では表示されなかった原因を特定できていないため、iOSやnRF Connectの仕様によるものと断定することはできません。

    参考: Nordic DevZone — IOS doesn’t show uuid, major and minor in iBeacon

まとめ

今回は、Manufacturer Specific Dataを利用して、XIAO ESP32C6からiBeacon形式のAdvertisingを発信しました。
iBeaconでは、

Company ID
     ↓
iBeacon識別子
     ↓
UUID
     ↓
Major
     ↓
Minor
     ↓
TX Power

という構造でデータを送信します。
今回使用した値は、

UUID
12345678-1234-1234-1234-123456789ABC

Major
1

Minor
1

TX Power
-59

です。
これまでの実験を振り返ると、

BLE
 │
 └─ Advertising
      │
      ├─ Local Name
      │
      └─ Manufacturer Specific Data
             │
             └─ iBeacon
                  │
                  ├─ UUID
                  ├─ Major
                  ├─ Minor
                  └─ TX Power

という関係になります。
これで、単純なBLE Advertisingから始めて、Manufacturer Specific Dataを使った独自データの送信、そしてiBeacon形式のビーコン発信まで進めることができました。

類似投稿