bluetooth lowenergy - Disminución de dispositivos BLE startScan detectados en Android 5.0 Lollipop
bluetooth-lowenergy android-5.0-lollipop (5)
He experimentado resultados muy similares con mi Nexus 4, tanto en KitKat como en Lollipop.
Con KitKat, el adaptador de bluetooth también dejó de responder; al principio pensé que podría estar relacionado con un intervalo de exploración corto (200 ms), pero aumentar ese número a un segundo no ayudó, en ese caso descubrí que, cuando no responde y habilita programáticamente el adaptador, a veces resuelve el problema . Lamentablemente no puedo decir que funcione todo el tiempo.
Ahora con Lollipop, en el que tenía muchas esperanzas de resolver estos problemas, experimenté el mismo comportamiento que usted describe. También tuve que usar la implementación startScan / stopScan, obteniendo resultados similares con respecto a los tiempos de detección. Lamentablemente, no he encontrado una solución para obtener resultados más rápidamente.
Según lo que describa, supongo que podría tratarse de un problema de hardware, aunque el Nexus 7 y el Nexus 4 son de diferentes fabricantes (Asus y LG).
Sé que no estoy brindando mucha ayuda aquí, además de tratar de responder tu pregunta acerca de que te has perdido algo; No lo creo, creo que el problema es algo así como el hardware o la API de bluetooth que aún no se comporta como debería en diferentes dispositivos.
Version corta:
En mis pruebas con Android 5.0 Lollipop noté que android.bluetooth.le.BluetoothLeScanner
detecta dispositivos BLE con menos frecuencia que Android 4.4 KitKat. ¿Por qué es esto y hay una alternativa?
Versión larga:
Estoy desarrollando una aplicación para Android, específicamente para la tableta Nexus 7, que se centra en la detección de dispositivos Bluetooth de baja energía (BLE). La aplicación está principalmente interesada en el valor RSSI de las balizas, para determinar su proximidad a la tableta. Esto significa que no necesitaré conectarme al dispositivo BLE, ya que el valor de RSSI pasa a la devolución de llamada de escaneo cuando se detecta el dispositivo.
En Android 4.4 KitKat, cuando llamo a BluetoothAdapter.startLeScan(LeScanCallback)
, mi devolución de llamada se llama solo UNA VEZ para cada dispositivo BLE detectado. (He visto algunas discusiones que afirman que este comportamiento puede diferir por dispositivo) Sin embargo, estoy interesado en el valor RSSI en constante cambio, por lo que la forma actualmente recomendada es hacer continuamente startLeScan y stopLeScan con un intervalo establecido (250 ms en mi caso):
public class TheOldWay {
private static final int SCAN_INTERVAL_MS = 250;
private Handler scanHandler = new Handler();
private boolean isScanning = false;
public void beginScanning() {
scanHandler.post(scanRunnable);
}
private Runnable scanRunnable = new Runnable() {
@Override
public void run() {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
if (isScanning) {
adapter.stopLeScan(leScanCallback);
} else if (!adapter.startLeScan(leScanCallback)) {
// an error occurred during startLeScan
}
isScanning = !isScanning;
scanHandler.postDelayed(this, SCAN_INTERVAL_MS);
}
};
private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
// use the RSSI value
}
};
}
Esencialmente, esto me da los resultados requeridos, pero este proceso requiere muchos recursos y finalmente conduce a un adaptador Bluetooth que no responde.
Por estas razones, actualicé mi Nexus 7 a Android 5.0 Lollipop para ver si se solucionaban mis problemas de BLE. En Lollipop BluetoothAdapter.startLeScan (LeScanCallback) está en desuso y reemplazado por android.bluetooth.le.BluetoothLeScanner que permite un poco más de control sobre el proceso de escaneo. Desde mis primeras pruebas, parece que startScan no llama continuamente a mi devolución de llamada (en mi Nexus 7) cuando cambian los valores de RSSI, por lo que todavía necesito usar la implementación startScan / stopScan:
@TargetApi(21)
public class TheNewWay {
private static final int SCAN_INTERVAL_MS = 250;
private Handler scanHandler = new Handler();
private List<ScanFilter> scanFilters = new ArrayList<ScanFilter>();
private ScanSettings scanSettings;
private boolean isScanning = false;
public void beginScanning() {
ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
scanSettings = scanSettingsBuilder.build();
scanHandler.post(scanRunnable);
}
private Runnable scanRunnable = new Runnable() {
@Override
public void run() {
BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();
if (isScanning) {
scanner.stopScan(scanCallback);
} else {
scanner.startScan(scanFilters, scanSettings, scanCallback);
}
isScanning = !isScanning;
scanHandler.postDelayed(this, SCAN_INTERVAL_MS);
}
};
private ScanCallback scanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
super.onScanResult(callbackType, result);
int rssi = result.getRssi();
// do something with RSSI value
}
@Override
public void onScanFailed(int errorCode) {
super.onScanFailed(errorCode);
// a scan error occurred
}
};
}
Como puede ver, he configurado el escáner utilizando la clase ScanSettings, que le permite configurar el modo de scanMode
. Uso ScanSettings.SCAN_MODE_LOW_LATENCY
, que tiene la siguiente documentación: "Escanear usando el ciclo de trabajo más alto. Se recomienda usar este modo solo cuando la aplicación se ejecuta en primer plano". Suena exactamente igual a lo que quiero, pero desafortunadamente solo detecto una baliza cada 15 a 30 segundos, donde la versión de KitKat me muestra la misma baliza cada 1 a 2 segundos en este intervalo de exploración.
¿Tienes alguna idea de cuál podría ser la razón de esta diferencia? ¿Me estoy perdiendo algo, tal vez algunas configuraciones nuevas? ¿Hay formas alternativas de hacer lo anterior?
¡Muchas gracias por adelantado!
Abel
PD: Quería incluir más enlaces a los recursos que he usado, pero todavía no tengo los puntos de representación.
He obtenido resultados muy diferentes con un Nexus 5 que ejecuta las nuevas API de escaneo de Android 5.0. Las detecciones de paquetes BLE se produjeron casi en tiempo real cuando se usa SCAN_MODE_LOW_LATENCY, cada 100 ms para las balizas BLE que transmiten a 10Hz.
Puedes leer los resultados completos aquí:
http://developer.radiusnetworks.com/2014/10/28/android-5.0-scanning.html
Estas pruebas se basan en la ejecución de la rama experimental android-l-apis de Android Beacon Library 2.0 de código abierto here .
No es obvio cuál es la diferencia en los resultados de las pruebas, pero es posible que al iniciar y detener la exploración se estén cambiando los resultados.
EDITAR: es posible que el hardware sea la diferencia. Vea un informe de tiempos similares en el Nexus 4: https://github.com/AltBeacon/android-beacon-library/issues/59#issuecomment-64281446
Más allá de la API 21, Android usa SCAN_MODE_LOW_POWER de forma predeterminada. SCAN_MODE_LOW_POWER
Prueba SCAN_MODE_BALANCED y ve si mejora.
SCAN_MODE_BALANCED
No tengo una reputación de 50 para un comentario todavía, así que tengan paciencia, este comentario tendrá la forma de una respuesta. En su código, no debería esta parte:
if (isScanning) { scanner.startScan(...)
sé esto en su lugar:
if (!isScanning) {
scanner.startScan(...)
Porque siguiendo su código, está llamando a stopScan () antes de iniciar una exploración. Es posible que no tenga un efecto directo en el resultado si el método stopScan () es idempotente / seguro. Pero ya sabes, por el bien de la inteligibilidad del código deberías editar la pregunta. Y haz lo mismo con tu código, a veces las cosas bizantinas están en juego;)
¿Has probado valores más grandes para SCAN_INTERVAL_MS? Si es así, ¿qué tan grande?
Si busca BW13_DayOne_Session1 Bluetooth Advanced
en google, encontrará un documento pdf que le proporciona las latencias de los dispositivos según la configuración de descubrimiento (consulte la página 8). Supongo que su problema tiene que ver con estos tiempos. Puede verificar la configuración de publicidad para el dispositivo que está probando (Adv Int, Duty Cycle) y luego averiguar qué están haciendo las configuraciones API para configurar el intervalo de exploración, etc. Una vez que tenga estas, puede usar esa tabla. interpolar para ver si está obteniendo los resultados que espera.
Sé que este es un sitio de software, pero a menudo, cuando se conecta con el hardware, necesita conocer el protocolo, de lo contrario, estará filmando en la oscuridad.