web-dev-qa-db-fra.com

BLE startScan a diminué les appareils détectés sur Android 5.0 Lollipop

Version courte:

Dans mes tests avec Android 5.0 Lollipop, j'ai remarqué Android.bluetooth.le.BluetoothLeScanner détecte les périphériques BLE moins fréquemment que Android 4.4 KitKat Pourquoi est-ce et existe-t-il une alternative?

Version longue:

Je développe une Android, spécialement pour la tablette Nexus 7, qui se concentre sur la détection des appareils Bluetooth Low Energy (BLE). L'application s'intéresse principalement à la valeur RSSI des balises, pour déterminer leur proximité avec la tablette. Cela signifie que je n'aurai pas besoin de me connecter au périphérique BLE, car la valeur RSSI est transmise au rappel de numérisation lorsque le périphérique est détecté.

Dans Android 4.4 KitKat, lorsque j'appelle BluetoothAdapter.startLeScan(LeScanCallback), mon rappel n'est appelé UNE FOIS pour chaque périphérique BLE détecté. (J'ai vu quelques discussions prétendent que ce comportement peut différer selon l'appareil) Cependant, je suis intéressé par la valeur RSSI en constante évolution, donc la méthode actuellement recommandée est de faire en continu startLeScan et stopLeScan avec un intervalle défini (250 ms dans mon cas):

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
        }
    };

}

Essentiellement, cela me donne les résultats requis, mais ce processus est très gourmand en ressources et conduit finalement à un adaptateur Bluetooth qui ne répond pas.

Pour ces raisons, j'ai mis à niveau mon Nexus 7 vers Android 5.0 Lollipop, pour voir si mes problèmes BLE seraient résolus. Dans Lollipop BluetoothAdapter.startLeScan (LeScanCallback) est obsolète et remplacé par a nouvelle API qui permet un plus grand contrôle sur le processus de numérisation. De mes premiers tests, il semble que startScan n'appelle pas continuellement mon rappel (sur mon Nexus 7) lorsque les valeurs RSSI changent, donc j'ai encore besoin d'utiliser le startScan/implémentation 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
        }
    };

}

Comme vous pouvez le voir, j'ai configuré le scanner à l'aide de la classe ScanSettings, qui vous permet de définir le scanMode. J'utilise ScanSettings.SCAN_MODE_LOW_LATENCY, Qui contient la documentation suivante: "Numériser en utilisant le rapport cyclique le plus élevé. Il est recommandé d'utiliser uniquement ce mode lorsque l'application s'exécute au premier plan." Cela ressemble exactement à ce que je veux, mais malheureusement, je ne reçois une détection de balise que toutes les 15 à 30 secondes, où la version KitKat me montre la même balise toutes les 1 à 2 secondes sur cet intervalle de balayage.

Avez-vous une idée de ce qui pourrait être la raison de cette différence? Suis-je en train de manquer quelque chose, peut-être de nouveaux paramètres? Existe-t-il d'autres façons de procéder?

Merci beaucoup d'avance!

Abel

PS: Je voulais inclure plus de liens vers les ressources que j'ai utilisées, mais je n'ai pas encore les points de représentant pour cela.

20
abelcookingfox

J'ai obtenu des résultats très différents avec un Nexus 5 exécutant les nouvelles Android 5.0 API de numérisation. Les détections de paquets BLE sont arrivées presque en temps réel lors de l'utilisation de SCAN_MODE_LOW_LATENCY, à toutes les 100 ms pour les balises BLE transmettant à 10 Hz .

Vous pouvez lire les résultats complets ici:

http://developer.radiusnetworks.com/2014/10/28/Android-5.0-scanning.html

Ces tests sont basés sur l'exécution de la source ouverte Android Branche Android-l-apis expérimentale de Beacon Library 2.0 ici .

La différence entre les résultats de vos tests n'est pas évidente, mais il est possible que le démarrage et l'arrêt de la numérisation modifient les résultats.

EDIT: il est possible que le matériel soit la différence. Voir un rapport d'horaires similaires sur le Nexus 4: https://github.com/AltBeacon/Android-beacon-library/issues/59#issuecomment-64281446

6
davidgyoung

Je n'ai pas encore 50 points de réputation pour un commentaire, alors restez avec moi, ce commentaire prendra la forme d'une réponse. Dans votre code, cette partie ne devrait-elle pas:

if (isScanning) { scanner.startScan(...)

être ceci à la place:

if (!isScanning) {
 scanner.startScan(...)

Parce que suivant votre code, vous appelez stopScan () avant de démarrer une analyse. Il peut ne pas avoir d'effet direct sur le résultat si la méthode stopScan () est idempotente/sûre. Mais vous savez, pour des raisons d'intelligibilité du code, vous devez modifier la question. Et faites de même avec votre code, parfois des choses byzantines sont en jeu;)

Avez-vous essayé des valeurs plus grandes pour SCAN_INTERVAL_MS? Si oui, quelle taille?

5
kurt

J'ai connu des résultats très similaires avec mon Nexus 4, à la fois dans KitKat et Lollipop.

Avec KitKat, l'adaptateur Bluetooth est finalement devenu insensible; au début, je pensais que cela pouvait être lié à un intervalle de balayage court (200 ms), mais augmenter ce nombre à une seconde n'a pas aidé, dans ce domaine, j'ai trouvé que, lorsque la désactivation et l'activation de l'adaptateur ne répondaient pas, cela résout parfois le problème . Malheureusement, je ne peux pas dire que cela fonctionne tout le temps.

Maintenant, avec Lollipop, dans lequel j'avais de grands espoirs de résoudre ces problèmes, j'ai connu le même comportement que vous décrivez. J'ai également dû utiliser l'implémentation startScan/stopScan, obtenant des résultats similaires concernant les temps de détection. Malheureusement, je n'ai pas trouvé de solution pour obtenir des résultats plus rapidement.

Sur la base de ce que vous décrivez, je suppose que cela pourrait être un problème matériel, même si les Nexus 7 et Nexus 4 sont de fabricants différents (Asus et LG).

Je sais que je n'apporte pas beaucoup d'aide ici en plus d'essayer de répondre à votre question sur le fait que vous avez raté quelque chose; Je ne pense pas, je pense que le problème est quelque chose comme le matériel ou l'API Bluetooth qui ne se comporte toujours pas comme il devrait sur différents appareils.

2
marp

Au-delà de l'API 21 Android utilise SCAN_MODE_LOW_POWER par défaut. SCAN_MODE_LOW_POWER

Essayez SCAN_MODE_BALANCED et voyez si cela s'améliore.
SCAN_MODE_BALANCED

1
Nowa Concordia

si vous recherchez BW13_DayOne_Session1 Bluetooth Advanced sur google, vous trouverez un document pdf qui vous donne les latences des appareils en fonction des paramètres de découverte (voir page 8). Je suppose que votre problème est lié à ces horaires. Vous pouvez vérifier en déterminant la configuration publicitaire de l'appareil que vous testez (Adv Int, Duty Cycle) puis comprendre ce que font les paramètres de l'API pour configurer l'intervalle d'analyse, etc. Une fois que vous les avez, vous pouvez ensuite utiliser ce tableau pour interpoler pour voir si vous obtenez les résultats attendus.

Je sais que c'est un site de logiciel, mais souvent lors de l'interfaçage avec du matériel, vous devez connaître le protocole sinon votre prise de vue dans l'obscurité.

0
Joel Kindem