• Servidor Bluetooth con BlueCove y Cliente Android

    Hoy vamos a aprender a montar una aplicación Java en nuestro ordenador que implemente un servidor Bluetooth mediante BlueCove que utilice información que enviemos mediante un dispositivo móvil con una app en Android. Necesitaremos:

    • Un adaptador bluetooth para el PC si no lo tuviera integrado.
    • La librería Java BlueCove. (Necesitaremos los ficheros bluecove-2.1.1-SNAPSHOT.jar y bluecove-gpl-2.1.1-SNAPSHOT.jar.
    • Un dispositivo móvil Android, obviamente.

    Servidor Bluetooth

    En este caso, la información que vamos a enviar y recibir son las coordenadas XYZ del acelerómetro de nuestro dispositivo. Así que las guardaremos en 3 variables.

    La librería BlueCove hará de intermediario entre nuestra aplicación y nuestro módulo Bluetooth del ordenador. Usar esta librería externa es completamente necesario dado que no disponemos de métodos de control Bluetooth en Java Lang.

    Arquitectura BlueCove

    El UUID es el identificador del servicio Bluetooth del dispositivo. Es así que un dispositivo móvil ofrece un UUID por cada aplicación que envíe datos (Cámara, Mando a distancia…) El UUID adecuado para este tipo de aplicaciones es el UUID por defecto, ya que al asignar otro UUID podría entrar en conflicto con otros servicios.

    import java.io.DataInputStream;
    import java.io.EOFException;
    import java.io.IOException;
    import javax.bluetooth.DiscoveryAgent;
    import javax.bluetooth.LocalDevice;
    import javax.microedition.io.Connector;
    import javax.microedition.io.StreamConnection;
    import javax.microedition.io.StreamConnectionNotifier;
    
    public class BluetoothServer implements Runnable {
     // UUID por defecto. No cambiar.
     static final String deviceUUID = "0000110100001000800000805F9B34FB";
     public static float accelerometerX, accelerometerY, accelerometerZ;
     static StreamConnectionNotifier server;
    
     public void run() {
     try {
     // Comenzar Servidor
     // Ajustar dispositivo local (Servidor) como "descubriendo".
     LocalDevice.getLocalDevice().setDiscoverable(DiscoveryAgent.GIAC);
    
    // Nombre del servicio a gusto del consumidor
     String url = "btspp://localhost:" + deviceUUID
     + ";name=BlueToothServer";
    
     server = (StreamConnectionNotifier) Connector.open(url);
     // El método por separado permite reconectar en caso de caida del cliente.
     receive();
     } catch (IOException e) {
     System.out.println("FATAL ERROR: Error while creating the server. " + e.getMessage());
     }
     }
    
     public void receive() throws IOException {
    
     // Espera hasta que el cliente se conecta
     StreamConnection connection = server.acceptAndOpen();
     DataInputStream dis = connection.openDataInputStream();
    
     while (true) {
     try {
     accelerometerX = dis.readFloat();
     accelerometerY = dis.readFloat();
     accelerometerZ = dis.readFloat();
     } catch (EOFException e) {
     break;
     }
     }
    
     connection.close();
     // No deja de escuchar aunque el cliente se desconecte momentaneamente.
     receive();
     }
    }
    
    

    En caso de que queramos implementar este servidor en nuestra aplicación Java para escritorio:

    BluetoothServer server = new BluetoothServer();
    // Comienza el servidor en otro hilo.
    Thread serverThread = new Thread(server);
    serverThread.start();
    // Imprime por pantalla la coordenada X
    System.out.println(BluetoothServer.accelerometerX);
    

    Cliente Bluetooth

    En el cliente Bluetooth Android no nos hará falta importar las librerías BlueCove, debido a que Android ya ofrece funcionalidades de control adecuadas sobre Bluetooth.

    Pasaremos a editar la clase principal de toda aplicación de Android: el AndroidLauncher.java

    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Set;
    import java.util.UUID;
    import android.bluetooth.BluetoothAdapter;
    import android.bluetooth.BluetoothDevice;
    import android.bluetooth.BluetoothSocket;
    import android.content.Intent;
    import android.os.Bundle;
    
    public class AndroidLauncher extends AndroidApplication {
    	private final SensorManager mSensorManager;
        private final Sensor mAccelerometer;
        // Aqui guardaremos las coordenadas del acelerómetro local
        public static float accelerometerX, accelerometerY, accelerometerZ;
    	private static final int REQUEST_ENABLE_BT = 0;
    	private static final int REQUEST_DISCOVERABLE_BT = 0;
    	private BluetoothSocket btSocket = null;
    	private DataOutputStream outStream = null;
    	private static String serverAddress = "00:15:83:0C:BF:EB";
    	private static final UUID BLUETOOTH_SPP_UUID = UUID
    			.fromString("00001101-0000-1000-8000-00805f9b34fb");
    
    	@Override
    	protected void onCreate(Bundle savedInstanceState) {
             mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
             mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
    		// INICIO APP ANDROID
    	}
    
         sensorManager.registerListener(new SensorEventListener() {
        @Override
        public void onSensorChanged(SensorEvent event) {
              // Actualizamos las coordenadas
            accelerometerX = event.values[0];
            accelerometerY = event.values[1];
            accelerometerZ = event.values[2];
    
        }
    
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
        }
    
    }, sensor, SensorManager.SENSOR_DELAY_FASTEST);
    

    A continuación vamos definiendo los métodos que podremos invocar durante la aplicación. Los muestro de manera simplificada y separada para un uso mas cómodo.

    Dispositivo soporta Bluetooth

    Primera operación que debemos comprobar al inicio de la aplicación. Si nuestro dispositivo móvil no dispone de módulo Bluetooth, mal vamos.

    public static boolean supportsBluetooth() {
    		return BluetoothAdapter.getDefaultAdapter() != null;
    	}
    

    Solicitud activar Bluetooth

    En el caso de que el Bluetooth no estuviera activado, lanza una petición al usuario para activarlo.

    public void requestEnable() {
    		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    		if (!adapter.isEnabled()) {
    			Intent enableBtIntent = new Intent(
    					BluetoothAdapter.ACTION_REQUEST_ENABLE);
    			startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
    		}
    	}
    

    Solicitud de hacer visible al dispositivo

    Hacer visible al dispositivo es necesario para emparejarlo con otros dispositivos. No obstante, recomiendo emparejar los dispositivos de manera manual desde el menú de Android.

    public void requestDiscoverable() {
    		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    		if (!adapter.isDiscovering()) {
    			Intent enableBtIntent = new Intent(
    					BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
    			startActivityForResult(enableBtIntent, REQUEST_DISCOVERABLE_BT);
    		}
    	}
    

    Desactivar Bluetooth

    public void requestTurnOff() {
    		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    		if (adapter != null) {
    			adapter.disable();
    		}
    	}
    

    Lista de dispositivos emparejados

    Devuelve una lista con los nombres de los dispositivos emparejados, listos para ser mostrados en pantalla. Si quisieramos operar con otros datos de cada dispositivo solo hay que devolver un Set de BluetoothDevice.

    public List<String> pairedDevices() {
    		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    		Set<BluetoothDevice> pairedDevices = adapter.getBondedDevices();
    		List<String> list = new ArrayList<String>();
    		for (BluetoothDevice bt : pairedDevices)
    			list.add(bt.getName());
    		return list;
    	}
    

    Conexión con el servidor

    public void startConnection(String device) {
    		BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    		BluetoothDevice btDevice = adapter.getRemoteDevice(serverAddress);
    		connect(btDevice);
    	}
    
    public BluetoothSocket connect(BluetoothDevice device) {
    		try {
    
    			btSocket = device
    					.createRfcommSocketToServiceRecord(BLUETOOTH_SPP_UUID);
    			Method m = null;
    			try {
    				m = device.getClass().getMethod("createInsecureRfcommSocket",
    						new Class[] { int.class });
    			} catch (NoSuchMethodException e1) {
    				e1.printStackTrace();
    			} catch (SecurityException e1) {
    				e1.printStackTrace();
    			}
    			try {
    				btSocket = (BluetoothSocket) m.invoke(device, 1);
    			} catch (IllegalAccessException e) {
    				e.printStackTrace();
    			} catch (IllegalArgumentException e) {
    				e.printStackTrace();
    			} catch (InvocationTargetException e) {
    				e.printStackTrace();
    			}
    			// Cancel discovery will prevent from errors
    			BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
    		} catch (IOException e) {
    			e.printStackTrace();
    		}
    
    		// Establish the connection. This will block the app until it connects.
    		try {
    			btSocket.connect();
    			System.out
    					.println("\n...Connection established and data link opened...");
    		} catch (IOException e) {
    			try {
    				btSocket.close();
    			} catch (IOException e2) {
    				System.out
    						.println("Fatal Error. Unable to close socket during connection failure"
    								+ e2.getMessage() + ".");
    			}
    		}
    
    		System.out
    				.println("\n...Connection established and data link opened...");
    
    		return btSocket;
    	}
    

    Envío de datos

    Con este último método enviamos los datos. Podemos enviar mediante outStream una variable booleana, un entero o una cadena. Como deseemos.

    public void send() {
    		try {
    			outStream = new DataOutputStream(btSocket.getOutputStream());
    		} catch (IOException e) {
    			System.out.println("Fatal Error. Output stream creation failed.  "
    					+ e.getMessage());
    		}
    
    		try {
    			outStream.writeFloat(accelerometerX);
    			outStream.writeFloat(accelerometerY);
    			outStream.writeFloat(accelerometerZ);
    		} catch (IOException e) {
    			System.out.println("Check that the SPP UUID: "
    					+ BLUETOOTH_SPP_UUID.toString() + " exists on server.\n\n");
    		}
    	}
    

Un comentario por el momento.

  1. Anonimo dice:

    Perfecto funciono. y si se quisiera enviar y recibir datos como si de un chat se tratara?

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *

Puedes usar las siguientes etiquetas y atributos HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>