AccessorySetupKit: Usage of manufacturer data blob

We want to use AccessorySetupKit to pair our BLE accessories. However, currently all our products announce the same BLE service UUID. The manufacturer data is different for every product.

I try to pair our products with ASK and create the ASDiscoveryDescriptor with the expected manufacturer data:

let descriptorA = ASDiscoveryDescriptor()
descriptorA.bluetoothServiceUUID = CBUUID("CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2") // same
descriptorA.bluetoothManufacturerDataBlob = Data([0xd2, 0x0a, 0x00, /* A */ 0x2a, 0x00, 0x00, 0x00]) // different
descriptorA.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff,         0xff, 0xff, 0xff, 0xff])

let descriptorB = ASDiscoveryDescriptor()
descriptorB.bluetoothServiceUUID = CBUUID("CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2") // same
descriptorB.bluetoothManufacturerDataBlob = Data([0xd2, 0x0a, 0x00, /* B */ 0x2b, 0x00, 0x00, 0x00]) // different
descriptorB.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff,         0xff, 0xff, 0xff, 0xff])

However, it seems random which device is found, as if the service UUID is the primary key to handle things in ASK.

My questions are:

  • Is it possible to use only manufacturer data to distinguish between different products with the same service UUID?
  • How do I use bluetoothManufacturerDataMask properly? I assume that internally some filtering like this is done: DataBlob & DataMask == ReceivedManufacturerData & DataMask. Because of that I have set all bits of the mask to 1. Should this e done differently?
Answered by Engineer in 792709022

thanks @melle for the last piece of info. Your plist looks almost perfect, but you're missing the NSAccessorySetupBluetoothCompanyIdentifiers key to indicate what manufacturer ID's you would like to scan for (https://developer.apple.com/documentation/bundleresources/information_property_list/nsaccessorysetupbluetoothcompanyidentifiers/)

In your case, you need to specify an array of 1 string, "0ad2".

Adding this to the plist will allow us to send you the data that we found.

Please let me know if that helps.

Thanks.

Hi @melle and thanks for reaching out !

From initial inspection of your payload, looks like the total bytes there are 32 and not 31 as defined by the BT spec. Can you please confirm ?

Also, just to clarify - the manufacturer blob/mask only applies to the manufacturer data following the manufacturer ID.

For example, if your manufacturer ID is 0x1010, your payload may be 0x01, 0x01, 0x0A, 0x0B, 0x0B.

Your blob/mask to match this entire payload exactly would be: mask : 0xFF, 0xFF, 0xFF blob : 0x0A, 0x0B, 0x0C

We exclude the manufacturer company ID from the blob/mask and you need to provide that value in ASBluetoothCompanyIdentifier.

Let me know if this addresses your concern and resolves the issue you've been experiencing !

Thanks.

Hi,

Thanks for the fast reply on @melle's post. I am a colleague of him, we had a session today doing some research on this and trying to implement a way to detect all of our existing products.

Unfortunately we didn't have success and could observe a few things as well as a few questions came up.

From your response it seems like bluetoothCompanyIdentifier is required to work with bluetoothManufacturerDataBlob as well as bluetoothManufacturerDataMask, so we need to set a company identifier on the descriptor and enter the remaining announced manufacturer data into the bluetoothManufacturerDataBlob?

We could not find out if it is necessary to enter the entire announced manufacturer data into the bluetoothManufacturerDataBlob or if it would be sufficient to enter parts of it?

Moreover we could not find out how to order the blob, we had different data from different apps (we used BlueSee as well as LightBlue). For example for one of our products the results looked like this:

BlueSee (mac): Manufacturer Data: d20a0031000000
LighBlue (iOS): 0x0031000ad2

We tried based on this example:

Product A
 
0xd2 0a ff d2 0a  00   00 00 00 00

Manufacturer 0xD20A
Device ID: 0xFFD2
color: 0a
 
 
Product B
 
0xd20a  00 31  00  00 00

Manufacturer 0xD20A

If we try a descriptor just defining the bluetoothServiceUUID, which all of our products announce, we can only see 1 device in the session having multiple around. We also could see a single device announcing it but never get detected by AccessorySetupKit. Any idea what it could be?

Even tho we are still having troubles implementing it for our products we are super excited about AccessorySetupKit, would love to be able to implement it for all of our existing products providing an unique experience for our customers 🤗

Hi and thanks for the quick response with the detailed explanation.

From your response it seems like bluetoothCompanyIdentifier is required to work with bluetoothManufacturerDataBlob as well as bluetoothManufacturerDataMask, so we need to set a company identifier on the descriptor and enter the remaining announced manufacturer data into the bluetoothManufacturerDataBlob?

yes, you need all 3 of these

for this question :

If we try a descriptor just defining the bluetoothServiceUUID, which all of our products announce, we can only see 1 device in the session having multiple around. We also could see a single device announcing it but never get detected by AccessorySetupKit. Any idea what it could be?

you will need a configuration for each of your different products, which means you will need multiple display items with the same manufacturer ID, but different blob/mask, and different display name to fit your product, one for product A, one for product B

for this :

Manufacturer 0xD20A Device ID: 0xFFD2 color: 0a

your payload should actually look like 0x06 0x0FF 0x0A 0xD2 0xFF 0xD2 0x0A

we need to account for the endianness of the LE over the air packet and how we treat uint16_t over the air.

Please try this, and let me know if this works or not.

If you are still encountering an issue with this, we would encourage you to send us a Feedback report with logs attached from your iOS device with timestamps so we can further investigate. Please remember to download and install the debug profiles from Profiles and Logs

You will need the AccessorySetupKit and the Bluetooth iOS profiles both installed before you can submit the logs to the feedback.

Thanks!

I'm sorry, but I have to ask again to make sure I understand the issue. When we use CoreBluetooth's CBCentralManager to scan for peripherals, we'll see this data in the advertisementData dictionary (CBAdvertisementDataManufacturerDataKey):

0xd2 0x0a 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8

I understand that AccessorySetupKit expects a different byte order and that the ASDiscoveryDescriptor should be set up as follows

let descriptor = ASDiscoveryDescriptor()
descriptor.bluetoothServiceUUID = CBUUID(string: "ce1eb45c-1bd2-45be-8163-acc88be94cb2")
descriptor.bluetoothCompanyIdentifier = .init(0x0ad2)
descriptor.bluetoothManufacturerDataBlob = Data([0xb2, 0xb1, 0xb4, 0xb3, 0xb6, 0xb5, 0xb8, 0xb7]) // ????
descriptor.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])

