studio scanner recibir para libreria dispositivos detectar datos buscar app android bluetooth-lowenergy

scanner - Android 4.3: cómo conectarse a múltiples dispositivos Bluetooth Low Energy



modulo bluetooth en android studio (5)

Mi pregunta es: ¿Puede Android 4.3 (cliente) tener conexiones activas con múltiples dispositivos BLE (servidores)? Si es así, ¿cómo puedo lograrlo?

Lo que hice hasta ahora

Intento evaluar qué rendimiento puedes lograr con BLE y Android 4.3 BLE API. Además, también trato de averiguar cuántos dispositivos pueden estar conectados y activos al mismo tiempo. Uso un Nexus 7 (2013), Android 4.4 como maestro y TI CC2540 Keyfob como esclavos.

Escribí un software de servidor simple para los esclavos, que transmite 10000 paquetes de 20 bits a través de notificaciones BLE. Basé mi aplicación de Android en el acelerador de aplicaciones de Bluetooth SIG.

Funciona bien para un dispositivo y puedo lograr un rendimiento de carga útil de alrededor de 56 kBits con un intervalo de conexión de 7,5 ms. Para conectarme a varios esclavos, seguí el consejo de un empleado nórdico que escribió en la zona de desarrolladores nórdicos :

Sí, es posible manejar múltiples esclavos con una sola aplicación. Debería manejar cada esclavo con una instancia de BluetoothGatt. También necesitaría BluetoothGattCallback específico para cada esclavo a quien se conecte.

Así que lo intenté y en parte funciona. Puedo conectarme a múltiples esclavos. También me puedo registrar para recibir notificaciones sobre múltiples esclavos. El problema comienza cuando comienzo la prueba. Recibo al principio notificaciones de todos los esclavos, pero después de un par de Intervalos de conexión solo llegan las notificaciones de un dispositivo. Después de unos 10 segundos, los otros esclavos se desconectan, ya que parecen alcanzar el tiempo de espera de conexión. A veces recibo desde el inicio de la prueba solo notificaciones de un esclavo.

También intenté acceder al atributo sobre una operación de lectura con el mismo resultado. Después de un par de lecturas, solo llegaron las respuestas de un dispositivo.

Soy consciente de que hay algunas preguntas similares en este foro: ¿Admite Android 4.3 múltiples conexiones de dispositivo BLE? , ¿Tiene nativa Android BLE GATT implementación naturaleza sincrónica? o Ble conexión múltiple . Pero ninguna de estas respuestas me lo dejó claro, si es posible y cómo hacerlo.

Estaría muy agradecido por el consejo.


Estoy desarrollando una aplicación con funciones BLE. La forma en que logré conectarme a múltiples dispositivos y activar las notificaciones fue implementar retrasos.

Así que hago un nuevo hilo (para no bloquear el hilo de UI) y en el nuevo hilo conecto y activo las notificaciones.

Por ejemplo, después de BluetoothDevice.connectGatt (); llama a Thread.sleep ();

Y agregue el mismo retraso para las notificaciones de lectura / escritura y activación / desactivación.

EDITAR

Utilice wait like this para que Android no haya generado ANR

public static boolean waitIdle() { int i = 300; i /= 10; while (--i > 0) { if (true) try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } return i > 0; }


Lamentablemente, las notificaciones en la pila actual de Android BLE son un poco problemáticas. Hay algunos límites codificados y he encontrado algunos problemas de estabilidad incluso con un solo dispositivo. (Leí en un momento que solo podía tener 4 notificaciones ... no estoy seguro de si eso está en todos los dispositivos o por dispositivo. Tratando de encontrar el origen de esa información ahora).

Intentaría cambiar a un ciclo de sondeo (por ejemplo, sondear los ítems en la pregunta 1 / seg) y ver si encuentra que su estabilidad aumenta. También consideraría cambiar a un dispositivo esclavo diferente (por ejemplo, un HRM o el SensorTag de TI) para ver si hay un problema con el código del lado del esclavo (a menos que pueda probarlo con iOS u otra plataforma y confirmar que no es parte del problema).

Editar : referencia para la limitación de notificaciones


Rain tiene razón en su respuesta, necesitas retrasos para casi todo cuando trabajas con BLE en Android. Desarrollé varias aplicaciones con él y es realmente necesario. Al usarlos evitarás muchos bloqueos.

En mi caso, uso retrasos después de cada comando de lectura / escritura. Al hacerlo, se asegura de que reciba la respuesta del dispositivo BLE casi siempre. Hago algo como esto: (por supuesto, todo se hace en un hilo separado para evitar mucho trabajo en el hilo principal)

readCharacteristic(myChar); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } myChar.getValue();

o:

myChar.setValue(myByte); writeCharacteristic(myChar); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); }

Esto es realmente útil cuando lee / escribe varias características seguidas ... Como Android es lo suficientemente rápido para ejecutar los comandos casi al instante, si no usa un retraso entre ellos, puede obtener errores o valores incoherentes ...

Espero que ayude incluso si no es exactamente la respuesta a tu pregunta.


Sospecho que todos los que agregan demoras solo permiten que el sistema BLE complete la acción que usted hizo antes de enviar otra. El sistema BLE de Android no tiene forma de hacer cola. Si lo haces

BluetoothGatt g; g.writeDescriptor(a); g.writeDescriptor(b);

