Android 4.3 Bluetooth Low Energy instable

189

Je développe actuellement une application qui utilisera Bluetooth Low Energy (test sur le Nexus 4). Après avoir commencé avec les API BLE officielles sous Android 4.3, j'ai remarqué qu'après avoir connecté un appareil pour la première fois, je suis rarement capable de me connecter / communiquer avec cet appareil ou tout autre appareil.

En suivant le guide ici , je peux me connecter avec succès à un appareil, analyser les services et les caractéristiques et lire / écrire / recevoir des notifications sans aucun problème. Cependant, après la déconnexion et la reconnexion, je suis souvent incapable d'analyser les services / caractéristiques ou de terminer une lecture / écriture. Je ne trouve rien dans les journaux pour indiquer pourquoi cela se produit.

Une fois que cela se produit, je dois désinstaller l'application, désactiver Bluetooth et redémarrer le téléphone avant qu'il ne recommence à fonctionner.

Chaque fois qu'un appareil est déconnecté, je m'assure d'appeler close () sur l'objet BluetoothGatt et de le définir sur null. Des idées?


EDIT:
Log dumps: Pour ces journaux, j'ai rooté mon téléphone et augmenté les niveaux de trace des éléments associés dans /etc/bluetooth/bt_stack.conf

Connexion réussie - Première tentative après le redémarrage du téléphone et l'installation de l'application. Je suis capable de me connecter, de découvrir tous les services / caractéristiques et de lire / écrire.

Tentative ratée 1 - Il s'agit de la prochaine tentative après la déconnexion de la connexion réussie ci-dessus. Il semble que j'ai pu découvrir des caractéristiques, mais la première tentative de lecture a renvoyé une valeur nulle et s'est déconnectée peu de temps après.

Tentative ratée 2 - Un exemple où je ne suis même pas en mesure de découvrir les services / caractéristiques.


EDIT 2:
Le périphérique auquel j'essaie de me connecter est basé sur la puce CC2541 de TI. J'ai obtenu un TI SensorTag (également basé sur le CC2541) pour jouer et j'ai découvert que TI avait publié une application Android pour le SensorTag hier. Cependant, cette application a le même problème. J'ai testé cela sur deux autres Nexus 4 avec le même résultat: la connexion au SensorTag est réussie la première ou la deuxième fois, mais (selon les journaux) ne parvient pas à découvrir les services par la suite, provoquant toutes sortes de plantages. Je commence à me demander si c'est un problème avec cette puce spécifique?

sa.shadow
la source
Veuillez publier des journaux complets de votre téléphone depuis le démarrage jusqu'à ce que vous soyez confronté au problème.
AAnkit du
3
J'utilise Samsung Galaxy S4 avec l'édition Google Android 4.3 installée; après de nombreuses connexions / déconnexions, lorsque je découvre des services, j'obtiens au hasard 129 (GATT_INTERNAL_ERROR) et un onConnectionStateChange avec le statut 133 (GATT_ERROR), state = BluetoothProfile.DEVICE_DISCONNECTED.
reTs
1
Pour une ou deux fois, j'ai reçu plusieurs rappels de statut 129 et 133 en peu de temps et je ne pourrais jamais recevoir de rappel dans BluetoothGattCallback jusqu'à ce que je redémarre mon appareil (mais la numérisation est bonne).
reTs
1
Oubliez de dire que je teste avec une dizaine d'appareils utilisant des puces TI (désolé je ne connais pas leurs modèles) et un appareil avec des puces nordiques. L'appareil avec des puces nordiques ne signale jamais d'erreur (pas assez pour prouver que le problème est spécifique à TI, cependant)
reTs
1
Je peux confirmer que ce problème existe toujours sur Samsung Galaxy S5 ( version de construction G900VVRU2BOG5 et G900VVRU2BOA8 ). Si j'efface les données de Paramètres> Gestionnaire d'applications >> Tous >> Bluetooth , cela fonctionne pendant un moment.
IronBlossom