Could you please confirm if this setup is correct? If not, I would greatly appreciate any corrections or guidance you could provide.

I find the differing byte orders between the advertisementData dictionary and the ASDiscoveryDescriptor a bit confusing. If the above setup is correct, I will proceed to file feedback with logs, as we are currently unable to detect our accessory using AccessorySetupKit.

Hello.

When you scan with CBCentralManager, you get a stream of bytes in the order they were received from BT controller. That is in this example :

0xd2 0x0a 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7 0xb8

However, when you register a company ID with the Bluetooth SIG to use in this AD type, you register a uint16 value. For example, Apple is 0x004C. When adverting that over the air the manufacturer ID will be translated in the payload to 0x4C 0x00 and not sent as 0x00 0x4C

descriptor.bluetoothCompanyIdentifier uses the same method so you need to put in your correct registered uint16 ID, and in the payload itself reverse just the manufacturer ID bytes. Other bytes should be set in the regular order.

For example, Apple payload to to advertise the b0-b7 bytes :

0x4C 0x00 0xb0 0xb1 0xb2 0xb3 0xb4 0xb5 0xb6 0xb7

And if you want to discover it :

let descriptor = ASDiscoveryDescriptor()
descriptor.bluetoothCompanyIdentifier = .init(0x004C)
descriptor.bluetoothManufacturerDataBlob = Data([0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7])
descriptor.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])

I did want to ask you about this part :

descriptor.bluetoothServiceUUID = CBUUID(string: "ce1eb45c-1bd2-45be-8163-acc88be94cb2")

Can you share a complete sample of your ADV payload ? Are you advertising a 16byte UUID in addition to the manufacturer data ? Do you also have flags in your payload ? A sample payload would help me get more context.

Thanks !

Hey there 👋

Thanks for the nice explanation, I'll do further research and discuss this together with @melle upcoming week.

I did want to ask you about this part :

descriptor.bluetoothServiceUUID = CBUUID(string: "ce1eb45c-> 1bd2-45be-8163-acc88be94cb2")

Can you share a complete sample of your ADV payload ? Are > you advertising a 16byte UUID in addition to the manufacturer > data ? Do you also have flags in your payload ? A sample > payload would help me get more context.

We're publishing this additionally to the manufacturer data in case a device is in pairing mode. There are flags in our manufacturer data's payload regarding device specifications. Guess that's also the reason for a lot of confusion on our side in what order to put the bytes. We can surely provide you with a more detailed sample upcoming week after we did some research.

Have a nice weekend and thank you very much for your help 😊

Thanks for the extra details, and I really look forward to your update next week about your progress. We strongly feel that this kind of filtering allows better control over the discovered peripherals and can enable you to use distinct and unique display items per accessory type.

Hello! We used LightBlue on Android to capture the complete BLE advertisement for two products we try to pair with AccessorySetupKit. I masked the local name of product 2, because it's not released yet.

Product 1 has this BLE advertisement: 0x0B097461747773325F626C6508FFD20A00350000001107B24CE98BC8AC6381BE45D21B5CB41ECE0000000000000000000000000000000000000000000000

