This post shows steps to create an iBeacon with Raspberry Pi, by modifying BlueZ BLE Advertisement example code (i.e. “example-advertisement“).
Note:
Even though it uses Bluetooth Low Energy standard, iBeacon is Apple’s proprietary protocol and making/deploying iBeacon devices requires the license from Apple [1]. The scope of this post is limited to getting familiar with BlueZ advertising example code and iBeacon format for experimental purpose.
*If you want to create AltBeacon [2], which is kind of an open source version of iBeacon, please see this post.
Prerequisites (parentheses indicate my environment)
- Raspberry Pi (Raspberry Pi4 B with Raspbian Buster 2019-06-20)
- Internet access
To download BlueZ example code. Here is a Wi-Fi Setup steps. If you downloaded already, you can work offline.
Steps
1. Downloading BlueZ
1-1. Download BlueZ source code archive.
wget www.kernel.org/pub/linux/bluetooth/bluez-5.50.tar.xz
1-2. Extract the archive file.
tar xvf bluez-5.50.tar.xz
1-3. Make sure that the sample code works. [Optional]
./bluez-5.50/test/example-advertisement
Output should be like this:
$ ./bluez-5.50/test/example-advertisement
GetAll
returning props
Advertisement registered
2. Modify BLE Advertisement Example Code
2-1. Copy the example code.
cp ./bluez-5.50/test/example-advertisement ./example-ibeacon
2-2. Open the file and look for TestAdvertisement class.
2-3. Replace ‘__init__’ method:
def __init__(self, bus, index):
Advertisement.__init__(self, bus, index, 'peripheral')
self.add_service_uuid('180D')
self.add_service_uuid('180F')
self.add_manufacturer_data(0xffff, [0x00, 0x01, 0x02, 0x03, 0x04])
self.add_service_data('9999', [0x00, 0x01, 0x02, 0x03, 0x04])
self.add_local_name('TestAdvertisement')
self.include_tx_power = True
self.add_data(0x26, [0x01, 0x01, 0x00])
with:
def __init__(self, bus, index):
company_id = 0x004C
beacon_type = [0x02, 0x15]
uuid = [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16]
major = [0x11, 0x22]
minor = [0x33, 0x44]
tx_power = [0xB3]
Advertisement.__init__(self, bus, index, 'peripheral')
self.add_manufacturer_data(company_id, beacon_type + uuid + major + minor + tx_power)
3. Test
3-1. Run the code. The console output should be same as Step 1-3.
./example-ibeacon
3-2. Find your ibeacon running on Raspberry Pi using a beacon scanner app. I used nRF Connect on an Android phone.
Summary
If everything goes well, the Raspberry Pi should be broadcasting iBeacon message and you can find it with a scanner app. Some of the iBeacon data can be configured on Step 2-3 for your application. Here is a brief explanation of those data.
- ‘company_id’
Company Identifiers are defined by Bluetooth SIG [3]. For iBeacon, it must be Apple’s ID (i.e. 0x004C).
- ‘beacon_type’
It must be ‘0x0215’ which means Proximity Beacon.
- ‘uuid’
Proximity UUID is an application unique ID.
- ‘major‘ and ‘minor‘
Major Number and Minor Number are application dependent values which can be used to identify more precise location, etc.
- ‘tx_power’
Tx Power is a device dependent value. It must be calibrated for each device when it’s deployed.
iBeacon and AltBeacon have the similar functionality and data structure as below.
*2 : Bluetooth 4.0 Core Specification, Volume 3, Part C, Appendix C, 18.1 Flags
*4 : Manufacture dependent value
*5 : Application dependent value
*6 : Device dependent value
References
[1] iBeacon – Apple Developer
[2] AltBeacon
[3] Company Identifiers – Bluetooth SIG
[4] BlueZ Release Notes