Android 4.3 Bluetooth de baja energía inestable

Actualmente estoy desarrollando una aplicación que usará Bluetooth Low Energy (prueba en el Nexus 4). Después de comenzar con las API BLE oficiales en Android 4.3, me di cuenta de que, después de conectar un dispositivo por primera vez, casi nunca puedo conectarme o comunicarme con ese dispositivo o cualquier otro dispositivo.

Siguiendo la guía aquí , puedo conectarme con éxito a un dispositivo, escanear servicios y características, y leer / escribir / recibir notificaciones sin ningún problema. Sin embargo, después de desconectarme y volver a conectarme, a menudo no puedo escanear servicios / características o no puedo completar una lectura / escritura. No puedo encontrar nada en los registros para indicar por qué ocurre esto.

Una vez que esto sucede, tengo que desinstalar la aplicación, desactivar Bluetooth y reiniciar el teléfono antes de que vuelva a funcionar.

Cada vez que se desconecta un dispositivo, me aseguro de llamar a close () en el objeto BluetoothGatt y establecerlo como nulo. ¿Alguna idea?


EDITAR:
Volcados de registro: para estos registros, rooteé mi teléfono y subí los niveles de rastreo de elementos relacionados en /etc/bluetooth/bt_stack.conf

Conexión exitosa : primer bash después de reiniciar el teléfono e instalar la aplicación. Puedo conectarme, descubrir todos los servicios / características, y leer / escribir.

Intento fallido 1 – Este es el siguiente bash después de desconectarse de la conexión exitosa anterior. Parece que pude descubrir características, pero el primer bash de leer devolvió un valor nulo y se desconectó poco después.

Intento fallido 2 : un ejemplo en el que ni siquiera puedo descubrir servicios / características.


EDICION 2:
El dispositivo al que bash conectarme está basado en el chip CC2541 de TI. Obtuve un TI SensorTag (también basado en el CC2541) para jugar y descubrí que TI lanzó ayer una aplicación de Android para el SensorTag. Sin embargo, esta aplicación tiene el mismo problema. Probé esto en otros dos Nexus 4 con el mismo resultado: la conexión al SensorTag es exitosa la primera o la segunda vez, pero (de acuerdo con los registros) no puede descubrir los servicios a partir de entonces, lo que provoca todo tipo de lockings. Estoy empezando a preguntarme si es un problema con este chip específico.

Importantes consejos de implementación

(Quizás algunas de esas sugerencias ya no sean necesarias debido a las actualizaciones del sistema operativo Android).

  1. Algunos dispositivos como Nexus 4 con Android 4.3 tardan más de 45 segundos en conectarse utilizando una instancia de gatt existente . Solución: siempre cierre las instancias gatt al desconectarse y cree una nueva instancia de gatt en cada conexión.
  2. No te olvides de llamar a android.bluetooth.BluetoothGatt#close()
  3. Inicie un nuevo hilo dentro onLeScan(..) y luego conéctese. Motivo: BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback) siempre falla, si se llama dentro de LeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) en el mismo hilo en Samsung Galaxy S3 con Android 4.3 (al menos para la comstackción JSS15J.I9300XXUGMK6)
  4. La mayoría de los dispositivos filtran publicidad
  5. Mejor no usar android.bluetooth.BluetoothAdapter#startLeScan(UUID[] serviceUuids, LeScanCallback callback) con el parámetro para filtrar ciertos UUID de servicio porque está completamente roto en Samsung Galaxy S3 con Android 4.3 y no funciona para UUID de 128bit en general .
  6. Gatt siempre puede procesar un comando a la vez . Si varios comandos se llaman cortos después de otro, el primero se cancela debido a la naturaleza sincrónica de la implementación de gatt.
  7. A menudo veo incluso en dispositivos modernos con Android 5, que Wifi interfiere con bluetooth y viceversa. Como último recurso, apague wifi para estabilizar bluetooth.

Tutorial para principiantes

Un punto de entrada bastante bueno para los recién llegados podría ser este video tutorial: Desarrollo de aplicaciones inteligentes Bluetooth para Android http://youtu.be/x1y4tEHDwk0

El problema y el trabajo descrito a continuación probablemente ya esté solucionado por las actualizaciones del sistema operativo