The manufacturer data as seen from CoreBluetooth (CBAdvertisementDataManufacturerDataKey) is 0xd20a0035000000

This is the desciptor we are using:

let descriptor1 = ASDiscoveryDescriptor()
descriptor1.bluetoothServiceUUID = CBUUID(string: "CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2")
descriptor1.bluetoothManufacturerDataBlob = Data([0x00, 0x35, 0x00, 0x00, 0x00])
descriptor1.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff])
descriptor1.bluetoothCompanyIdentifier = .init(0x0ad2)

Product 2 has this BLE advertisement: 0x02010A1107B24CE98BC8AC6381BE45D21B5CB41ECE08FFOAD2003F1300000909**************0000000000000000000000000000000000000000000000

The manufacturer data as seen from CoreBluetooth (CBAdvertisementDataManufacturerDataKey) is 0xd20affd20a0000000000

This is the desciptor we are using:

let descriptor2 = ASDiscoveryDescriptor()
descriptor2.bluetoothServiceUUID = CBUUID(string: "CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2")
descriptor2.bluetoothManufacturerDataBlob = Data([0xFF, 0xD2, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00])
descriptor2.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff])
descriptor2.bluetoothCompanyIdentifier = .init(0x0ad2)

Both products can be found with CoreBluetooth, however, both are not visible when using the AccessorySetupKit. Is there anything unexpected the advertisement? Do we need to change anything in the desciptors to match the advertisements?

@melle

For this payload :

0x0B097461747773325F626C6508FFD20A00350000001107B24CE98BC8AC6381BE45D21B5CB41ECE0000000000000000000000000000000000000000000000

Looks like its more than 31 bytes so I'm assuming you're doing extended advertising and not legacy advertising, can you confirm ?

Also, this payload above should not be discovered at all as it does not have any flags to mark it as discoverable.

Can you please file a feedback with AccessorySetupKit and Bluetooth logging profiles installed so I can take another look a this ?

for :

0x02010A1107B24CE98BC8AC6381BE45D21B5CB41ECE08FFOAD2003F1300000909**************0000000000000000000000000000000000000000000000

This also looks longer than 31 bytes. This does have flags but your ASDiscoveryDescriptor is not properly configured. It should be

let descriptor2 = ASDiscoveryDescriptor()
descriptor2.bluetoothServiceUUID = CBUUID(string: "CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2")
descriptor2.bluetoothManufacturerDataBlob = Data([0x00, 0x3F, 0x13, 0x00, 0x00])
descriptor2.bluetoothManufacturerDataMask = Data([0xff, 0xff, 0xff, 0xff, 0xff])
descriptor2.bluetoothCompanyIdentifier = .init(0x0ad2)

Please try this, and see if it works, otherwise, please file a second feedback for this payload.

Also, could you share the contents of your info.plist so we can make sure everything is ok with it ?

Thanks.

I filed feedbacks for different advertisements used by 3 different products:

  • FB14052487
  • FB14051395
  • FB14051767

Bluetooth and ASK logging profiles are installed and I attached the sysdiagnose to each.

About the lenght of the advertisements: I assume we're using extended advertising, I'll check with the hardware people and update you.

The missing discoverability flag seem like a bug. I can try to have this fixed, but unfortunately we cannot fix this for already released products. This advertisement contains the "General Discoverable" flag and is also not discovered by ASK: 0x02010A1107B24CE98BC8AC6381BE45D21B5CB41ECE08FFD2OA003F1300000909**************0000000000000000000000000000000000000000000000

The not properly configured ASDiscoveryDescriptor was caused by pasting the wrong code to the message. I was using your suggestion, unfortunately without success.

The info.plist looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>NSAccessorySetupBluetoothServices</key>
	<array>
		<string>CE1EB45C-1BD2-45BE-8163-ACC88BE94CB2</string>
	</array>
	<key>NSAccessorySetupKitSupports</key>
	<array>
		<string>Bluetooth</string>
	</array>
</dict>
</plist>
Accepted Answer

thanks @melle for the last piece of info. Your plist looks almost perfect, but you're missing the NSAccessorySetupBluetoothCompanyIdentifiers key to indicate what manufacturer ID's you would like to scan for (https://developer.apple.com/documentation/bundleresources/information_property_list/nsaccessorysetupbluetoothcompanyidentifiers/)

In your case, you need to specify an array of 1 string, "0ad2".

Adding this to the plist will allow us to send you the data that we found.

Please let me know if that helps.

Thanks.

Oh no, we were so focused on getting the manufacturer data right that we forgot to fill in the plist key. In other words, it works like a charm, we can now set up all our existing and future products with ASK 🥳 Thanks for your help.

AccessorySetupKit: Usage of manufacturer data blob
 
 
Q