Seeed Studio XIAO ESP32C6 でBLEビーコンを試してみる(6)
この記事では、Seeed Studio XIAO ESP32C6を使って、MicroPythonからBluetooth Low Energy(BLE)のiBeacon形式のBLEビーコンを発信し、スマートフォンからビーコンを検出してみます。
この記事で学べること
- iBeaconとは?
- UUID、Major、Minor
- MicroPythonのコード例
- スマートフォンでの確認方法
ステップごとの解説
- 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
└── 店舗内のエリア
というような使い方ができます。
- 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
という構造になります。
- 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が続きます。
- Apple Company ID
最初の
4C 00
は、AppleのCompany Identifierです。
ここは少し注意が必要です。
Company Identifierとしては、
0x004C
ですが、Advertisingデータでは、
4C 00
というバイト順で格納されます。
そのため、nRF ConnectなどでManufacturer Dataを見ると、
4C 00
と表示されます。
- iBeacon Type
続く、
02 15
は、iBeaconを識別するための固定値です。
02 15
を見つけることで、スキャナなどはAdvertisingデータをiBeacon形式として解釈できます。
つまり、
4C 00
02 15
の部分を見ると、
Apple
↓
iBeacon
というデータであることが分かります。
- UUID
次の16バイトがUUIDです。
今回は、
12345678-1234-1234-1234-123456789ABC
を使用します。
UUIDはiBeaconを大きなグループとして識別するために使用できます。
例えば、会社が複数の店舗にビーコンを設置する場合、
UUID
↓
会社全体
Major
↓
店舗
Minor
↓
店舗内の場所
というような階層構造にできます。
UUID、Major、Minorの具体的な意味は、ビーコンを利用する側が決めることができます。
- MajorとMinor
MajorとMinorは、それぞれ2バイトの値です。
今回は、
Major = 1
Minor = 1
とします。
16進数では、
Major
00 01
Minor
00 01
となります。
例えば、次のように設定することもできます。
UUID
会社
Major
店舗番号
Minor
エリア番号
このようにすると、同じUUIDを使用していても、MajorとMinorによって個々のビーコンを区別できます。
- TX Power
最後の1バイトがTX Powerです。
例えば、
-59
を設定すると、符号付き8ビット値として、
C5
になります。
この値は、ビーコンから約1m離れた位置で受信した場合のRSSIを基準とする**測定送信電力(Measured Power)**として利用され、受信側が距離の目安を推定するために使われます。
ただし、RSSIは周囲の環境やアンテナの向きなどによって変化するため、これだけで正確な距離を測定できるわけではありません。
- 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
- VSCodeで以前、作ったプロジェクトを選択する
VSCodeを起動して、以前、作ったプロジェクトを選択します。

- エディタで新しいファイルを作成する
左側のエクスプローラにて右クリックして、「新しいファイル」を選択します。ファイル名を入力する欄が表示されるので、適当に名前を入力します。今回は、「ibeacon.py」としました。

- 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
- 下記コードをエディターで記入する
「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)
- プログラムを確認する
今回のプログラムでは、まず、
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を追加します。
- 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でもそのまま使われていることが分かります。
- 「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
- 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 を使用します。
- iOS版nRF Connectで表示されなかった原因について
今回、AppleのCompany ID(0x004C)を使用したiBeaconデータは、Android版nRF Connectでは正常に解析されましたが、iOS版では期待した情報が表示されませんでした。
この現象について調べたところ、Nordic DevZoneにも、AppleのCompany ID0x004Cを使用すると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形式のビーコン発信まで進めることができました。
