Reputation: 529
I have to build an Android App that reads information on a kind of device that only shows up on scan when it's filtered (general scans won't show it). The device is beacon-like, so it only advertises data, which have the info I want on the advertise (it's not connectable). The filter that the manufacturer gave to me, is a raw data. Which is:
0x02010612435542
I can't filter it by name, because the device does not advertise it's name. I can't do it by MAC Address
either, because the App won't previously know the device's Address (it will be many devices of that kind).
The nrfConnect App, does it nicely, as you can see below:
The filter's name on the App is:
Filter by raw advertising data
And, when filtered, that's how a device shows up on the App:
So, here is the thing. I can't filter either by name or MAC Address
.
The other options in Java (android/ble standard lib) for filtering are:
ScanFilter scanFilter1 = new ScanFilter.Builder().setManufacturerData(manufacturerId, manufacturerData).build();
ScanFilter scanFilter2 = new ScanFilter.Builder().setServiceData(serviceDataUuid, serviceData).build();
ScanFilter scanFilter2 = new ScanFilter.Builder().setServiceUuid(serviceUuid).build();
I've got the UUID provided by the manufacturer. It's
B54ADC00-67F9-11D9-9669-0800200C9A66
But, as the manufacturer stated, the UUID is used to scan for iOS, won't work on Android (tested it, it's true).
So, I'am left with 2 options of the scanFilters above.
I have knowledge like: "The manufacturer data is advertised within the raw advertising data, which can be found via nrfConnect App. And the first two bytes of the manufacturer data, is the manufacturer ID, to use with the setManufacturerData()
filter".
I even was able to retrieve the raw manufacturer advertised data (using the setDeviceAddress()
filter (for testing, using a test-device, because as I said, the App won't know the MACAddresses previously), and I got something like this:
0X020106124355420000080390BECB49400400CB500CF
Sorry for the long question, but I tried to make it the most complete I could.
I have tried everything I could using those scanFilter methods, but couldn't get it to work.
Someone knows how to implement this? I am going crazy for over a MONTH on this.
Thanks in advance!
Upvotes: 2
Views: 5648
Reputation: 9
I Finally figured it out with two methods.
Using ScanCallback
ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
byte[] scanRecord = result.getScanRecord().getBytes();
//scanRecord will give you the raw advertisement data given by the device in byte array.
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult sr : results) {
//
}
}
@Override
public void onScanFailed(int errorCode) {
//
}
};
Using LeScanCallback
BluetoothAdapter.LeScanCallback mLeScanCallback =
new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
//scanRecord will give you the raw advertisement data given by the device in byte array.
}
};
You can filter out the device you want from this byte array.
For example:
To find out only Heart Rate Monitor Device, I have converted the scanRecord byte array to a string and then checked the occurrence of "0d 18" in it.
If the device raw advertising data contains "0d 18" string, it is a Heart rate monitor otherwise it's not.
Let me know if anyone still needs help
Upvotes: 1
Reputation: 529
I finally found a solution. It doesn't answer the question about the filter scan by raw advertising data but, I could scan for the devices I needed. This is what I did:
First, I made a filter by name. Although the device have no name, I filter by name to scan for devices whose name == null
.
private List<ScanFilter> scanFilters() {
List<ScanFilter> list = new ArrayList<ScanFilter>();
ScanFilter scanFilterName = new ScanFilter.Builder().setDeviceName(null).build();
list.add(scanFilterName);
return list;
}
After that, I needed a second filter (which wasn't on the scanFilters()method above, it was on the scanResult) because it was returning me a huge amount of devices, and that filter was by the MAC Address prefix (which is the same for my devices).
private Set<String> btDevice = new LinkedHashSet<String>();
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
BluetoothDevice device = result.getDevice();
ScanRecord record = result.getScanRecord();
byte[] dataByteArray = record.getBytes();
if (device.getAddress().startsWith("F8:36:9B")) {
btDevice.add(device.getAddress());
}
}
};
And finaly, I got to scan only the devices I needed. I still want to know the main question so, if someone have a solution to this, please feel free to answer. Thanks!
Upvotes: 0