Creating iBeacon with Raspberry Pi using BlueZ Example Code (updated)

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