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.
References
[1] iBeacon – Apple Developer
[2] AltBeacon
[3] Company Identifiers – Bluetooth SIG
[4] BlueZ Release Notes