El trastero de José Juan Valid XHTML 1.1 Valid CSS! Estilo de página alternativo
Artículo creado en 2008.
Valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración sobre 7 comentarios.

Bluetooth

Bluetooth

Bluetooth es ya todo un estándar para la interconexión inalámbrica de dispositivos a corta distancia. Permite por ejemplo que con sólo acercarnos a nuestro ordenador, se sincronicen las agendas del ordenador y del teléfono móvil, o que con sólo entrar en el coche quede conectado el GPS, los mandos del volante y el teléfono móvil, de forma que podemos visualizar la ruta en el teléfono móvil y realizar y recibir llamadas usando los comandos del volante. Otros muchos usos pueden hacerse (y se hacen) pero no hablaremos aquí de ello.

Lo que ya no está tan claro, es que las aplicaciones reales utilicen todas las posibilidades de Bluetooth y además de forma correcta. Otras pegas como los tiempos de latencia en sincronizaciones, la escasa velocidad del canal, etc... supongo se irán resolviendo con el tiempo. En cualquier caso, el esquema general aportado por Bluetooth parece muy interesante.

Para más información puedes ir a http://www.bluetooth.org.

Conectando con Bluetooth

Cuando empecé a buscar información para realizar aplicaciones para Bluetooth leía con expectación que a la gente le parecían engorrosas las API para utilizar Bluetooth. Como todo, hasta que no le dedicas algo de tiempo, a uno le resulta desconocido y a priori no se entienden algunos esquemas o términos usados en la cuestión. Sin embargo, si bien es cierto que la documentación es amplia y engorrosa, en seguida uno se da cuenta que no hay muchas diferencias con TCP/IP, Sockets u otros. Sólo se trata de tener un poco de paciencia.

Bluetooth despliega un amplio repertorio de esquemas y protocolos de conexión, debido probablemente a la amplia variedad de aplicaciones empotradas sobre las que actúa. Si tu intención es servir o consumir alguno de los servicios de la amplísima gama disponibles (vídeo, audio, telefonía, archivos, impresión, pagos, tarjetas, datos telefónicos, mensajería, etc...) no te quedará más remedio que empaparte la documentación de la parte que te toque. No obstante, si lo que pretendes es hacer tu propia comunicación (por ejemplo entre tu aplicación J2ME y tu aplicación de escritorio) en muchos de los casos te será suficiente una conexión SPP (Serial Port Profile) que de forma sencilla te permite crear un canal (Stream) entre tu servidor y tus clientes.

Una descripción genérica de los pasos para crear esta comunicación mínima (pero útil) SPP serían:

Pero... ¿cómo se reconocen los dispositivos?, ¿y los servicios publicados?

Como Servidor somos un dispositivos más que será visible (audible, accesible, etc...) por cualquier otro dispositivo cercano (y tenga permisos, etc...), obviamente cada dispositivo del "conjunto visible" tiene su propia dirección (como las IP en TCP/IP). Cada dispositivo además, puede "publicar" los servicios que suministre y éstos tienen un identificador único establecido por quien crea el servicio (quien lo programa) y puede ser fijo o bien crearlo aleatoriamente (en cuyo caso deberá haber otros datos [como el nombre del servicio] que permitan identificarlo a los clientes que quieran conectar).

Como Cliente uno puede listar los dispositivos cercanos (o recordados) y saber si están conectados, su dirección, listar los servicios disponibles, etc...

Dónde y cómo implementar Bluetooth

A nivel físico, existen gran variedad de módulos para la interconexión de sistemas mediante Bluetooth que abstraen el nada trivial (a ese nivel) conjunto de acciones que deben implementarse. Si quieres incrustar la funcionalidad Bluetooth en algún circuito eléctrico te sugiero que busques información sobre ellos.

A nivel software existen diversas librerías en diversas plataformas para acceder a Bluetooth. Para utilizarlo en Java y más concretamente en dispositivos móviles (teléfonos móviles) lo normal sería usar la JSR-82. Para usarlo por ejemplo en entornos Windows está disponible en el SDK de plataforma Windows las API, sin embargo existen diversos proyectos que suministran librerías que simplifican todavía más el tema, una de ellas es InTheHand.

Implementar un servidor Bluetooth

Voy a describir cómo publicar un servicio Bluetooth y cómo procesar las peticiones de los clientes. En este caso, será una implementación sobre la librería JSR-82 para dispositivos móviles. No creo que tengas problemas en adaptarlo a tus necesidades, no obstante, decir que se compila sobre CLDC 1.0 y MIDP 1.1.

