pythonbluetoothbeaconeddystone

How to create EddyStone Beacon using BlueZ and Python?


I'm working on BLE(BlueTooth Low Energy) on an Embedded Linux board. We use BlueZ and Python. I need to create EddyStone Beacon. I found there is a way to create iBeacon: https://scribles.net/creating-ibeacon-using-bluez-example-code-on-raspberry-pi/. I tried it. It worked. But we need to create EddyStone Beacon. So I use the Beacon data format from here(https://ukbaz.github.io/howto/beacon_scan_cmd_line.html) to create the manufacturer data. But my code doesn't work. What is wrong with my code? Here is my code:

def __init__(self, bus, index):
    eddystone_id = 0xAAFE
    beacon_type = [0x14, 0x16]  # Length = 0x14, EddyStone type = 0x16
    uuid = [0xAA, 0xFE] # EddyStone UUID = 0xAAFE
    frame_type = [0x10] # Frame Type = 0x10
    power = [0x00]      # Power = 0x00
    prefix = [0x02]     # URL scheme = 0x02 (http://)
    url = [0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x07]

    Advertisement.__init__(self, bus, index, 'peripheral')
    self.add_manufacturer_data(eddystone_id, beacon_type + uuid + frame_type + power + prefix + url)
    

However, if I use this command, the EddyStone Beacon is created. I can see it shows EddyStone Beacon in nRF mobile app:

sudo hcitool -i hci0 cmd 0x08 0x0008 1c 02 01 06 03 03 aa fe 14 16 aa fe 10 00 02 73 61 6d 70 6c 65 77 65 62 73 69 74 65 07 00 00 00

As you can see, the data I put in the add_manufacturer_data() function is the same as the data in the command. But why the Python code doesn't work?


Solution

  • iBeacon uses manufacturer_data while Eddystone beacons use service_data so I would expect your code to look more like this:

        def __init__(self, bus, index):
            Advertisement.__init__(self, bus, index, 'broadcast')
            self.add_service_uuid('FEAA')
            frame_type = [0x10] # Eddystone frame Type = 0x10
            power = [0x00]      # Beacon broadcast power = 0x00
            prefix = [0x02]     # URL scheme = 0x02 (http://)
            url = [0x73, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x77, 0x65, 0x62, 0x73, 0x69, 0x74, 0x65, 0x07]
            eddystone_data = frame_type + power + prefix + url
            self.add_service_data('FEAA', eddystone_data)
    

    As a side note, hcitool is one of the tools that has been deprecated by the BlueZ developers. The currently supported way to create the Eddystone beacon from the command line would be with bluetoothctl. The sequence of commands would be:

    bluetoothctl 
    menu advertise
    uuids 0xFEAA
    service 0xFEAA 0x10 0x00 0x02 0x73 0x61 0x6D 0x70 0x6C 0x65 0x77 0x65 0x62 0x73 0x69 0x74 0x65 0x07
    back
    advertise broadcast
    discoverable on
    

    I changed the advertisement type from peripheral to broadcast because typically people don't want beacons to be connectable, but it depends on your application.