3

I'd like to ask whether it is possible to access the raw advertisement data from a custom BLE device built using a Raspberry Pi from the Core Bluetooth API?

The use case is to broadcast constantly changed data from the Raspberry Pi to multiple iOS devices in the proximity and consume them in an iOS app. See the topology description in this article.

I already found out that the iBeacon advertisements are filtered out from the Core Bluetooth API and are only accessible from the Core Location API only, which requires the knowledge of the UUID. Due to the constantly changed data a custom iBeacon wouldn't work for this particular use case anyway. But I am unsure whether I could achieve that with Core Bluetooth?

Lukáš Kubánek
  • 946
  • 1
  • 15
  • 27

2 Answers2

3

You can do what you want if you change the Raspberry Pi to transmit a non-iBeacon format. CoreBluetooth only filters out the raw bytes of advertisements if they are iBeacon advertisements. See here: Obtaining Bluetooth LE scan response data with iOS

A simple solution is to change your iBeacon advertisement to an open-source AltBeacon advertisement. CoreLocation will no longer pick it up, but CoreBluetooth will.

Here's an example of what you get in the advertisementData NSDictionary in the CoreBluetooth centralManager:didDiscoverPeripheral:advertisementData:RSSI: callback. This example is the result of detecting an AltBeacon advertisement (an open-source beacon standard), with identifiers 2F234454-CF6D-4A0F-ADF2-F4911BA9FFA6 1 2:

{
    kCBAdvDataIsConnectable = 0;
    kCBAdvDataManufacturerData = <1801beac 2f234454 cf6d4a0f adf2f491 1ba9ffa6 00010002 be00>;
}

You can see how to decode the above bytes by looking at the AltBeacon spec here. Note that the above are the actual contents of the NSDictionary for a detected advertisement on iOS8 that were printed to the console using an NSLog statement.

Community
  • 1
  • 1
davidgyoung
  • 63,876
  • 14
  • 121
  • 204
  • Well, I asked this question to clarify whether this is possible for a non-iBeacon format, because most people don't distinguish between BLE devices and iBeacons. I am a little bit confused because @l0gg3r (the author of the other answer) says that the advertisement data are filtered out for all BLE devices... So is that wrong? – Lukáš Kubánek Nov 16 '14 at 15:05
  • I see you've also updated your other answer, which confused me as well: http://stackoverflow.com/a/22837799/670119 – Lukáš Kubánek Nov 16 '14 at 15:08
  • Here is a copy from Apple doc "Although advertising packets in general can hold a variety of information about the peripheral device, you may advertise only your device’s local name and the UUIDs of any services you want to advertise. That is, when you create your advertising dictionary, you may specify only the following two keys: CBAdvertisementDataLocalNameKey and CBAdvertisementDataServiceUUIDsKey." – l0gg3r Nov 16 '14 at 15:32
  • But the "copy from Apple doc" you reference is about *transmitting* from an iOS device. In your question, you are asking about transmitting from a Raspberry Pi and *receiving* from an iOS device. So I don't think that copy applies. – davidgyoung Nov 16 '14 at 15:39
  • @davidgyoung on iOS 7 the data was filtered, i think on iOS8 that will be filtered too – l0gg3r Nov 16 '14 at 16:29
  • 1
    I just tested this and confirmed the raw advertisement bytes *are not filtered* on iOS8 for non-iBeacon advertisements. See my edited answer where I have pasted the actual results of scanning for an AltBeacon and reading the raw bytes on an iOS 8 device. To reproduce, please run modify your transmitter to send a non-iBeacon advertisement and use the example code to detect it from this blog post: http://developer.radiusnetworks.com/2013/10/21/corebluetooth-doesnt-let-you-see-ibeacons.html – davidgyoung Nov 16 '14 at 16:49
  • @davidgyoung Many thanks for doing the test and confirming that the advertisement data is not filtered out. I accepted your answer. – Lukáš Kubánek Nov 16 '14 at 18:36
  • @l0gg3r May that behavior have changed from iOS 7 to iOS 8? – Lukáš Kubánek Nov 16 '14 at 18:38
  • @davidgyoung replacing iBeacons with AltBeacons is not a good idea on iOS. you will loose functionality like - 'background monitoring/ranging', 'killed state monitoring/ranging' – l0gg3r Nov 17 '14 at 07:02
  • @I0gg3r, in general, you are correct that using AltBeacon on iOS has the disadvantage of losing `CoreLocation` support you mention. However in this use case, the UUID is changing constantly, making `CoreLocation` unworkable. – davidgyoung Nov 17 '14 at 12:20
  • i am also getting the data in kCBAdvDataManufacturerData = ... so how to fetch data from it ? do you have any other way to decode it ? or any method ? @davidgyoung ? – Moxarth Aug 23 '17 at 11:17
  • You should open a new question, @Moxarth. Not enough room to answer here. – davidgyoung Aug 23 '17 at 11:42
  • @davidgyoung i have raised the question - [https://stackoverflow.com/questions/45854508/in-ios-how-to-decode-the-received-advertisement-data-from-ble-device-in-kcbadv] . please guide me through it . – Moxarth Aug 24 '17 at 06:38
2

Quick answer is "there is no direct way".

Why:
Because CoreBluetooth filters out advertisement data, except kCBAdvDataServiceUUIDs, kCBAdvDataLocalName, so there is now way to pass custom data from peripheral to central via advertising.

How can we workaround:
Peripheral
1) Holds some custom service (let's name it 'BeaconService').
2) BeaconService contains Beacon's UUID, major, minor characteristics.
3) Advertises BeaconService UUID (via kCBAdvDataServiceUUIDs key).

Central
1) Scans for peripherals that have BeaconService UUID.
2) Found peripherals are queued.
3) Connection is opened to queued peripherals, and the iBeacon information is read from BeaconService.
4) Read values can be used to start CoreLocation beacon monitoring/ranging.

So by this way you can make bridge from CoreBluetooth to CoreLocation.

l0gg3r
  • 8,864
  • 3
  • 26
  • 46
  • But can you get those characteristics data without establishing a connection with the peripheral i.e. only from the advertisement? (This question is actually not about iBeacons, I don't need any proximity UUID but a custom generated data.) – Lukáš Kubánek Nov 16 '14 at 13:14
  • what we are doing, advertising our service UUID from peripheral side, so the central scans only for peripherals that have the specific serviceUUID, after that we are queueing that peripherals, and reading beacon characteristics. – l0gg3r Nov 16 '14 at 13:16
  • 1
    so yes, we are connecting to that peripherals – l0gg3r Nov 16 '14 at 13:17
  • I see. But do you have to connect to the peripheral or do you simply get the data during the scan process? – Lukáš Kubánek Nov 16 '14 at 13:20
  • yea.. we are connecting, there is no way. Apple filters out advertising data. – l0gg3r Nov 16 '14 at 13:22
  • So the filtering of advertisement data is done not only for iBeacons but for all BLE devices? – Lukáš Kubánek Nov 16 '14 at 13:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/65031/discussion-between-lukas-kubanek-and-l0gg3r). – Lukáš Kubánek Nov 16 '14 at 13:26
  • 1
    I think this answer is correct *only* for iBeacon advertisements. For non-iBeacon advertisements, the data *are not* filtered by `CoreBluetooth` on iOS. See my answer with included proof. – davidgyoung Nov 16 '14 at 17:00