Lo normal cuando se crea un servicio, es que corra en background respecto de la aplicación principal, por ello, crearíamos una clase que extiende la Thread y espera a que se conecte algún cliente, así no detiene la ejecución normal de la aplicación:

public class BluetoothServer
   extends Thread {
   ...
   public BluetoothServer( ..parámetros... ) {
      ... preparación ...
   }
   ...
   public void run() {
      ...preparar servidor...
      while( seguir a la escucha ) {
         ... esperar cliente ...
         ... atender al cliente conectado ...
      }
   }
}

Para ejecutar el servidor, sólo tenemos que crear un objeto BluetoothServer y ejecutarlo en background:


   ...
   // Como seguramente querremos acceder a los miembros de nuestro servidor
   // (por ejemplo para detenerlo o consultar su estado) debemos tener un
   // miembro:
   private BluetoothServer server = null;
   ...

   // En el constructor...
   public MiAplicacion() {
      ...
      // Creamos un nuevo servidor:
      server = new BluetoothServer( ...parámetros... );
      // Lo iniciamos:
      server.Start();
      ...
   }

Hasta aquí es el mismo esquema que cualquier servidor al estilo TCP/IP o Sockets, sólo queda rellenar los detalles de la implementación, en este caso con sólo un vistazo al código creo es suficiente:

public void run() {

   // TRY por si hay problemas poder reportarlos:
   try {

      // Debemos formar la URL de servicio que viene a ser:
      String url = "btspp://";   // Tipo de servicio, en este caso SPP (Serial Port Profile)
      url += "localhost:";      // Dirección sobre la que servimos, esto sólo sería diferente
                           //      de localhost en el caso de disponer de varios periféricos
                           //      Bluetooth dentro del mismo sistema (como cuando tenemos
                           //      dos tarjetas de red).
      url += uuid;            // El GUID de nuestro servicio, podemos generar uno aleatoriamente
                           //      cada vez o reutilizar siempre el mismo (así podemos darle
                           //      "nombre" a nuestro servicio) sería algo así como que todo
                           //      el mundo sabe que el puerto para FTP es el 21.
      url += ";name=" + name;      // Lo suyo es dar un nombre "humano" al servicio, esto es bueno
                           //      para que el usuario del sistema cliente pueda identificarlo
                           //      correctamente.

      // Accedemos a nuestro dispositivo local, si hubiera varios, habría que elegir uno:
      LocalDevice local = LocalDevice.getLocalDevice();

      // Indicamos el tipo de descubrimiento, actualmente sólo están disponibles GIAC o LIAC que viene
      // a ser "visible para todos" u "oculto y sólo visible para los que me conocen":
      local.setDiscoverable( DiscoveryAgent.GIAC );

      // Abrimos el servidor y obtenemos su objeto:
      StreamConnectionNotifier server = (StreamConnectionNotifier) Connector.open( url );

      // Aquí nos quedamos en "listening", en escucha a los clientes, en este ejemplo, sólo conectamos
      // con uno, pero es trivial hacer un bucle para aceptar múltiples clientes:
      StreamConnection conn = server.acceptAndOpen();

      // Aquí pasará un tiempo, entre que nos ponemos a la escucha, nuestro servicio se publica,
      // el cliente se conecta, etc...

      // Ya tenemos el cliente conectado, ahora accedemos al canal creado y podemos leer o escribir
      // como sea necesario, en este caso, escribiremos:
      DataOutputStream dos = conn.openDataOutputStream();

      // Controlamos posibles errores concretos en la transmisión:
      try {
         // Dejamos el canal del cliente abierto mientras desde la aplicación nos dejen
         // activos:
         while( activo ) {

            // Aquí lo suyo es esperar a "algo", por ejemplo a que el servidor
            // genere datos para enviar al cliente.
            ...

            // Es frecuente también crear dos Thread por cliente, uno para las lecturas
            // y otro para las escrituras (así pueden estar en WAIT hasta que sea preciso).

            // Una vez tenemos los datos, escribimos:
            dos.write( datos );

         }

      } catch( Exception ex ) {
         System.printnl( "ERROR CLIENTE: " + ex.getMessage() );
      }

      // Cerramos todos los objetos creados:
      dos.close();
      conn.close();
      server.close();

   } catch( Exception ex ) {
      System.printnl( "ERROR SERVIDOR: " + ex.getMessage() );
   }

}

