Programáticamente, ¿Cómo identificar si un faro pertenece a Eddystone o iBeacon?
He creado una aplicación androide para escanear BLE usando Bluetooth LEscanner. Ahora que necesito mi aplicación para identificar si un faro pertenece a iBeacon o Eddystone. Hasta ahora, tengo éxito en la determinación de UUID, MajorId, MinorId de ibeacon al analizar el marco AD.
- Listado de beacons en el dispositivo android
- Medir la distancia a iBeacon desde el dispositivo Android
- IBeacons - Compañía (Estimate, Gimbal, etc.) SDKs contra la biblioteca de Android / iOS
- Problemas con el ejemplo de Kontakt.io Beacon
- ¿Puedo usar iBeacon en Android con mensajes cercanos?
- Kontakt Beacons: Resultados incoherentes y poco fiables al determinar la distancia de la baliza
- ¿Es posible utilizar un BLE habilitado para Android / iPhone como un faro BLE?
- Estimar iBeacon: Supervisión en segundo plano (Android)
- Ble scanning callback sólo se llaman varias veces y luego se detiene
- Cómo obtener el Id único de un Beacon usando Estimate SDK en Android
- Excepción al intentar agregar un BeaconParser a AltBeacon lib
- Cómo detectar IBeacon en android sin usar ninguna biblioteca
- Android AltBeacon Antecedentes
Es relativamente fácil leer los bytes de los anuncios si conoce los desplazamientos de bytes de todos los campos. Dos fragmentos de código a continuación muestran cómo se pueden analizar estos. El primero muestra cómo puede hacer esto en su propia onLeScan
llamada onLeScan
usando la Biblioteca de Android Beacon , y el segundo muestra cómo puede rodar su propio desde cero.
Para explicar cómo funcionan los diseños, mire el código de abajo. Utiliza la clase BeaconParser
Beacon Libray de BeaconParser
que maneja todo el análisis para un diseño configurable. (Incluso si quieres rodar el tuyo como se muestra en el segundo fragmento de código, vale la pena mirar las expresiones de diseño para que sepas cómo funcionan.Las expresiones siguientes muestran los detalles de AltBeacon que es muy similar a iBeacon. Porque no existen restricciones de propiedad intelectual para discutir su implementación, tanto AltBeacon como Eddystone son estándares de código abierto.)
La primera expresión de disposición muestra que AltBeacon (de nuevo muy similar a iBeacon) tiene tres identificadores (expresiones "i"). El primero (conocido como UUID en iBeacon) es de 16 bytes que va desde el desplazamiento de bytes 4-19. El segundo (conocido como mayor en iBeacon) es de 2 bytes que va desde el desplazamiento de bytes 20-21. El tercero (conocido como menor en iBeacon) es de 2 bytes que va desde el desplazamiento de bytes 22-23.
La segunda expresión de disposición muestra que Eddystone-UID es un anuncio de servicio que tiene un UUID de servicio de 16 bits de 0xfeaa seguido de un código de byte coincidente de 0x00. Tiene dos identificadores, el primero conocido como "identificador de espacio de nombres" de los desplazamientos de bytes 4-13. El segundo identificador se conoce como el "identificador de instancia" de los desplazamientos de bytes 14-19.
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { ArrayList<BeaconParser> beaconParsers = new ArrayList<BeaconParser>(); final String ALTBEACON_LAYOUT = "m:2-3=beac,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25"; final String EDDYSTONE_UID_LAYOUT = "s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19"; beaconParsers.add(new BeaconParser().setBeaconLayout(EDDYSTONE_UID_LAYOUT)); beaconParsers.add(new BeaconParser().setBeaconLayout(ALTBEACON_LAYOUT)); Beacon beacon = null; for (BeaconParser parser : beaconParsers) { beacon = parser.fromScanData(scanRecord, rssi, device); if (beacon != null) { if (beacon.getServiceUuid() == 0xfeaa) { // This is Eddystone, which uses a service Uuid of 0xfeaa Identifier eddystoneNamespaceId = beacon.getId1(); Identifier eddystoneInstanceId = beacon.getId2(); } else { // This is another type of beacon like AltBeacon or iBeacon Identifier uuid = beacon.getId1(); Identifier major = beacon.getId2(); Identifier minor = beacon.getId3(); } } }
La biblioteca de código abierto Android Beacon maneja todos los detalles sobre las PDU de longitud variable que pueden alterar ligeramente los desplazamientos de bytes dentro de la respuesta de análisis. Puede ver el código fuente de cómo funciona su BeaconParser aquí.
Si quieres rodar tu propio completamente desde cero, la manera más fácil es simplemente hacer un bucle a través de los bytes que buscan el patrón que quieres encontrar, luego analizar los bytes de interés basados en los desplazamientos. (La Biblioteca Beacon de Android utiliza un método más robusto y sofisticado de analizar realmente PDU individuales). Pero la técnica de bucle sigue funcionando.
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { for (int startByte = 0; startByte < scanRecord.length; startByte++) { if (scanRecord.length-startByte > 19) { // need at least 19 bytes for Eddystone-UID // Check that this has the right pattern needed for this to be Eddystone-UID if (scanRecord[startByte+0] == (byte)0xaa && scanRecord[startByte+1] == (byte)0xfe && scanRecord[startByte+2] == (byte)0x00) { // This is an Eddystone-UID beacon. byte[] namespaceIdentifierBytes = Arrays.copyOfRange(scanRecord, startByte+4, startByte+13); byte[] instanceIdentifierBytes = Arrays.copyOfRange(scanRecord, startByte+14, startByte+19); // TODO: do something with the above identifiers here } } if (scanRecord.length-startByte > 24) { // need at least 24 bytes for AltBeacon // Check that this has the right pattern needed for this to be AltBeacon // iBeacon has a slightly different layout. Do a Google search to find it. if (scanRecord[startByte+2] == (byte)0xbe && scanRecord[startByte+3] == (byte)0xac) { // This is an AltBeacon byte[] uuidBytes = Arrays.copyOfRange(scanRecord, startByte+4, startByte+19); byte[] majorBytes = Arrays.copyOfRange(scanRecord, startByte+20, startByte+21); byte[] minorBytes = Arrays.copyOfRange(scanRecord, startByte+22, startByte+23); // TODO: do something with the above identifiers here } } } }
Una vez más, el código anterior muestra cómo analizar los AltBeacons de código abierto (por razones de propiedad intelectual). Para analizar iBeacons, necesitará realizar una búsqueda en Google para su BeaconLayout y realizar pequeños ajustes en el código anterior.
Las balizas pueden anunciar iBeacon y Eddystone . De hecho, un proyecto en el que estoy involucrado está utilizando tales faros.
Es fácil extraer iBeacon y Eddystone de paquetes si usa la biblioteca nv-bluetooth . Me gusta esto:
// onLeScan() method of BluetoothAdapter.LeScanCallback interface. public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { // Parse the payload of the advertisement packet. List<ADStructure> structures = ADPayloadParser.getInstance().parse(scanRecord); // For each AD structure contained in the advertising packet. for (ADStructure structure : structures) { // If the ADStructure instance can be cast to IBeacon. if (structure instanceof IBeacon) { // An iBeacon was found. IBeacon iBeacon = (IBeacon)structure; ...... } // If the ADStructure instance can be cast to Eddystone. else if (structure instanceof Eddystone) { if (structure instanceof EddystoneUID) { // Eddystone UID EddystoneUID es = (EddystoneUID)structure; ...... } else if (structure instanceof EddystoneURL) { // Eddystone URL EddystoneURL es = (EddystoneURL)structure; ...... } else if (structure instanceof EddystoneTLM) { // Eddystone TLM EddystoneTLM es = (EddystoneTLM)structure; ...... } } ...... } ...... }
Tenga en cuenta que android.bluetooth.le.ScanRecord
es una de las peores API en Android, por lo que es mejor analizar paquetes manualmente que utilizar ScanRecord
.
Por favor, lea la documentación sobre ScanRecord
https://developer.android.com/reference/android/bluetooth/le/ScanRecord.html . El método getManufacturerSpecificData()
puede ser algo que está buscando.