Réponses:

184

Conseils de mise en œuvre importants

(Peut-être que certains de ces conseils ne sont plus nécessaires en raison des mises à jour du système d'exploitation Android.)

  1. Certains appareils comme le Nexus 4 avec Android 4.3 prennent plus de 45 secondes pour se connecter à l'aide d'une instance gatt existante . Solution: fermez toujours les instances gatt lors de la déconnexion et créez une nouvelle instance de gatt à chaque connexion.
  2. N'oubliez pas d'appeler android.bluetooth.BluetoothGatt#close()
  3. Démarrez un nouveau fil à l'intérieur onLeScan(..) , puis connectez-vous. Raison: BluetoothDevice#connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)échoue toujours, s'il est appelé à l'intérieur LeScanCallback() {...}.onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord)dans le même thread sur Samsung Galaxy S3 avec Android 4.3 (au moins pour la build JSS15J.I9300XXUGMK6)
  4. La plupart des appareils filtrent la publicité
  5. Mieux vaut ne pas utiliser android.bluetooth.BluetoothAdapter#startLeScan(UUID[] serviceUuids, LeScanCallback callback) avec le paramètre pour filtrer certains UUID de service, car cela est complètement cassé dans Samsung Galaxy S3 avec Android 4.3 et ne fonctionne pas pour les UUID 128 bits en général.
  6. Gatt peut toujours traiter une commande à la fois . Si plusieurs commandes sont appelées l'une après l'autre, la première est annulée en raison de la nature synchrone de l'implémentation gatt.
  7. Je vois souvent, même sur les appareils modernes avec Android 5, que le Wifi interfère avec le bluetooth et vice versa. En dernier recours, désactivez le wifi pour stabiliser le bluetooth.

Tutoriel pour les débutants

Un bon point d'entrée pour les nouveaux arrivants pourrait être ce tutoriel vidéo: Développement d'applications Bluetooth Smart pour Android http://youtu.be/x1y4tEHDwk0

Le problème et le contournement décrits ci-dessous sont probablement résolus maintenant par les mises à jour du système d'exploitation

Solution: je pourrais "stabiliser" mon application en faisant cela ...

  1. Je fournis à l'utilisateur un paramètre "Redémarrer Bluetooth". Si ce paramètre est activé, je redémarre Bluetooth à certains points qui indiquent que le début de la pile BLE devient instable. Par exemple, si startScan renvoie false. Un bon point peut également être si serviceDiscovery échoue. Je viens d'éteindre et de réactiver Bluetooth.
  2. Je propose un autre paramètre "Désactiver le WiFi". Si ce paramètre est activé, mon application désactive le Wi-Fi lorsque l'application est en cours d'exécution (et la rallume par la suite)

Ce travail est basé sur les expériences suivantes ...

  • Le redémarrage de Bluetooth permet de résoudre les problèmes de BLE dans la plupart des cas
  • Si vous désactivez le Wifi, la pile BLE devient beaucoup plus stable. Cependant, cela fonctionne également très bien sur la plupart des appareils avec le wifi activé.
  • Si vous désactivez le Wifi, le redémarrage de Bluetooth récupère complètement la pile BLE sans qu'il soit nécessaire de redémarrer l'appareil dans la plupart des cas.
Un seul monde
la source
33
Google, vous devez résoudre ce problème maintenant. Ce travail (je l'ai fait en plus parce que ça marche) est ridicule.
Chris Herbert
4
Parfois, la découverte de service réussira avec un statut 0 (en supposant qu'aucun problème), mais les lectures de caractéristiques donneront des valeurs NULL car elles ne sont essentiellement pas vraiment connectées ou les caractéristiques n'ont pas été découvertes (je vois cela dans le journal: 11-01 18:37: 32.131: WARN / BluetoothGatt (20119): exception non gérée: java.lang.NullPointerException)
Lo-Tan
2
@ Lo-Tan Je vérifie toujours après la découverte de service, si mon service attendu est inclus. Vous ne pouvez également jamais être sûr que la découverte de service donne un résultat. Parfois, je ne reçois aucun rappel. J'ai donc appliqué un délai d'expiration pour la découverte de services.
OneWorld
2
Mon expérience est la suivante: Samsung S3 (4.3) s'est reconnecté avec succès après la fermeture d'un client Gatt comme décrit au paragraphe 2 ci-dessus; en utilisant Nexus 4 & 7 (4.4.2) Je n'ai pas pu me reconnecter après la coupure de la connexion, même en redémarrant l'adaptateur BL, mais il peut être reconnecté automatiquement après 2 min
Konstantin Konopko
1
Quelqu'un peut-il confirmer si android.bluetooth.BluetoothGatt ne peut gérer qu'une seule opération GATT en attente PAR APPAREIL , PAR PROCESSUS ou PÉRIODE (c'est-à-dire sur tous les processus). Je suppose que c'est PAR APPAREIL, mais ce problème est tellement compliqué qu'il ne me surprendrait pas s'il en était autrement. Si la limitation est uniquement PAR APPAREIL, alors le système d'exploitation / appareil capable de gérer plusieurs opérations simultanées est la preuve que ce problème est purement dû à une faible implémentation naïve dans l'instance BluetoothAdapter que le système d'exploitation transmet à chaque processus (que j'avais supposé être un singleton dans tous les processus).
swooby
18

Désactiver le WIFI:

Je peux également confirmer que la désactivation du WIFI rend Bluetooth 4.0 plus stable, en particulier sur Google Nexus (j'ai un Nexus 7).

Le problème

est que l'application que je développe nécessite à la fois une analyse WIFI et Bluetooth LE en continu . Donc, désactiver le WIFI n'était pas une option pour moi.

De plus, j'ai réalisé que la numérisation Bluetooth LE continue peut en fait tuer la connexion WIFI et rendre l' adaptateur WIFI incapable de se reconnecter à un réseau WIFI tant que l'analyse BLE n'est pas activée. (Je ne suis pas sûr des réseaux mobiles et de l'Internet mobile).
Cela s'est certainement produit sur les appareils suivants:

  • Nexus 7
  • Motorola Moto G

Cependant, la numérisation BLE avec WIFI activé semblait assez stable sur:

  • Samsung s4
  • HTC One

Ma solution de contournement

Je scanne le BLE pendant une courte période de 3-4 secondes, puis je désactive le scan pendant 3-4 secondes . Puis à nouveau sur ON.

  • Évidemment, je désactive toujours le scan BLE lorsque je me connecte à un appareil BLE.
  • Lorsque je me déconnecte d'un appareil, je redémarre BLE (éteignez puis rallumez l'adaptateur) pour réinitialiser la pile avant de recommencer l'analyse.
  • Je réinitialise également BLE lors de la découverte servicesou characteristicséchoue.
  • Lorsque je reçois des données publicitaires d'un appareil auquel l'application doit se connecter (disons 500 fois sans pouvoir se connecter - c'est environ 5 à 10 secondes de publicité), je réinitialise à nouveau BLE.
benka
la source
Vous avez dit que je redémarre BLE après qu'un appareil est déconnecté. Supposons, si l'utilisateur transférait le fichier via une connexion Bluetooth. Ensuite, vous provoquerez l'échec de ce transfert Bluetooth à tout moment.
Rahul Rastogi
1
qu'entendez-vous par «éteindre et rallumer l'adaptateur»?
Marian Paździoch
Je suis d'accord, le Wifi et le Bluetooth sont en train de tuer les performances de l'application dans Moto G.
Nigilan
@ MarianPaździoch, par "éteindre et rallumer l'adaptateur" @ benka signifie BluetoothAdapter
Anup
9

Assurez-vous que votre Nexus est couplé à l'appareil. Je ne peux pas vérifier si la communication fonctionne correctement ou non, mais vous pourrez vous connecter plus d'une fois sans redémarrer. Il semble que la première connexion ne nécessite pas d'appairage, mais toutes les tentatives ultérieures le font.

Je mettrai à jour cette réponse dans quelques jours lorsque je testerai la découverte de services et gatt lire et écrire des requêtes sans redémarrage.

EDIT: Il s'avère que je testais une version de firmware de développement (notre capteur) qui causait des problèmes si elle n'était pas couplée. Notre dernière version de micrologiciel de production fonctionne bien sur les 2540 et 2541.

EDIT: J'ai remarqué que sur le Nexus 7 2013, les connexions sont plus stables lorsque le WiFi est désactivé. J'aimerais savoir si cela aide quelqu'un d'autre.

EDIT: Je semble l'avoir eu à l'envers avec l'appariement. Tout fonctionne bien lorsqu'il n'est pas jumelé. Après l'appairage, je ressens exactement les mêmes symptômes que l'OP. On ne sait tout simplement pas encore si cela est lié à notre firmware ou à l'API Android BLE. Soyez prudent si vous testez ceci car une fois couplé, vous ne pourrez peut-être pas vous déconnecter en raison d'un bogue expliqué dans 3b de cet article .

Mikt25
la source
Je me connecte et me reconnecte constamment à un appareil CC2541 sans aucune sorte d'appairage manuel ou de redémarrage.
dgel
Pour mon avis, il n'y a pas d'appairage nécessaire. Les documents officiels ne commentent pas non plus l'appariement. Je pourrais également effectuer une notification d'écriture, de lecture et de changement de caractéristique sans aucun couplage. Cependant, juste pour une courte période. Maintenant, il est à nouveau instable ... Le SAMSUNG BLE SKD v2.0 ne nécessitait pas non plus d'appairage et fonctionnait plutôt bien.
OneWorld
3
Je peux confirmer, c'est plus stable après avoir éteint le Wifi. Tout le monde devrait essayer ça.
OneWorld
1
Le fait que le couplage soit requis ou non dépend de la mise en œuvre de l'appareil. Les appareils nrf8002 nécessitent un couplage et les API Samsung 2.0 et 1.2 le prennent en charge. Il semble que le support officiel de l'API rencontre des problèmes avec l'aspect d'appairage car après avoir appairé un appareil ble, il semble impossible de dissocier!
Chris Herbert
2
J'ai un problème pour être incapable de dissocier. 1) allez dans votre menu bt, sélectionnez dissocier, supprimez le périphérique ble de la zone ou éteignez-le, sélectionnez le périphérique ble dans le menu bt et il essaiera de se coupler et échouera, puis réinitialisez le bluetooth. Lors de la réinitialisation, l'appareil sera dissocié.
Chris Herbert
7

Dans certains modèles, il y a un défaut: https://code.google.com/p/android/issues/detail?id=180440

D'un autre côté, dans mon cas, le problème était que ma connexion n'était pas correctement fermée dans la méthode onDestroy. Après la fermeture correcte, le problème pour moi n'existe pas, peu importe que le wifi soit activé ou désactivé.

btGatt.disconnect();
btGatt.close();
Krystian
la source
Pourquoi est-ce closenécessaire?
IgorGanapolsky
3
La procédure de fermeture correcte est la clé lorsque vous souhaitez connecter Bluetooth plusieurs fois. D'après mon expérience, cela fonctionne mieux si vous exécutez votre connexion Ble dans un service UNBOUND séparé afin que vous puissiez la démarrer et l'arrêter manuellement. Et que vous appelez mConnectedGatt.disconnect (); ble_device = null; dans votre inDestroy (). Dans mon cas, ce modèle fonctionne de manière stable sans problème.
medTech
4

J'étais confronté à un problème similaire. Ma solution était

if (Build.VERSION.SDK_INT >= 23) {
  mBluetoothGatt = device.connectGatt(this, false, mGattCallback, BluetoothDevice.TRANSPORT_LE);
} else {
  mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
}

& appeler fermer après la déconnexion.

Sam Reyes
la source