UNIVERSIDAD DE EL SALVADOR FACULTAD DE INGENIERIA Y ARQUITECTURA ESCUELA DE INGENIERIA DE SISTEMAS INFORMATICOS PROGRAMACION PARA DISPOSITIVOS MOVILES PDM115 Ciclo I-2014 GUIA DE PRACTICA (EX Aula opcional) LED RGB controlado por Arduino desde un dispositivo movil con SO Android 2.2 o superior. Objetivos General: Implementar la comunicación por medio de bluetooth de un circuito implementado con la placa Arduino y un dispositivo Android 2.2 o mejor. Específicos: Conocer las partes más importantes de un módulo bluetooth compatible con Arduino. Identificar y utilizar los pines de Arduino dedicados a la transición y recepción de datos. Utilizar una aplicativo Android para controlar un led RGB por medio de bluetooth. Tabla de contenido Descripción general del proyecto a implementar: .............................................................................. 1 Precondiciones para la efectiva realización de la siguiente guía: ....................................................... 2 Material necesario para realizar la practica: ....................................................................................... 2 Código fuente para la placa Arduino:.................................................................................................. 2 Solución a nivel de circuitería: ............................................................................................................ 3 Módulo bluetooth HC-07 .................................................................................................................... 4 Diagrama de conexión del led RGB con Arduino y modulo bluetooth HC-07: ................................... 5 Aplicativo bluetooth en Android. ........................................................................................................ 7 Manifest: ......................................................................................................................................... 8 Strings .............................................................................................................................................. 9 Menú ............................................................................................................................................... 9 led_tri_color.xml ......................................................................................................................... 9 desconecta.xml ........................................................................................................................... 9 Layuot .............................................................................................................................................. 9 activity_led_tri_color.xml ........................................................................................................... 9 Clases Principales .......................................................................................................................... 12 ConexionBT.java ........................................................................................................................ 12 LedTriColor.java......................................................................................................................... 20 Detalles importantes del desarrollo de la aplicación. ....................................................................... 27 Como funciona LedTriColor............................................................................................................... 28 Anexos ............................................................................................................................................... 30 Obtener la MAC de un módulo bluetooth. ................................................................................... 31 Descripción general del proyecto a implementar: En la presente guía se muestra las modificaciones que se deben realizar al circuito elaborado en la guía anterior para poder manipular un led RGB por medio de un dispositivo móvil con SO Android 2.2 o mejor. En la guía anterior logramos manipular un led RGB por medio de comandos desde la computadora gracias a la consola de comunicación serial del IDE de Arduino, en esta guía vamos a llevarlo un paso más adelante logrando enviar parámetros por bluetooth desde una aplicación en Android la cual enviara el parámetro que corresponda la presionar el color que deseamos encender. Hablaremos un poco de lo que son los módulos bluetooth y para qué sirve cada uno de los pines que nos interesan conocer y así realizar la práctica de la mejor manera posible, evitando así conectar mal nuestro modulo, asegurándonos así la integridad del mismo. En la parte de circuitería integraremos un módulo bluetooth a nuestra placa Arduino para que este se pueda comunicar con el dispositivo móvil que deseemos, y luego la vincularemos a nuestro dispositivo móvil para que puedan comunicarse entre sí. En la parte programática desarrollaremos la aplicación por la cual nos comunicaremos con la placa Arduino, para lograr esto no necesitaremos modificar nuestro sketch ya que la comunicación entre el modulo bluetooth y la placa Arduino siempre se da por medio del puerto serial de la placa. 1 Precondiciones para la efectiva realización de la siguiente guía: Haber concluido la guía de implementación de un dispositivo para controlar un led RGB desde la computadora por medio de la placa Arduino. Tener el circuito elaborado en la guía anterior. Conocimiento en la creación de aplicativos para Android. Material necesario para realizar la practica: Modulo bluetooth compatible con arduino por ejemplo HC-05, HC-06, HC-07 o RN-42. Dispositivo móvil con bluetooth y SO Android 2.2 o mejor. Batería de 12v y clavija hembra tipo Jack para alimentar la placa y el modulo bluetooth o si se posee una fuente DC a 12 voltios también se puede utilizar. Código fuente para la placa Arduino: Debido a que la comunicación por parte del módulo bluetooth con la placa Arduino igualmente se realiza por medio del puerto serie de la misma, no se hará ningún cambio en el código fuente para que este funcione, por lo que no será necesario modificar el sketch de la guía anterior. 2 Solución a nivel de circuitería: Debido a que el circuito para controlar el led RGB es el mismo lo único que cambia en la manera de comunicarnos con la placa, que en esta ocasión es por medio de un módulo bluetooth. Para poder conectar nuestro modulo bluetooth en los pines correctos es necesario recordar el siguiente diagrama. Existe 2 formas de comunicarnos con esta placa Arduino: 1. Por medio del cable USB. 2. A través de los pines de recepción y transmisión de datos que son el Pin 0 (Rx0) y Pin 1 (Tx0) respectivamente. Cabe aclarar que en otras placas Arduino como por ejemplo los Atmega 2560 se cuenta con 4 pares de pines Tx y Rx con los que se puede tener diversas fuentes de comunicación. Una vez teniendo claro cuáles son los pines de comunicación de la placa Arduino procedemos a explicar algunas generalidades del módulo bluetooth a utilizar y luego procedemos a conectar el modulo a nuestra placa Arduino. 3 Módulo bluetooth HC-07 Este módulo es de los más comunes para trabajar con Arduino ya que tiene un alcance aceptable y su precio es muy accesible. Si usted posee un HC-05 o HC-06, el pinnado es el mismo ya que forman parte de la misma familia, el funcionamiento de cada uno de los pines se detalla a continuación. RXD: Es el pin que se encarga de la recepción de los datos que se desean transmitir por medio de bluetooth. Este pin se conecta directamente al pin TX de la placa Arduino. TXD: Es el pin que se encarga de la transmisión de los datos que se han recibido por medio del bluetooth hacia la placa Arduino. Este pin se conecta al RX del Arduino. GND: Es el pin de Tierra, se conecta a mismo GND del Arduino para cerrar el circuito electrónico. VCC: Es el pin de alimentación y tiene un margen de alimentación funcional de 3.6v a 6v. Se conecta al pin de alimentación de nuestro circuito. Los pines STATE y KEY nos sirven para la respectiva configuración de nuestro modulo, en los casos que se deseen cambiar los parámetros de fábrica. Cabe mencionar que el modulo debe estar previamente configurado; normalmente la configuración de fábrica de estos módulos es suficiente. Aunque hay caso en que se desea cambiar la clave de emparejamiento, el nombre del módulo, o en un caso especial los baudios de transmisión por defecto son 9600, este proceso no se explica en esta guía. 4 Diagrama de conexión del led RGB con Arduino y modulo bluetooth HC-07: 5 Los pines del módulo que utilizaremos son los siguientes: El pin RX (cable amarillo) del módulo HC-07 se conecta al pin TX0 del Arduino. El pin TX (cable café) del módulo HC-07 se conecta al pin RX0 del Arduino. El pin VCC (cable anaranjado) del módulo HC-07 se conecta al pin VCC del Arduino. El pin GND (cable negro) del módulo HC-07 se conecta al GND del Arduino. Como se puede observar, los otros componentes quedan conectados exactamente igual que en la guía anterior. Si hay alguna duda revise la guía anterior. Antes de proceder a alimentar el circuito para hacer una prueba si nuestro modulo bluetooth ha sido bien conectado, tomémonos el tiempo de revisar las conexiones ya que estos dispositivos son delicados y podrían sufrir algún daño por cualquier descuido. Procedemos a alimentar nuestro circuito ya se por medio de una batería de 12v(cuadrada), una fuete de 12 voltios de por lo menos 1A o por medio del cable usb hacia la computadora, en este momento el led(Rojo) indicador de nuestro modulo debe estar parpadeante lo que indica que está listo para aparearse con otro dispositivo bluetooth. Y al momento en que se conecten este led debe de dejar de parpadear y quedar encendido. En este momento ya tenemos nuestro circuito listo para conectarnos a él por medio de un dispositivo con bluetooth, para esta práctica en específico lo haremos desde un dispositivo móvil con SO Android 2.2 o mejor. 6 Aplicativo bluetooth en Android. A continuación se presenta el código fuente para realizar la aplicación con la que controlaremos nuestro led RGB. Este aplicativo es capaz de funcionar desde dispositivos con Android 2.2 en adelante, aunque cabe aclarar que en versiones más recientes de Android se pueden utilizar funciones que facilitan el manejo del bluetooth, pero como el objetivo de esta práctica es abarcar la mayoría de dispositivos Android no se ha hecho uso de estas funciones. Android 4.2.2 Android 2.2 7 Manifest: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="ues.fia.eisi.ledtricolor" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17" /> <!-- Permisos para utilizar el Bluetooth --> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="ues.fia.eisi.ledtricolor.LedTriColor" android:label="@string/app_name" android:screenOrientation="portrait"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 8 Strings <?xml version="1.0" encoding="UTF-8" standalone="no"?> <resources> <string name="app_name">LedTriColor</string> <string name="hello_world">Controlador Led RGB</string> <string name="bluetooth">Conectar</string> <string name="Off">Apagar</string> <string name="Rojo">Rojo</string> <string name="Verde">Verde</string> <string name="Azul">Azul</string> <string name="Desconexion">Desconectar</string> <string name="mac">00:12:07:13:12:91</string><!--HINT FORMATO DE MAC --> </resources> Menú led_tri_color.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/Conexion" android:title="@string/bluetooth" android:orderInCategory="100" android:showAsAction="never"> </item> </menu> desconecta.xml <?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@+id/desconexion" android:title="@string/Desconexion" android:orderInCategory="100"> </item> </menu> Layuot activity_led_tri_color.xml <?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="wrap_content" > <RelativeLayout android:layout_width="wrap_content" 9 android:layout_height="wrap_content" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context=".LedTriColor" > <TextView android:id="@+id/textView1" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/hello_world" android:textSize="25sp" /> <EditText android:id="@+id/mac" android:layout_width="fill_parent" android:layout_height="70dp" android:layout_below="@id/textView1" android:ems="10" android:hint="@string/mac" android:inputType="text|textCapCharacters" android:maxLength="17" android:textSize="25sp" > <requestFocus /> </EditText> <LinearLayout android:id="@+id/btnConexion" android:layout_width="fill_parent" android:layout_height="80dp" android:layout_below="@id/mac" > <Button android:id="@+id/conectar" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:text="@string/bluetooth" android:textSize="20sp" /> <Button android:id="@+id/desconectar" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:text="@string/Desconexion" android:textSize="20sp" /> </LinearLayout> <LinearLayout android:id="@+id/botones" android:layout_width="fill_parent" 10 android:layout_height="100dp" android:layout_below="@id/btnConexion" android:layout_marginBottom="20dp" android:layout_marginTop="20dp" android:orientation="horizontal" > <Button android:id="@+id/Rojo" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:text="@string/Rojo" android:textSize="30sp" /> <Button android:id="@+id/Verde" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:text="@string/Verde" android:textSize="30sp" /> <Button android:id="@+id/Azul" android:layout_width="wrap_content" android:layout_height="fill_parent" android:layout_weight="1" android:text="@string/Azul" android:textSize="30sp" /> </LinearLayout> <Button android:id="@+id/Off" android:layout_width="fill_parent" android:layout_height="60dp" android:layout_below="@id/botones" android:text="@string/Off" android:textSize="30sp" /> </RelativeLayout> </ScrollView> 11 Clases Principales Esta clase es la encargada de efectuar todo lo concerniente a la conexión y a la comunicación. ConexionBT.java package ues.fia.eisi.ledtricolor; // Debug Para monitorizar los eventos private static final String TAG = "Servicio_Bluetooth"; private static final boolean D = true; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.UUID; import android.bluetooth.BluetoothAdapte r; import android.bluetooth.BluetoothDevice ; import android.bluetooth.BluetoothServer Socket; import android.bluetooth.BluetoothSocket ; import android.content.Context; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; // Nombre para el registro SDP cuando el socket sea creado private static final String NAME = "BluetoothDEB"; // UUID Identificador unico de URI para esta aplicacion private static final UUID MY_UUID = UUID.fromString("00001101-00001000-8000-00805F9B34FB"); // UUID para chat con otro Android ("fa87c0d0-afac11de-8a39-0800200c9a66"); // UUID para modulos BT RN42 ("00001101-0000-1000-800000805F9B34FB"); /** * Esta clase realiza todo el trabajo para configurar y administrar la conexion Bluetooth con otro dispositivo. * Hay un hilo que esta a la escucha de conexiones entrantes, un hilo para conexiones con un dispositivo y * un hilo para realizar las transmisiones una vez que se este conectado. */ public class ConexionBT { // Campos de coexion private final BluetoothAdapter AdaptadorBT; private final Handler mHandler; private AcceptThread HebraDeAceptacion; private ConnectThread HiloDeConexion; private ConnectedThread HiloConetado; private int EstadoActual; //<<<<<<<<<<<<<<<<<<<<<<<<< <<<< Definiciones >>>>>>>>>>>>>>>>>>>>>>>>>>> // Constantes que indican el estado de conexion 12 public static final int STATE_NONE = 0; // No se esta haciendo nada public static final int STATE_LISTEN = 1; // Escuchando por conexiones entrantes public static final int STATE_CONNECTING = 2; // Iniciando conexion saliente public static final int STATE_CONNECTED = 3; // Conectado con un dispositivo EstadoActual = estado; // Le enviamos al Handler el nuevo estado actual para que se actualize en la Actividad mHandler.obtainMessage(LedTriColo r.Mensaje_Estado_Cambiado, estado, -1).sendToTarget(); } /** * Regresa el estado de la conexion */ public synchronized int getState() { return EstadoActual; } //<<<<<<<<<<<<<<<<<<<<<<<<< <<<< METODOS >>>>>>>>>>>>>>>>>>>>>>>>>>> //----<<<<---->>>>----METODOS NO ALTERADOS----<<<<---->>>>---/** * Constructor. Prepara una nueva sesion para la conexion Bluetooth Smartphone-Dispositivo * @param context El identificador UI de la actividad de context * @param handler Un Handler para enviar mensajes de regreso a la actividad marcada por el UI * * */ public ConexionBT(Context context, Handler handler) { AdaptadorBT = BluetoothAdapter.getDefaultAdapte r(); EstadoActual = STATE_NONE; mHandler = handler; } /** * Inicia el servicio bluetooth. Especificamente inicia la HebradeAceptacion para iniciar el * modo de "listening". LLamado por la Actividad onResume() */ public synchronized void start() { if (D) Log.e(TAG, "start"); //Cancela cualquier hilo que quiera hacer una conexion if (HiloDeConexion != null) {HiloDeConexion.cancel(); HiloDeConexion = null;} //Cancela cualquier hebra que este corriendo una conexion if (HiloConetado != null) {HiloConetado.cancel(); HiloConetado = null;} /** * Actualizamos estado de la conexion BT a la actividad * @param estado Un entero definido para cada estado */ private synchronized void setState(int estado) { // Inicia la hebra que escuchara listen en el BluetoothServerSocket if (HebraDeAceptacion == null) { 13 HebraDeAceptacion = new AcceptThread(); * @param socket El socket Bt donde se realizara la conexion * @param device El dispositivo BT con que se conectara */ public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) { if (D) Log.e(TAG, "connected"); HebraDeAceptacion.start(); } setState(STATE_LISTEN); } /** * Inicia el HiloConectado para iniciar la conexion con un dispositivo remoto * @param device -->El dispositivo BT a conectar */ public synchronized void connect(BluetoothDevice device) { if (D) Log.e(TAG, "Conectado con: " + device); // Cancela el hilo que completo la conexion if (HiloDeConexion != null) {HiloDeConexion.cancel(); HiloDeConexion = null;} //Cancela el hilo que actualmente esta corriendo la conexion if (HiloConetado != null) {HiloConetado.cancel(); HiloConetado = null;} //Cancela cualquier hilo que intente realizar una conexion if (EstadoActual == STATE_CONNECTING) { if (HiloDeConexion != null) {HiloDeConexion.cancel(); HiloDeConexion = null;} } // Cancela la Hebradeaceptacion debido a que solo queremos conectar con un dispositivo********** if (HebraDeAceptacion != null) {HebraDeAceptacion.cancel(); HebraDeAceptacion = null;} //Cancela cualquier hilo que se encuentre corriendo una conexion if (HiloConetado != null) {HiloConetado.cancel(); HiloConetado = null;} //Inicia el hilo para administrar la conexion y realizar transmisiones HiloConetado = new ConnectedThread(socket); HiloConetado.start(); //Inicia el hilo para conectar con un dispositivo HiloDeConexion = new ConnectThread(device); HiloDeConexion.start(); //Envia el nombre del dispositivo conectado de vuelta Message msg = mHandler.obtainMessage(LedTriColo r.Mensaje_Nombre_Dispositivo); Bundle bundle = new Bundle(); setState(STATE_CONNECTING); } /** * Inicia la hebra conectada para iniciar la administracion de la conexión BT 14 if (EstadoActual != STATE_CONNECTED) return; r = HiloConetado; } // Realizar la escritura Asincrona r.write(out); } bundle.putString(LedTriColor.DEVI CE_NAME, device.getName()); msg.setData(bundle); mHandler.sendMessage(msg); setState(STATE_CONNECTED); } /** * Indica que el intento de conexion fallo y notifica a la actividad WidgetProvider/UpdateService */ private void connectionFailed() { setState(STATE_LISTEN); //Envia un mensaje de falla de vuelta a la actividad Message msg = mHandler.obtainMessage(LedTriColo r.Mensaje_TOAST); Bundle bundle = new Bundle(); /** * Para todos los hilos y pone el estado de STATE_NONE donde no esta haciendo nada */ public synchronized void stop() { if (D) Log.e(TAG, "stop"); if (HiloDeConexion != null) {HiloDeConexion.cancel(); HiloDeConexion = null;} if (HiloConetado != null) {HiloConetado.cancel(); HiloConetado = null;} if (HebraDeAceptacion != null) {HebraDeAceptacion.cancel(); HebraDeAceptacion = null;} setState(STATE_NONE); } bundle.putString(LedTriColor.TOAS T, "Error de conexión"); msg.setData(bundle); mHandler.sendMessage(msg); } /** * Indica que la conexion se perdio y notifica a la UI activity(WidgetProvider/UpdateSEr vice) */ private void connectionLost() { setState(STATE_LISTEN); //Envia un mensaje de falla de vuelta a la actividad Message msg = mHandler.obtainMessage(LedTriColo r.Mensaje_TOAST); Bundle bundle = new Bundle(); /** * Escribe en el HiloConectado de manera Asincrona * @param out Los bytes a escribir * @see ConnectedThread#write(byte[]) */ public void write(byte[] out) { ConnectedThread r; //Creacion de objeto temporal // Syncronizar la copia del HiloConectado synchronized (this) { 15 } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> public void run() { if (D) Log.e(TAG, "Comenzar HiloDeAceptacion " + this); bundle.putString(LedTriColor.TOAS T, "Se perdio conexion"); msg.setData(bundle); mHandler.sendMessage(msg); msg = mHandler.obtainMessage(LedTriColo r.MESSAGE_Desconectado); setName("HiloAceptado"); BluetoothSocket socket = null; //Escucha al server socket si no estamos conectados while (EstadoActual != STATE_CONNECTED) { try { //Esto es un bloque donde solo obtendremos una conexion o una excepcion socket = mmServerSocket.accept(); } catch (IOException e) { Log.e(TAG, "accept() failed", e); break; } //Si la conexion fue aceptada... if (socket != null) { synchronized (ConexionBT.this) { switch (EstadoActual) { case STATE_LISTEN: case STATE_CONNECTING: // Situation normal. Iniciamos HebraConectada mHandler.sendMessage(msg); } /** * Este hilo corre mientras se este ESCUCHANDO por conexiones entrantes. Este se * comporta como el ladoServidor cliente. Corre mientras la conexion es aceptada(o cancelada) */ private class AcceptThread extends Thread { // El soket de servidor Local private final BluetoothServerSocket mmServerSocket; //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> public AcceptThread() { BluetoothServerSocket tmp = null; //Creamos un nuevo listening server socket try { tmp = AdaptadorBT.listenUsingRfcommWith ServiceRecord(NAME, MY_UUID); } catch (IOException e) { Log.e(TAG, "listen() fallo", e); } mmServerSocket = tmp; connected(socket, socket.getRemoteDevice()); break; case STATE_NONE: 16 case conexion de salida con un dispositivo. * Este correra a través de la conexion ya sea establecida o fallada */ private class ConnectThread extends Thread { private final BluetoothSocket mmSocket; private final BluetoothDevice mmDevice; STATE_CONNECTED: // O no esta lista o ya esta conectado. Termina el nuevo socket try { socket.close(); } catch (IOException e) { Log.e(TAG, "No se pudo cerrar el socket no deseado", e); } public ConnectThread(BluetoothDevice device) { mmDevice = device; BluetoothSocket tmp = null; // Obtiene un BluetoothSocket para la conexion con el Dispositivo obtenido try { tmp = device.createRfcommSocketToServic eRecord(MY_UUID); } catch (IOException e) { Log.e(TAG, "create() Fallo", e); } mmSocket = tmp; } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> public void run() { Log.e(TAG, "Comenzando HebraConectada"); break; } } } } if (D) Log.e(TAG, "Fin de HIlodeAceptacion"); } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> public void cancel() { if (D) Log.e(TAG, "Cancela " + this); try { mmServerSocket.close(); } catch (IOException e) { Log.e(TAG, "close() del servidor FAllo", e); } } setName("HiloConectado"); //Siempre cancela la busqueda debido a que esta hara lenta la conexion //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> } AdaptadorBT.cancelDiscovery(); // Realiza la conexion con el socketBluetooth try { /** * Esta Hebra correra mientras se intente realizar una 17 // Aqui solo recibiremos o una conexion establecida o una excepcion Log.e(TAG, "close() of connect socket failed", e); } } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> }//fin de conectThread mmSocket.connect(); } catch (IOException e) { connectionFailed(); // Cierra el socket try { /** * Este hilo corre durante la conexion con un dispositivo remoto. * Este maneja todas las transmisiones de entrada y salida. */ private class ConnectedThread extends Thread { private final BluetoothSocket BTSocket; private final InputStream INPUT_Stream; private final OutputStream OUTPUT_Stream; mmSocket.close(); } catch (IOException e2) { Log.e(TAG, "Imposible cerrar el socket durante la falla de conexion", e2); } // Inicia el servicio a traves de reiniciar el modo de listening ConexionBT.this.start(); return; } // Resetea el HiloConectado pues ya lo hemos usado synchronized (ConexionBT.this) { HiloDeConexion = null; } // Inicia el hiloconectado connected(mmSocket, mmDevice); } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> public void cancel() { try { mmSocket.close(); } catch (IOException e) { public ConnectedThread(BluetoothSocket socket) { Log.d(TAG, "Creacion de HiloConectado"); BTSocket = socket; InputStream tmpIn = null; OutputStream tmpOut = null; // Obtencion del BluetoothSocket de entrada y saldida try { tmpIn = socket.getInputStream(); tmpOut = socket.getOutputStream(); } catch (IOException e) { 18 Log.e(TAG, "Sockets temporales No creados", e); } INPUT_Stream = tmpIn; OUTPUT_Stream = tmpOut; } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> /** * Escribe al Stream de salida conectado * @param buffer Los bytes a escribir */ public void write(byte[] buffer) { try { public void run() { Log.e(TAG, "Comenzar Hebraconectada"); byte[] buffer = new byte[1024]; int bytes; while (true) { //Mantiene escuchando el InputStream mientras este conectado try { //Lee desde el InputStream bytes = INPUT_Stream.read(buffer); // byte[] readBufX = (byte[]) buffer; //Construye un String desde los bytes validos en el buffer // String readMessageX = new String(readBufX, 0, bytes);//Se envia el readNessagexxx en lugar del buffer pues ya se PARSEO OUTPUT_Stream.write(buffer) ; //Compartir el mensaje enviado con la UI activity mHandler.obtainMessage(LedTriColo r.Mensaje_Escrito, -1, -1, buffer).sendToTarget(); } catch (IOException e) {Log.e(TAG, "Exception during write", e);} }//FIN DE WRITE //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> public void cancel() { try { mHandler.obtainMessage(LedTriColo r.Mensaje_Leido, bytes, -1, buffer).sendToTarget(); //readMessageX por buffer } catch (IOException e) {Log.e(TAG, "disconnected", e);connectionLost();break; } }//_____________----FIN DE WHILE (TRUE)----_________________ BTSocket.close(); } catch (IOException }//**************_________FIN DE PUBLIC VOID RUN__________************** //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> e) { Log.e(TAG, "close() del socket conectado Fallo", e); } } //<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< <<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>> }//-------------------*****FIN de la clase ConnectedThread*****------------------ 19 >>>_____FIN DE LA CLASE CONEXIONBT_____<<<<<_____>>>>>___ _<<<<<_____>>>>> } //<<<<<____>>>>>_____<<<<<_____>> LedTriColor.java Esta es nuestra clase principal y desde donde utilizaremos la clase ConexionBT. package ues.fia.eisi.ledtricolor; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.annotation.SuppressLint; import android.app.Activity; import android.bluetooth.BluetoothAdapte r; import android.bluetooth.BluetoothDevice ; import android.content.Intent; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public static final int Mensaje_Leido = 2; public static final int Mensaje_Escrito = 3; public static final int Mensaje_Nombre_Dispositivo = 4; public static final int Mensaje_TOAST = 5; public static final int MESSAGE_Desconectado = 6; public static final int REQUEST_ENABLE_BT = 7; public static final String DEVICE_NAME = "device_name"; public static final String TOAST = "toast"; //Nombre del dispositivo conectado private String mConnectedDeviceName = null; // Adaptador local Bluetooth private BluetoothAdapter AdaptadorBT = null; //Objeto miembro para el servicio de ConexionBT private ConexionBT Servicio_BT = null; //variables para el Menu de conexión private boolean seleccionador=false; public int Opcion=R.menu.led_tri_color; private EditText dirMac; /*-----------------------------------------------------------------------------------------------*/ @Override public void onCreate(Bundle savedInstanceState){ @SuppressLint("HandlerLeak" ) public class LedTriColor extends Activity { /*---------------------------------------------------------------------------------------------*/ // Debugging public static final String TAG = "LedTriColor"; public static final boolean D = true; // Tipos de mensaje enviados y recibidos desde el Handler de ConexionBT public static final int Mensaje_Estado_Cambiado = 1; 20 super.onCreate(savedInstanceState ); Desconectar.setOnClickListe ner(onclick); setContentView(R.layout.activity_ led_tri_color); Button Azul,Verde,Rojo,oFF,Conectar,Desc onectar; dirMac=(EditText)findViewBy Id(R.id.mac); } Azul=(Button)findViewById(R.id.Az ul); View.OnClickListener onclick= new View.OnClickListener() { Azul.setOnClickListener(onc lick); @Override public Verde=(Button)findViewById( R.id.Verde); void onClick(View v) { // TODO Apéndice de método generado automáticamente Verde.setOnClickListener(on click); switch(v.getId()){ case Rojo=(Button)findViewById(R .id.Rojo); R.id.Azul: if(D) Log.e("BotonLed", "Encendiendo.."); Rojo.setOnClickListener(onc lick); sendMessage("A"); oFF=(Button)findViewById(R. id.Off); break; oFF.setOnClickListener(oncl case ick); R.id.Verde: if(D) Log.e("BotonLed", "Encendiendo.."); Conectar=(Button)findViewBy Id(R.id.conectar); sendMessage("V"); Conectar.setOnClickListener (onclick); break; Desconectar=(Button)findVie wById(R.id.desconectar); case R.id.Rojo: 21 if(D) Log.e("BotonLed", "Encendiendo.."); if(seleccionador)// Esta conectado? sendMessage("R"); { sendMessage("x"); break; case desconectar(); R.id.Off: } if(D) Log.e("BotonLed", "Apagando.."); else { sendMessage("x"); Toast.makeText(LedTriColor. this,"NO ESTA CONECTADO",Toast.LENGTH_LONG).sho w(); break; case R.id.conectar: } if(D) Log.e("BotonLed", "Conectado!!!.....!!!"); break; } if(!seleccionador) //Esta desconectado? } }; public iniciarConexion(); void onStart() { super.onStart(); ConfigBT(); else { } Toast.makeText(LedTriColor. this,"ESTA CONECTADO!!",Toast.LENGTH_LONG).s how(); @Override public void onDestroy(){ super.onDestroy(); if (Servicio_BT != null) Servicio_BT.stop();//Detenemos servicio } } break; case R.id.desconectar: public void ConfigBT(){ // Obtenemos el adaptador de bluetooth if(D) Log.e("BotonLed", "Conectado!!!.....!!!"); 22 AdaptadorBT = BluetoothAdapter.getDefaultAdapte r(); if (AdaptadorBT.isEnabled()) //Si el BT esta encendido { if (Servicio_BT == null) //y el Servicio_BT es nulo, invocamos el Servicio_BT { Activity.RESULT_OK) {//BT esta activado,iniciamos servicio ConfigBT(); } else {//No se activo BT, salimos de la app Toast.makeText(this,"ENCIEN DA EL BT!!! ",Toast.LENGTH_LONG).show(); finish(); //Fin de la APP Servicio_BT = new ConexionBT(this, mHandler); } } } else{ }//fin de switch case if(D) Log.e("Setup", "Bluetooth apagado..."); //Mensaje para el log }//fin de onActivityResult Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_RE QUEST_ENABLE); @Override public boolean onPrepareOptionsMenu(Menu menux){ startActivityForResult(enab leBluetooth, REQUEST_ENABLE_BT); } } menux.clear();//limpiamos menu actual if (seleccionador==false) public void onActivityResult(int requestCode, int resultCode, Intent data){ //Una vez que se ha realizado una actividad regresa un "resultado"... switch (requestCode) { Opcion=R.menu.led_tri_color ;//dependiendo las necesidades if (seleccionador==true) Opcion=R.menu.desconecta; // crearemos un menu diferente case REQUEST_ENABLE_BT://Respuesta al intento de encendido de BT if (resultCode == getMenuInflater().inflate(O pcion, menux); return super.onPrepareOptionsMenu(menux) ; } 23 @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.Conexion: if(D) Log.e("conexion", "conectandonos"); if(!dirMac.getText().toStri ng().equals("")) Toast.makeText(this,"MAC ERRONEA", Toast.LENGTH_LONG).show(); direccion="00:12:07:1 3:12:91"; //Direccion MAC default. } iniciarConexion(); return direccion; } public void iniciarConexion(){ return true; String direccionMac=obtenerMac();//Extra emos la direccion try { case R.id.desconexion: sendMessage("x"); BluetoothDevice device = AdaptadorBT.getRemoteDevice(direc cionMac); desconectar(); return true; }//fin de swtich de opciones return false; }//fin de metodo onOptionsItemSelected Servicio_BT.connect(device); } catch (Exception e) { // TODO: handle exception } public String obtenerMac(){ String direccion=""; } public void desconectar(){ if(dirMac.getText().toStrin g().length()==17){ if (Servicio_BT != null) direccion=dirMac.getText(). toString(); } else { Servicio_BT.stop();//Detene mos la comunicacion BT. } 24 public void sendMessage(String message) { if (Servicio_BT.getState() == ConexionBT.STATE_CONNECTED) {//checa si estamos conectados a BT if (message.length() > 0) { // checa si hay algo que enviar byte[] send = message.getBytes();//Obtenemos bytes del mensaje if(D) Log.e(TAG, "Mensaje enviado:"+ message); if(D) Log.e(TAG, "Message_write =w= "+ writeMessage); break; //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>> case Mensaje_Leido: byte[] readBuf = (byte[]) msg.obj;//buffer de lectura... //Construye un String de los bytes validos en el buffer Servicio_BT.write(send); //Mandamos a escribir el mensaje } } else Toast.makeText(this, "No conectado", Toast.LENGTH_SHORT).show(); }//fin de sendMessage String readMessage = new String(readBuf, 0, msg.arg1); if(D) Log.e(TAG, "Message_read =w= "+ readMessage); break; final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>> case Mensaje_Nombre_Dispositivo: switch (msg.what) { mConnectedDeviceName = msg.getData().getString(DEVICE_NA ME); //Guardamos nombre del dispositivo //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>> case Mensaje_Escrito: Toast.makeText(getApplicationCont ext(), "Conectado con "+ mConnectedDeviceName, Toast.LENGTH_SHORT).show(); byte[] writeBuf = (byte[]) msg.obj;//buffer de escritura... seleccionador=true; // Construye un String del Buffer break; String writeMessage = new String(writeBuf); //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 25 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>> case Mensaje_TOAST: Log.e("Conexion","DESConectados") ; seleccionador=false; break; Toast.makeText(getApplicationCont ext(), msg.getData().getString(TOAST), //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>> Toast.LENGTH_SHORT).show(); break; }//FIN DE SWITCH CASE PRIMARIO DEL HANDLER }//FIN DE METODO INTERNO handleMessage };//Fin de Handler //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> >>>> case MESSAGE_Desconectado: }//Fin LedTriColor if(D) 26 Detalles importantes del desarrollo de la aplicación. Para que código anterior no se necesita ningún otro tipo de extensión, jar o cualquier otra configuración especial, basta con el código presentado. El código de la aplicación está documentado por si tiene alguna duda, se le invita a seguir la lógica del mismo y si fuese necesario se puede apoyar del ciclo de vida de una aplicación Android. La dirección MAC (siglas en inglés de media access control; en español "control de acceso al medio") es un identificador de 48 bits (6 bloques hexadecimales) que corresponde de forma única a una tarjeta o dispositivo de red. Se conoce también como dirección física, y es única para cada dispositivo. Por medio de esta dirección MAC nos conectamos a nuestro modulo bluetooth, si dentro de LedTricolor.java buscamos direccion="00:12:07:13:12:91", ahí se encuentra la dirección por default a la cual la aplicación intentara conectarse, si no encontrará ninguna dirección ingresada en el Editext o si la dirección ingresada es errónea. Motivo por el cual se le invita a cambiarla por la dirección de su módulo bluetooth y por cuestiones estéticas a cambiar el hint del Editext. Si no sabe cómo obtener la dirección MAC de su módulo bluetooth se le recomienda ver los anexos. 27 Como funciona LedTriColor Al correr la aplicación, si no tenemos encendido el servicio de bluetooth esta automáticamente nos pedirá permiso para encenderlo, si aceptamos nos activara el servicio, pero no lo activamos cierra la aplicación. Luego si corregimos la dirección MAC en el código anterior para que por defecto funcionase la de nuestra preferencia directamente podemos intentar conectarnos, o si intenta conectarse a otro modulo que no sea el suyo debe de ingresar la dirección en el Editext principal y luego en conectar. 28 En este momento procedemos a alimentar nuestro circuito, para que al momento de intentar conectar con nuestro modulo este sea encontrado. Recuerde que el led del módulo bluetooth debe estar parpadeado (color rojo) y al momento en que nuestros dispositivos se conecten este indicador quedara directo. Puede conectarse de 2 formas diferentes, por medio del botón conectar o abriendo el menú y seleccionando conectar y de las misma manera para desconectarse. En este momento al presionar conectar, nos enviará una notificación de vinculación de dispositivos en la cual debemos ingresar la clave de vinculación del módulo bluetooth, si esta no ha sido cambiada normalmente es 1234 o 0000 ya que son las claves que traen de fábrica. Si ingresamos la clave correcta procederá a intentar la conexión, con lo cual podemos estar seguro que los dispositivos están vinculados y si no vuelva a intentar de nuevo con otra clave. La vinculación solo se da la primera vez que se intentan conectar dos dispositivos bluetooth. Si la conexión fue exitosa nos informara junto con el nombre del módulo bluetooth al que nos hemos conectado, en nuestro caso el modulo se ha nombrado “linvor”. Los mismos comandos que enviamos en la guía anterior son enviados por esta aplicación al momento de presionar cualquiera de los botones. Ya sea Rojo envía “r”, o Azul envía “a” y estos datos son recibidos por la placa Arduino y esta se encarga de encender el led correspondiente. 29 Anexos 30 Obtener la MAC de un módulo bluetooth. Se puede obtener con los métodos siguientes, siempre y cuando nuestro modulo bluetooth este encendido. Por medio de un dispositivo móvil BlackBerry: o Primero debemos vincular los dispositivos. o Una vez estén vinculados, nos dirigimos al panel de configuración del bluetooth. o Luego buscamos los dispositivos bluetooth activos. o Y ubicamos nuestro modulo y ahí aparece el nombre, lo seleccionamos y entramos a las propiedades ahí encontraremos la dirección MAC con el siguiente formato: ##:##:##:##:##:##. Instalando una aplicación de consola bluetooth para nuestro dispositivo Android: o En este caso instalaremos BlueTerm (buscar en la playstore). o Una vez instalada la abrimos y luego desde el menú de opciones. o Seleccionamos “Conectarse a un dispositivo” y ahí nos aparecerá la lista de dispositivos bluetooth cercanos con su respectivo nombre y dirección MAC. Si disponemos con una maquina con dispositivo bluetooth: o Vinculamos el modulo. o Una vez vinculado, localizamos el dispositivo bluetooth de nuestro interés. o Abrimos las propiedades del dispositivo vinculado y ahí encontraremos la dirección MAC. 31