luego, la primera operación de escritura se sobrescribirá inmediatamente con la segunda. Sí, es realmente estúpido y la documentación probablemente debería mencionar esto.

Si inserta una espera, permite que la primera operación se complete antes de hacer la segunda. Aunque eso es un gran hack feo. Una mejor solución es implementar su propia cola (como Google debería tener). Afortunadamente, Nordic ha lanzado uno para nosotros.

https://github.com/NordicSemiconductor/puck-central-android/tree/master/PuckCentral/app/src/main/java/no/nordicsemi/puckcentral/bluetooth/gatt

Editar: Por cierto, este es el comportamiento universal para las API BLE. WebBluetooth se comporta de la misma manera (pero Javascript hace que sea más fácil de usar), y creo que la API BLE de iOS también se comporta de la misma manera.


bluetooth-lowenergy problema bluetooth-lowenergy en android android : sigo usando retrasos.

El concepto: después de cada acción importante que provoca el BluetoothGattCallback (por ejemplo, detección, descubrimiento de servicio, escritura, lectura) es necesario un acuerdo. PD: eche un vistazo al ejemplo de Google en la muestra del nivel 19 de la API BLE para la conectividad, a fin de comprender cómo se deben enviar las transmisiones y obtener una comprensión general, etc.

En primer lugar, scan (o scan ) para dispositivos Bluetooth, complete la conexión de cola con los dispositivos deseados y llame a initConnection () .

Echa un vistazo al siguiente ejemplo.

private Queue<BluetoothDevice> connectionQueue = new LinkedList<BluetoothDevice>(); public void initConnection(){ if(connectionThread == null){ connectionThread = new Thread(new Runnable() { @Override public void run() { connectionLoop(); connectionThread.interrupt(); connectionThread = null; } }); connectionThread.start(); } } private void connectionLoop(){ while(!connectionQueue.isEmpty()){ connectionQueue.poll().connectGatt(context, false, bleInterface.mGattCallback); try { Thread.sleep(250); } catch (InterruptedException e) {} } }

Ahora, si todo está bien, ha realizado las conexiones y se ha llamado a BluetoothGattCallback.onConnectionStateChange (BluetoothGatt gatt, int status, int newState) .

public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { switch(status){ case BluetoothGatt.GATT_SUCCESS: if (newState == BluetoothProfile.STATE_CONNECTED) { broadcastUpdate(BluetoothConstants.ACTION_GATT_CONNECTED, gatt); }else if(newState == BluetoothProfile.STATE_DISCONNECTED){ broadcastUpdate(BluetoothConstants.ACTION_GATT_DISCONNECTED, gatt); } break; } } protected void broadcastUpdate(String action, BluetoothGatt gatt) { final Intent intent = new Intent(action); intent.putExtra(BluetoothConstants.EXTRA_MAC, gatt.getDevice().getAddress()); sendBroadcast(intent); }

Es posible que deba enviarse PS sendBroadcast (intento) de esta manera:

Context context = activity.getBaseContext(); context.sendBroadcast(intent);

Luego BroadcastReceiver.onReceive(...) recibe la BroadcastReceiver.onReceive(...)

public BroadcastReceiver myUpdateReceiver = new BroadcastReceiver(){ @Override public void onReceive(Context context, Intent intent) { final String action = intent.getAction(); if(BluetoothConstants.ACTION_GATT_CONNECTED.equals(action)){ //Connection made, here you can make a decision: do you want to initiate service discovery. // P.S. If you are working with multiple devices, // make sure that you start the service discovery // after all desired connections are made } .... } }

Después de hacer lo que quieras en el receptor de la transmisión, aquí es cómo continúo:

private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>(); private void initServiceDiscovery(){ if(serviceDiscoveryThread == null){ serviceDiscoveryThread = new Thread(new Runnable() { @Override public void run() { serviceDiscovery(); serviceDiscoveryThread.interrupt(); serviceDiscoveryThread = null; } }); serviceDiscoveryThread.start(); } } private void serviceDiscovery(){ while(!serviceDiscoveryQueue.isEmpty()){ serviceDiscoveryQueue.poll().discoverServices(); try { Thread.sleep(250); } catch (InterruptedException e){} } }

De nuevo, después de un descubrimiento exitoso del servicio, se llama a BluetoothGattCallback.onServicesDiscovered(...) . De nuevo, envío un intento al BroadcastReceiver (esta vez con una cadena de acción diferente) y es ahora que puede comenzar a leer, escribir y habilitar notificaciones / indicaciones ... PD Si está trabajando con varios dispositivos, asegúrese de comenzar la lectura, escritura, etc ... cosas después de que todos los dispositivos hayan informado que sus servicios han sido descubiertos.

private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>(); private void startThread(){ if(initialisationThread == null){ initialisationThread = new Thread(new Runnable() { @Override public void run() { loopQueues(); initialisationThread.interrupt(); initialisationThread = null; } }); initialisationThread.start(); } } private void loopQueues() { while(!characteristicReadQueue.isEmpty()){ readCharacteristic(characteristicReadQueue.poll()); try { Thread.sleep(BluetoothConstants.DELAY); } catch (InterruptedException e) {} } // A loop for starting indications and all other stuff goes here! }

BluetoothGattCallback tendrá todos sus datos entrantes del sensor BLE. Una buena práctica es enviar una transmisión con los datos a su BroadcastReceiver y manejarlo allí.