Implementar un cliente Bluetooth

Implementar un cliente Bluetooth es tanto más fácil que el servidor, si bien tiene la "dificultad" de tener que andar buscando el servicio, sólo tiene que atender a sí mismo. En este caso lo hacemos en C# utilizando la librería para conexión Bluetooth InTheHand.

Descubriendo dispositivos:

Para descubrir los servicios disponibles sólo debemos recorrer los dispositivos y consultar los ID de los servicios disponibles, si lo encontramos, listo. En este caso, supongamos que queremos listar los dispositivos que admiten un determinado tipo de servicio en un ComboBox para que lo seleccione el usuario:

	// Un objeto cliente:
	BluetoothClient cli = new BluetoothClient();

	// Vaciamos la lista de dispositivos que admiten un servicio GUID_SERVICE:
	lista.Items.Clear();

	// Para cada dispositivo descubierto...
	foreach( BluetoothDeviceInfo dev in cli.DiscoverDevices() )
		// ...si está conectado...
		if( dev.Connected ) {
			// ...para cada servicio de este dispositivo de tipo SPP...
			foreach( ServiceRecord sr in dev.GetServiceRecords( BluetoothService.SerialPort ) )
				// ...para cada atributo que lo describe...
				foreach( ServiceAttribute sa in sr )
					// ...si tiene nuestro GUID...
					if( BuscarGUID( sa.Value, GUID_SERVICE ) ) {
						// ...lo añadimos...
						lista.Items.Add( new DeviceItem( dev ) );
						// ...y listo.
						goto Terminado;
					}
// Se que no es estructurado. ¡Pero es la solución correcta!
Terminado:
		}

Bueno, la función BuscarGUID es fácil:

private bool BuscarGUID( ServiceElement se, Guid guid ) {
	switch( se.ElementType ) {
	case ElementType.Uuid128:
	case ElementType.Uuid16:
	case ElementType.Uuid32:
		return guid == se.GetValueAsUuid();
	case ElementType.ElementSequence:
		foreach( ServiceElement sse in se.GetValueAsElementList() )
			if( BuscarGUID( sse, guid ) )
				return true;
		break;
	}
	return false;
}

Consumiendo un servicio:

Si el usuario ya ha seleccionado un elemento de la lista y nos queremos conectar a él, es fácil consumirlo, se parece mucho a conectar por TCP/IP, también es posible si se quiere lanzar el cliente en un Thread separado:

	// Tomamos el dispositivo seleccionado de la lista (debería admitir el servicio):
	DeviceItem dev = (DeviceItem) lista.SelectedItem;

	// Obtenemos el punto de acceso, formado por la dirección y el tipo de servicio:
	BluetoothEndPoint ep = new BluetoothEndPoint( dev.Device.DeviceAddress, GUID_SERVICE );

	// Un cliente Bluetooth:
	BluetoothClient c = new BluetoothClient();

	// Conectamos:
	c.Connect( ep );

	// Obtenemos un canal de red (para leer y escribir):
	NetworkStream s = c.GetStream();

	// Bien, mientras estemos activos y el canal esté conectado:
	while( activo && c.Connected ) {

		// Un buffer para leer datos:
		byte [] buff = new byte [ MAX_BUFF ];

		// Leemos (esta llamada bloqueará el cliente):
		int leído = s.Read( buff, 0, MAX_BUFF );

		// Usamos datos:
		...

	}
	s.Close();
	c.Close();

Sencillo, ¿no?



Opinado el 30/04/10 22:17, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    excelente bastante util.. felicitaciones
Opinado el 18/05/10 21:57, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    Gracias
Opinado el 30/06/10 02:33, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    me gustaria saber cual seria el ejemplo para envio de imagenes de un cliente a un servidor via blutooth.. gracias
Opinado el 31/10/11 00:33, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    muy claro
Opinado el 31/10/11 18:13, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    pjduran@gmail.com ¿Que librerias incluyo?: using
Opinado el 20/05/12 20:30, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    
Opinado el 23/07/12 05:01, valoración ValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoraciónValoración
    Gracias 3..2
¿Te ha gustado? ¡aporta tu opinión!
Valoración:
 0    1    2    3    4    5    6    7    8    9    10

Comentario:
NOTA: si es una petición... ¡pon el e-mail al que responderte o no sabré a dónde escribir!

Código de verificación captcha