Solución: podría “estabilizar” mi aplicación haciendo eso …

  1. Proporciono al usuario una configuración “Reiniciar Bluetooth”. Si esa configuración está habilitada, reinicio Bluetooth en algunos puntos que indican que el inicio de la stack BLE se vuelve inestable. Por ejemplo, si startScan devuelve falso. Un buen punto también puede ser si serviceDiscovery falla. Simplemente apago y enciendo Bluetooth.
  2. Proporciono otra configuración “Desactivar WiFi”. Si esa configuración está habilitada, mi aplicación apaga Wifi cuando la aplicación se está ejecutando (y luego la vuelve a encender)

Este trabajo se basa en experiencias pasadas …

  • Reiniciar Bluetooth ayuda a solucionar problemas con BLE en la mayoría de los casos
  • Si desactiva Wifi, la stack BLE se vuelve mucho más estable. Sin embargo, también funciona bien en la mayoría de los dispositivos con wifi activado.
  • Si desactiva Wifi, al reiniciar Bluetooth se recupera completamente la stack BLE sin la necesidad de reiniciar el dispositivo en la mayoría de los casos.

Desactivando WIFI:

Puedo confirmar también, que al desactivar WIFI hace que Bluetooth 4.0 sea más estable, especialmente en Google Nexus (tengo un Nexus 7).

El problema

es que la aplicación que estoy desarrollando necesita tanto WIFI como el escaneo continuo de Bluetooth LE . Así que apagar WIFI no era una opción para mí.

Además, me he dado cuenta de que el escaneo continuo de Bluetooth LE puede matar la conexión WIFI y hacer que el adaptador WIFI no pueda volver a conectarse a ninguna red WiFi hasta que el escaneo BLE esté activado. (No estoy seguro acerca de las redes móviles e internet móvil).
Esto definitivamente sucedió en los siguientes dispositivos:

  • Nexus 7
  • Motorola Moto G

Sin embargo, el escaneo BLE con WIFI parecía bastante estable en:

  • Samsung s4
  • HTC One

Mi solución

Escano BLE durante un corto período de tiempo 3-4 segundos y luego apago el escaneo por 3-4 segundos . Luego, otra vez.

  • Obviamente, siempre apago BLE scan cuando me conecto a un dispositivo BLE.
  • Cuando me desconecto de un dispositivo reinicio BLE (apago el adaptador y luego lo enciendo) para restablecer la stack antes de comenzar a escanear nuevamente.
  • También reinicié BLE cuando falla el descubrimiento de services o characteristics .
  • Cuando obtengo datos publicitarios de un dispositivo al que la aplicación debe conectarse (digamos 500 veces sin poder conectar, eso es alrededor de 5-10 segundos de publicidad) reinicié BLE nuevamente.

Asegúrate de que tu Nexus esté sincronizado con el dispositivo. No puedo verificar si la comunicación funciona correctamente o no, pero podrá conectarse más de una vez sin reiniciar. Parece que la primera conexión no requiere vinculación, pero todos los bashs subsiguientes sí lo requieren.

Actualizaré esta respuesta en un par de días cuando pruebo la detección de servicios y grabe las solicitudes de lectura y escritura sin reiniciar.

EDITAR: Resultó que estaba probando en una versión de firmware de desarrollo (nuestro sensor) que estaba causando problemas si no estaba emparejado. Nuestra última versión de firmware de producción funciona bien en los 2540 y 2541.

EDITAR: Me di cuenta de que en el Nexus 7 2013, las conexiones son más estables cuando WiFi está desactivado. Me gustaría saber si esto ayuda a alguien más.

EDITAR: parece que lo tuve al revés con el emparejamiento. Todo funciona bien cuando no está sincronizado. Después del emparejamiento, estoy experimentando exactamente los mismos síntomas que el OP. Todavía no se sabe si esto está relacionado con nuestro firmware o la API BLE de Android. Tenga cuidado si prueba esto porque una vez emparejado, es posible que no pueda deshacer la conexión debido a un error explicado en 3b de esta publicación .

En algunos modelos, existe un defecto: https://code.google.com/p/android/issues/detail?id=180440

Por otro lado, en mi caso, el problema era que mi conexión no se cerraba correctamente en el método Destroy. Después del cierre correcto, el problema para mí no existe, no importa si el wifi está encendido o apagado.

 btGatt.disconnect(); btGatt.close();