How to receive advertising data on specific UUID?
Hello,
I'm working on a Flutter project using the universal_ble package for Bluetooth Low Energy communication. I'm trying to figure out how to receive advertising data specifically for the UUID 0x181A
Does the universal_ble package support receiving advertising data for specific UUIDs?
I'd appreciate any guidance, code examples, or documentation references that could help me implement this functionality.
Thank you in advance for your help!
@ethan8051 you can use scan filter to get only those devices which have this specific id in their advertising data
Thank you for your response.
I've attempted to implement a scan filter to capture broadcast data, but it appears to be ineffective for certain devices. I've verified using the nRF Connect app that these devices are indeed broadcasting packets.
Furthermore, I have an additional question: Assuming I successfully obtain a list of devices based on the specified UUID, how can I extract the actual data content from the broadcast, rather than just the device information and UUID?
I'm aiming to interface with this device's firmware: https://github.com/pvvx/ATC_MiThermometer?tab=readme-ov-file#bluetooth-advertising-formats
Any insights or guidance on these issues would be greatly appreciated. Thank you in advance for your help.
@ethan8051 can you provide your minimum sample code, have you tried example app ? in example app you can add scan filter here and whatever we add in scan filter, only those devices will be discovered
also it would be helpful to see the Nrf Connect app's screenshot of the device's advertising data which you are expecting to be discovered by this plugin
and for now you can obtains these information of a discovered device, you can let us know if something is missing in this
Thank you for your response.
The attached image is a screenshot from nRF Connect that I've been using. I'm trying to read the advertisement data from the 181A service.
However, when I attempt to add the UUID 181A to the scan filter's withServices, I'm unable to detect any devices.
Information of a discovered device:
I/flutter ( 7465): name: ATC_DD7A81
I/flutter ( 7465): rssi: -36
I/flutter ( 7465): isPaired: false
I/flutter ( 7465): isSystemDevice: null
I/flutter ( 7465): manufacturerData: []
I/flutter ( 7465): manufacturerDataHead: []
I/flutter ( 7465): services: []
I've included my source code below for reference:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:universal_ble/universal_ble.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
// List<BleScanResult> deviceList = [];
Map<String, BleScanResult> deviceList = {};
bool isScanning = false;
late Timer scanTimer;
@override
void initState() {
super.initState();
requestPermission();
// Set a scan result handler
UniversalBle.onScanResult = (scanResult) {
setState(() {
deviceList[scanResult.deviceId] = scanResult;
});
};
startScan();
}
Future<void> startScan() async {
if (isScanning) return;
setState(() {
isScanning = true;
deviceList.clear();
});
await UniversalBle.startScan(
scanFilter: ScanFilter(
// withNamePrefix: ["Meta"],
// withServices: ["0000181a-0000-1000-8000-00805f9b34fb"],
// withServices: ["181A"],
),
);
scanTimer = Timer(const Duration(seconds: 10), () {
// stopScan();
});
}
Future<void> stopScan() async {
if (!isScanning) return;
await UniversalBle.stopScan();
scanTimer.cancel();
setState(() {
isScanning = false;
});
}
Future requestPermission() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.location,
Permission.bluetooth,
Permission.bluetoothConnect,
Permission.bluetoothScan,
Permission.bluetoothAdvertise
].request();
print("Permission.location: ${statuses[Permission.location]}");
print(
"Permission.bluetoothConnect: ${statuses[Permission.bluetoothConnect]}");
print("Permission.bluetoothScan: ${statuses[Permission.bluetoothScan]}");
print(
"Permission.bluetoothAdvertise: ${statuses[Permission.bluetoothAdvertise]}");
}
@override
Widget build(BuildContext context) {
deviceList.forEach((k,v) => print("got key $k with ${v.manufacturerData}"));
final sortedDeviceList = deviceList.values.toList()
..sort((a, b) => b.rssi!.compareTo(a.rssi ?? 0));
return MaterialApp(
home: SafeArea(
child: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: isScanning ? stopScan : startScan,
child: Icon(isScanning ? Icons.stop : Icons.search),
),
body: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: sortedDeviceList.length,
itemBuilder: (context, index) {
final device = sortedDeviceList.elementAt(index);
return ListTile(
leading: const Icon(Icons.device_hub),
title: Text("[${device.rssi}] ${device.name ?? "Unknow"}"),
subtitle: Text((device.manufacturerData ?? []).toString()),
);
},
),
),
],
),
),
),
);
}
}
@ethan8051 a quick thing to test, try to scan all devices without any filter, and print the BleDevice info of required device, and please share that, so that we can know if our plugin is discovering these required services in Advertising data
@ethan8051 i just noticed that you have already mentioned the discovered device
I/flutter ( 7465): name: ATC_DD7A81
I/flutter ( 7465): rssi: -36
I/flutter ( 7465): isPaired: false
I/flutter ( 7465): isSystemDevice: null
I/flutter ( 7465): manufacturerData: []
I/flutter ( 7465): manufacturerDataHead: []
I/flutter ( 7465): services: []
we can see that services list is empty, probably the platform on which you are trying to filter the device with this service does not gets this services in advertisement data
on Which platform you are trying with UniversalBle and on which platform you are testing with NrfConnect app ?
and if both platforms are different, i would suggest to run the same code on the platform on which you are testing with NrfConnect app
@rohitsangwan01
Thank you for your response.
I scanned with filtering turned off. UniversalBle and the NRF Connect app were run on the same Android 13 Samsung phone.
In addition, I have tried using ESP32 with Arduino + NimBLE to implement a device for broadcast testing. I set the broadcast service UUID to 181A and filled in fixed data for broadcasting. However, the result is still the same I am unable to obtain the data.
@ethan8051 So when you start scan without filters, and you discover your device, and when you print it like this
I/flutter ( 7465): name: ATC_DD7A81
I/flutter ( 7465): rssi: -36
I/flutter ( 7465): isPaired: false
I/flutter ( 7465): isSystemDevice: null
I/flutter ( 7465): manufacturerData: []
I/flutter ( 7465): manufacturerDataHead: []
I/flutter ( 7465): services: []
do you get services list empty in discovered BleDevice object ? if the services list is empty, that means, android probably not detecting those services as a part of advertising data, which also means that service filter will ignore this device
and if the services list is empty in universalBle but not in nrf connect, then that might be a bug in plugin, also can you cross check on any other platform ?
@rohitsangwan01 Thank you for your response.
The results of executing UniversalBle on Linux are as follows:
[UniversalBle] BleAdapter: ethan-System-Product-Name - 00:1A:00:00:00:00
flutter: name: ATC_DD7A81
flutter: rssi: -44
flutter: isPaired: false
flutter: isSystemDevice: null
flutter: manufacturerData: []
flutter: manufacturerDataHead: []
flutter: services: []
[UniversalBle] UnhandledDevicePropertyChanged ATC_DD7A81 A4:C1:00:00:00:00: ServiceData
flutter: name: ATC_DD7A81
flutter: rssi: -43
flutter: isPaired: false
flutter: isSystemDevice: null
flutter: manufacturerData: []
flutter: manufacturerDataHead: []
flutter: services: []
Additionally, I found that if I don't set any ScanFilter at all, the device won't appear in the list
scanFilter: ScanFilter(
withNamePrefix: ["ATC"],
),
I tried using Python + bleak to scan for devices, this is my source code.
import asyncio
import bleak
async def main():
devices = await bleak.BleakScanner.discover()
for device in devices:
if("ATC" not in device.name):
continue
print(f"name: {device.name}")
print(f"details: {device.details}")
asyncio.run(main())
Execution result, it is possible to successfully obtain the 181A ServiceData.:
name: ATC_DD7A81
details:{
"path":"/org/bluez/hci0/dev_A4_C1_00_00_00_00",
"props":{
"Address":"A4:C1:00:00:00:00",
"AddressType":"public",
"Name":"ATC_DD7A81",
"Alias":"ATC_DD7A81",
"Paired":false,
"Trusted":false,
"Blocked":false,
"LegacyPairing":false,
"RSSI":-51,
"Connected":false,
"UUIDs":[],
"Adapter":"/org/bluez/hci0",
"ServiceData":{
"0000181a-0000-1000-8000-00805f9b34fb":"bytearray(b""\\x81z\\xdd8\\xc1\\xa4I\nz\\x17D\\x0ba\\xe7\\x04"")"
},
"ServicesResolved":false
}
}
@ethan8051 we are using UUIDS list for displaying services list in UniversalBle
but from your Bleak response, i can see that services are discovered in ServicesData
We are not using ServicesData in UniversalBle on any platform
can you check if the Peripheral you are using can send services in UUIDs List as well ?
Additionally, I found that if I don't set any ScanFilter at all, the device won't appear in the list scanFilter: ScanFilter( withNamePrefix: ["ATC"], ),
You mean, only this device does not appear, or no device discovers without filter ?
blocked by https://github.com/Navideck/universal_ble/issues/95