Está en la página 1de 24

 

 
 
Comunicación mediante puerto serie 
virtual (SPP) utilizando Bluetooth, entre 
Android y Arduino 
 
 
 
 
Programació De Dispositius Mòbils 
PRDM 
 
 
 
 
Cristobal Raya Giner 2015 
   
En este ejemplo, se va a controlar el estado del led de pruebas conectado al pin 13, en una placa 
Arduino mediante una aplicación Android utilizando el puerto serie a través de bluetooth con el 
protocolo RFCOMM que emula un puerto serie (SPP). 

 
 

El programa en Arduino, lee el puerto serie a la espera de recibir un ‘0’ o un ‘1’ para cambiar el 
estado del led, y cada 500ms aprox. Envía el valor en milisegundos del timer interno y el estado 
del led, en una trama con el formato *tiempo+estadoled+@, en que se indica el inicio de trama 
con un ‘*’, el final de trama con ‘@’ y los datos se separan mediante ‘+’. 

Programa Arduino 
int led = 13; //led Rojo de prueba de conexión conectado al pin 13

float estado[2] = {0,0};


char inbyte = 0; //Char para leer el led

void setup() {
Serial.begin(9600);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}

void loop() {
estado[0]=millis();

if (Serial.available() > 0)
{
inbyte = Serial.read();
//Serial.println(inbyte);
if (inbyte == '0')
{
digitalWrite(led, LOW); //LED OFF
estado[1] = 0;
}
if (inbyte == '1')
{
digitalWrite(led, HIGH); //LED ON
estado[1] = 1;
}
}
envia_serie();
delay(490); //Se envían los datos cada 490+10=500ms
}

//enviar los valores por el puerto serie o bluetooth


void envia_serie() //Enviará *tiempo+estado+@
{
Serial.print('*'); //con ‘*’ comienzan de los datos
for(int k=0; k<2; k++)
{
Serial.print(estado[k]);
Serial.print('+'); //separamos los datos con +
}
Serial.print('@'); //con '@' finalizan los datos
Serial.println();
delay(10); //Esperamos que finalice la transmisión
}

Programa Android 
El programa en Android está formado por dos actividades. La primera para activar Bluetooth en 
Android,  listar  los  dispositivos  Bluetooth  emparejados,  y  seleccionar  la  dirección.  Una  vez 
seleccionada la dirección, se ejecuta la actividad de control, donde tras conectarse al dispositivo 
Bluetooth con la dirección seleccionada, recibe los datos de Bluetooth y transmite las órdenes al 
pulsar los botones. 

Actividad de selección de la dirección del dispositivo Bluetooth  
El fichero activity_conectabt.xml, corresponde al layout de la actividad de selección de dirección 
Bluetooth. Como objetos más importantes incorpora el botón de iniciar la conexión y una lista 
que mostrará los dispositivos Bluetooth emparejados, y en que realizaremos la  selección.  

 
   
El  fichero  conectabt.java  corresponde  al  código  de  que  permitirá  seleccionar  la  dirección  del 
dispositivo Bluetooth. 

Tras los imports necesarios, 
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.Set;
 

Definimos los objetos de la actividad. Se crean el botón y la lista que se enlazarán con los objetos 
gráficos del layout, un adaptador Bluetooth (BluetoothAdapter), y una estructura de dispositivos 
Bluetooth  (BluetoothDevice)  que  mediante  una  interficie  Set<e>  no  permitirá  dispositivos 
duplicados. Finalmente unos String que servirán para pasar la dirección seleccionada a la siguiente 
actividad: 
public class conectabt extends AppCompatActivity {

// Crea los objetos para enlazar con los objetos gráficos


Button btnconectar;
ListView listadispositivosBT;

//Crea objeto bluetooth


private BluetoothAdapter miBluetooth=null;
//Crea un objeto BluetoothDevice, pero sin elementos duplicados
(java.util.Set <E>)
private Set <BluetoothDevice> disposivosEmparejados;
//Crea un String "direccionBT" que se enviara como identificador de
la dirección a la aplicación
public static String DIRECCION_EXTRA = "direccion BT";
public static String NOMBREBT_EXTRA = "nombre BT";
 

Al  iniciar  la  actividad,  en  el  método  onCreate(),  asignamos  los  objetos  gráficos  y  el  adaptador 
Bluetooth del dispositivo Android al objeto creado: 

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_conectabt);

//Crea los enlaces a los objectos gráficos


btnconectar=(Button) findViewById(R.id.button);
listadispositivosBT=(ListView) findViewById(R.id.listView);

//Asigna el adaptador bluetooth por defecto del propio dispositivo


al objeto miBluetooth
miBluetooth = BluetoothAdapter.getDefaultAdapter();
 

Si no existiera ningún adaptador Bluetooth, indicaría un mensaje de error: 
if (miBluetooth==null) //Si el dispositivo propio no tiene bluetooth
indica el error
{
Toast.makeText(getApplicationContext(),"Bluetooth no
existe",Toast.LENGTH_LONG).show();
}
 

Si  existe  un  dispositivo  comprueba  si  está  habilitado.  En  caso  de  no  estar  habilitado,  pide 
habilitarlo: 
else
{
if (miBluetooth.isEnabled()) //Si esta activado no hace nada
// Recordar añadir al fichero AndroidManifest.xml la linea: <uses-
permission android:name="android.permission.BLUETOOTH" />
{}
else //Si no esta activado llama a la actividad de activar bluetooth
del Adaptador del dispositivo android
{
Intent activaBT=new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(activaBT,1);
}
}
 

Finalmente configura el Listener del botón, para que al pulsar busque los dispositivos Bluetooth 
emparejados y los muestre en la lista: 
btnconectar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buscarDispositivo(); //Busca los dispositivo bluetooth
}
});
}
 

El  la  función  buscarDispositivo()  primero  asigna  lee  todos  los  dispositivos  emparejados  del 
dispositivo Android y los guarda en el objeto de dispositivosEmparejados. Despues extrae uno a 
uno el nombre y la dirección de cada uno de los dispositivos Bluetooth y los añade a una lista. En 
caso de no encontrar ninguno, indica el error. 

Tras  extraer  la  lista  asigna  los  valores  al  ListView  y  finalmente  crea  un  Listener  de  la  lista  que 
permitirá seleccionar el  dispositivo al clickar sobre la lista y ejecutará la siguiente actividad de 
control del led con los datos del dispositivo Bluetooth seleccionado. 
private void buscarDispositivo()
{
//Toast.makeText(getApplicationContext(),"Buscando
dispositivos",Toast.LENGTH_SHORT).show();
disposivosEmparejados=miBluetooth.getBondedDevices(); //Mira los
dispositivos BT emparejados
ArrayList lista=new ArrayList(); //Crea un objeto lista
if (disposivosEmparejados.size()>0) //Si hay algún dispositivo BT
emparejado, los añade a la lista
{
for (BluetoothDevice bt:disposivosEmparejados)
{
lista.add(bt.getName()+"\n"+bt.getAddress());
}
}
else //Si no hay dispositivo BT emparejados, avisa
{
Toast.makeText(getApplicationContext(),"No hay dispositivos
Bluetooth emparejados",Toast.LENGTH_LONG).show();
}

//Crea un ArrayAdapter para configurar la lista de dispositivos y le


asigna los encontrados
final ArrayAdapter adaptador=new
ArrayAdapter(this,android.R.layout.simple_list_item_1,lista);
listadispositivosBT.setAdapter(adaptador); //Asigna el adaptador a
la lista
//Asigna al clicklistener de dispositivo seleccionado de la lista
listadispositivosBT.setOnItemClickListener(miListenerdeLista);
}
 

Cuando se pulse sobre el dispositivo de la lista para seleccionarlo, el Listener del ListView va a 
convertir  a  String  los  datos  del  dispositivo  seleccionado  (realizando  primero  la  conversión  a 
TextView  del  parámetro  view  del  ítem  seleccionado),  extrae  los  17  últimos  caracteres  que 
corresponden a la MAC del dispositivo bluetooth seleccionado, y el nombre del dispositivo (resto 
de caracteres iniciales), y crea un Intent para iniciar la siguiente actividad del programa de control 
del led, pero pasando los datos de la dirección MAC y el nombre. 

//Crea el clickListener que vigile el dispositivo seleccionado de la


lista
private AdapterView.OnItemClickListener miListenerdeLista=new
AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
//Convierte de tipo view a textview y extrae el texto del
dispositivo BT seleccionado
String infoBT=((TextView)view).getText().toString();
//Extrae los últimos 17 carácteres que corresponden a la MAC
del dispositivo BT seleccionado
String direccionMACBT=infoBT.substring(infoBT.length()-17);
String nombreBT=infoBT.substring(0,infoBT.length()-18);
//Crea el intent, le añade la dirección MAC, y llama a la
siguiente actividad
Intent i=new Intent(conectabt.this,programaControl.class);
i.putExtra(DIRECCION_EXTRA,direccionMACBT);
i.putExtra(NOMBREBT_EXTRA,nombreBT);
startActivity(i);
//Esta actividad no se cierra y se mantiene en segundo plano
para que en caso de
//algún problema en la siguiente actividad, al cerrarla se
pueda volver a conectar a otro dispositivo
}
};
}
 

Actividad de control del led mediante Bluetooth 
El fichero activity_programa_control.xml, corresponde al layout de la actividad de control del led. 
Como objetos más importantes incorpora los botones de encender y apagar el led, mediante los 
que se enviarán las órdenes correspondientes y un texto que mostrará el estado del led recibido. 

El fichero programaControl.java corresponde al código que se encarga de conectarse  al 
dispositivo bluetooth, y realizará la comunicación mediante SPP. 

Tras los imports necesarios, 
import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Handler;
import java.io.IOException;
import java.util.UUID;
 

Definimos los objetos de la actividad. Se crean los Strings para recibir los datos del nombre y la 
dirección  del  dispositivo  bluetooth  seleccionado  por  la  actividad  de  selección,  un  indicador  de 
dispositivo conectado, un dialogo de progresso que aparecerá mientras se conecta al dispositivo, 
un adaptador y un socket bluetooth para realizar la comunicación bluetooth, y un Stringbuilder 
para manipular el String de datos recibidos. Finalmente un Thread o Hilo que se creará para recibir 
datos  en  segundo  plano,  y  el  Handle  necesario  para  comunicarse  con  el  hilo  principal.  Para  el 
Handler, el import necesario es: import android.os.Handler 
public class programaControl extends AppCompatActivity {

String nombreBT=null;
String direccionBT=null;
//Crea una variable booleana para saber cuando la aplicación esta
conectada al dispositivo
private boolean BTconectado=false; //Inicialmente se supone que no
esta conectada
private ProgressDialog progresoind;
BluetoothAdapter miBluetooth=null;
BluetoothSocket btSocket=null;
static final UUID UUIDserie=UUID.fromString("00001101-0000-1000-
8000-00805F9B34FB");
final int estadohandler = 0; //Sirve como identificador del mensaje
gestionado por el Handler
Handler leeBThandler; //El import ha de ser: import
android.os.Handler;
StringBuilder datosdeBTString=new StringBuilder(); //Crea un objeto
para manipular Strings
private HiloConexion HiloLectura;
 

Al  iniciar  la  actividad,  en  el  método  onCreate(),  asignamos  los  objetos  gráficos  y  el  adaptador 
Bluetooth del dispositivo Android al objeto creado: 
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_programa_control);

//Crea y enlaza los elementos graficos


TextView dispositivoBT=(TextView)findViewById(R.id.dispositivoBT);
Button botON=(Button)findViewById(R.id.botON);
Button botOFF=(Button)findViewById(R.id.botOFF);
Button botdesc=(Button)findViewById(R.id.botdescon);
final TextView estado=(TextView)findViewById(R.id.estado);
final TextView trama=(TextView)findViewById(R.id.trama);
final TextView tiempo=(TextView)findViewById(R.id.tiempo);
 

Crea un Intent para leer los datos del dispositivo Bluetooth enviados por la actividad de selección 
de  dirección,  y  ejecuta  una  tarea  en  segundo  plano  para  conectarse  al  dispositivo  bluetooth 
seleccionado. 

//Crea un intent para leer los datos enviados por la actividad de


seleccionar dispositivo BT
Intent intentanterior=getIntent();
direccionBT=intentanterior.getStringExtra(conectabt.DIRECCION_EXTRA);
nombreBT=intentanterior.getStringExtra(conectabt.NOMBREBT_EXTRA);

dispositivoBT.setText(nombreBT+" : "+direccionBT);

//Ejecuta la tarea en segundo plano ConectarBT para conectarse al


dispositivo seleccionado
new ConectarBT().execute();
 
Crea  los  listeners  de  los  botones  para  encender  y  apagar  el  led,  y  para  desconectarse  del 
dispositivo bluetooth, que llamarán a las funciones que realizarán la acción correspondiente. 

//Crea listeners de los botones


botON.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EnciendLedBT();
}
});

botOFF.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ApagaLedBT();
}
});

botdesc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DesconectarBT();
}
});
 

Para finalizar el código del método onCreate(), crea un Handler para leer los datos del Thread 
Hilolectura,  y  actualizar  los  valores  recibidos  desde  el  dispositivo  Bluetooth.  Primer  mira  si  el 
origen de los datos del mensaje, y si es el valor del identificador estadohandler (0), es que son los 
datos recibidos por bluetooth, extrae los datos y los añade al objeto datosdeBtString. La trama 
recibida tiene el formato *tiempo+estadoled+@, con lo que comprueba si encuentra el carácter 
‘@’ y el índice de la posición en que se encuentra. Si lo encuentra y el índice es mayor de 0, extrae 
la trama hasta ‘@’. Entonces busca si el primer carácter es ‘*’,  y si es el primer carácter es que 
tiene la trama completa y extrae los valores de tiempo y estado que se encuentran entre los dos 
caracteres ‘+’. Tras extraer los datos los muestra en los TextView correspondientes. Finalmente 
borra  los  objetos  que  contenían  la  trama  hasta  la  siguiente  lectura.  Hasta  aquí  el  código  del 
método onCreate(). 

//Crea el Handler para recibir los datos del bluetooth leidos por el
Thread
leeBThandler = new Handler(){
public void handleMessage(Message msg) { //Ha de estar
importado: import android.os.Message
if (msg.what==estadohandler){ //Si los datos del handler
son los leidos por el Thread
String datosleidosBT = (String) msg.obj; //Lee los datos
del Thread leidos de Bluetooth
datosdeBTString.append(datosleidosBT); // Copia los
datos leidos al objeto String
int indicefintrama = datosdeBTString.indexOf("@");
//Busca la posicion del carácter de fin de trama
if (indicefintrama>0){
String tramadatos
=datosdeBTString.substring(0,indicefintrama); //Extrae toda la trama de
datos
int longtrama = tramadatos.length();
trama.setText("Trama Recibida = "+tramadatos+" long
bytes:"+String.valueOf(longtrama));
if (tramadatos.charAt(0)== '*'){ //Comprueba si el
primer caracter es el inicio de trama
int masind1=tramadatos.indexOf("+");
int masind2=tramadatos.indexOf("+",masind1+1);
String tiempoBT=tramadatos.substring(1,masind1);
tiempo.setText("Tiempo: "+tiempoBT);
String
estadoled=tramadatos.substring(masind1+1,masind2);
estado.setText("Estado: "+estadoled);//+"
mas1:"+String.valueOf(masind1)+" mas2:"+String.valueOf(masind2));
}
datosdeBTString.delete(0,datosdeBTString.length());
tramadatos="";
}
}
}
};
}
 

Para conectarse al dispositivo bluetooth se utiliza una tarea en segundo plano del tipo AsyncTask. 
Esta consta de tres partes de código: una antes de ejecutar el código principal (onPreExecute()), 
otra  que  ejecuta  el  principal  código  en  segundo  plano  hasta  que  finaliza  el  código 
(doInBackground()),  y  finalmente  un  código  que  se  ejecuta  al  finalizar  el  código  principal 
(onPostExecute()).  Se  utiliza  una  tarea  en  segundo  plano  ya  que  el  tiempo  de  conexión  es 
suficientemente largo para dejar bloqueado el hilo principal de la actividad y provocar un error. 

Inicialmente se crea un objeto booleano para indicar si se ha conectado el dispositivo bluetooth, 
y en el método onPreExecute() se muestra un diálogo indicador de progreso. 

 
 

//Crea una tarea asíncrona en segundo plano (AsynTask) sin parámetros


para conectarse al dispositivo Bluetooth
//Si no se hiciera en segundo plano, al estar bloqueado el hilo
principal, si se tocara en pantalla apareceria error
private class ConectarBT extends AsyncTask <Void,Void,Void>
{
//Crea una variable para indicar en la tarea que se ha conectado al
dispositivo BT
private boolean Sehaconectado=true; //Inicialmente suponemos que nos
conectaremos correctamente

@Override
protected void onPreExecute() {
//super.onPreExecute();
//Muestra una rueda de progreso con el título Conectando y el
texto Paciencia

progresoind=ProgressDialog.show(programaControl.this,"Conectando...","Pa
ciencia");
}
En el código principal para conectar comprobará si aún no existe ningún dispositivo conectado, y 
en  caso  de  no  existir,  intentará  conectarse  a  la  dirección  seleccionada  por  la  actividad  de 
selección, mediante el adaptador disponible en Android y una conexión insegura al servicio serie 
SPP  de  bluetooth  utilizando  el  UUID  serie.  Si  no  consigue  conectarse  guardará  el  estado  en  el 
indicador correspondiente. 

//Mientras muestra la rueda, intenta conectar al dispositivo


@Override
protected Void doInBackground(Void... params) {

//Si no existe una conexión anterior o no esta conectado el


dispositivo, intenta conectarse con control de error
try
{
if (btSocket==null||!BTconectado)
{
//Asigna el adaptador bluetooth del propio dispositivo
miBluetooth=BluetoothAdapter.getDefaultAdapter();
//Crea un objeto disposito y lo asigna al BT remoto mediante
la dirección
BluetoothDevice
dispositivo=miBluetooth.getRemoteDevice(direccionBT);
//Asigna al objeto Socket, una conexión serie RFComm con eel
dispositivo remoto

btSocket=dispositivo.createInsecureRfcommSocketToServiceRecord(UUIDserie
);
//Deja de buscar dispositivos remotos
BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
//Recordar poner en el AndroidManifest : <uses-permission
android:name="android.permission.BLUETOOTH_ADMIN" />
//Intenta iniciar la conexión con el dispositivo remoto
btSocket.connect();
}
}
//En caso de error de conexión indica que no se ha conectado
catch (IOException e)
{
Sehaconectado=false;
}
return null;
}
 

Tras ejecutar el código principal de conexión, si no se ha conectado cierra la actividad y vuelve a 
la actividad de selección de dirección para volver a intentar con el mismo u otro dispositivo, y en 
caso de haberse conectado, cierra el dialogo indicador de progreso, y ejecuta la tarea en 
segundo plano (HiloLectura) del tipo Thread que se encargará de recibir los datos por bluetooth. 

@Override
protected void onPostExecute(Void aVoid) {
//Verificar si funciona sin la siguiente linea
//super.onPostExecute(aVoid);

//Tras intentar conectarse, si no se conecta, indica el error y


finaliza la tarea ConectarBT
if (!Sehaconectado)
{
String msg="Error de conexión. El dispositivo remoto soporta
Bluetooth serie SPP? Prueba otra vez";

Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_SHORT).show();
finish(); //Finaliza la actividad actual y la cierra
}
else //Si se ha conectado indica que se ha conectado
{

Toast.makeText(getApplicationContext(),"Conectado",Toast.LENGTH_SHORT).s
how();
BTconectado=true;
//Activa el Thread en segundo plano para la lectura de
bluetooth
HiloLectura = new HiloConexion();
HiloLectura.start();

}
progresoind.dismiss(); //Finaliza el indicador de la rueda de
progreso
}
}
 

La tarea en segundo plano que leerá los datos recibidos por bluetooth es del tipo Thread. En ella 
estará continuamente leyendo los datos del socket bluetooth, los convertirá a String y los pasa al 
mensaje que el Handler leerá indicando que es del tipo ‘estadohandler’ (0). 

Al inicio puede ser que en el buffer hubiera más de una trama, con lo que el handler no 
gestionaría bien la trama. Al ser la trama de menos de 20 caracteres, si los datos recibidos 
tienen una longitud mayor, estos no se envían al Handler y se pierden para vaciar el buffer. 

//Crea una nuevo hilo en segundo plano para leer continuamente la


entrada de datos por Bluetooth
private class HiloConexion extends Thread {

//Codigo que se ejecutará


public void run() {
byte[] buffer=new byte[256];
int bytes;

while (true){ //Estará continuamente ejecutandose la lectura de


bluetooth en segundo plano
try{
bytes=btSocket.getInputStream().read(buffer); //lee el
dispositivo de Bluetooth
String datosBTleidos = new String(buffer, 0, bytes);
//Crea el String con los datos leidos
if (bytes<20) { //Como la trama sabemos que tiene menos
de 20 carácteres, si hay más borramos la trama ya que no la enviamos
leeBThandler.obtainMessage(estadohandler, bytes, -1,
datosBTleidos).sendToTarget(); //Envia los datos al Handler
}
}
catch (IOException e){
break;
}
}
}

}
La función de encender el led envía un ‘1’ al dispositivo bluetooth: 

//Envia los datos para encender el led


private void EnciendLedBT()
{
if(btSocket!=null)
{
try
{
btSocket.getOutputStream().write("1".getBytes());
}
catch (IOException e)
{
Toast.makeText(getApplicationContext(),"Error encender
Led",Toast.LENGTH_SHORT).show();
}
}
}
 

La función de apagar el led envía un ‘0’ al dispositivo bluetooth: 

//Envia los datos para apagar el led


private void ApagaLedBT()
{
if(btSocket!=null)
{
try
{
btSocket.getOutputStream().write("0".getBytes());
}
catch (IOException e)
{
Toast.makeText(getApplicationContext(),"Error apagar
Led",Toast.LENGTH_SHORT).show();
}
}
}
 

Finalmente la función desconectar, cierra el socket de la conexión bluetooth, y finaliza la 
actividad. 
private void DesconectarBT()
{
if(btSocket!=null)
{
try
{
btSocket.close();
}
catch (IOException e)
{
Toast.makeText(getApplicationContext(),"Error
desconexión",Toast.LENGTH_SHORT).show();
}
}
finish(); //Finaliza la actividad actual y la cierra
}
}
Códigos fuente 
Fichero activity_conectabt.xml 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="com.example.esaii.bt_ard_rxtx.arduinorxtxbt.conectabt">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Conectar a dispositivo bluetooth"
android:id="@+id/textView"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Conectar"
android:id="@+id/button"
android:layout_below="@+id/textView"
android:layout_centerHorizontal="true" />

<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_below="@+id/button"
android:layout_toStartOf="@+id/button"
android:layout_toLeftOf="@+id/button" />
</RelativeLayout>
 

Fichero activity_programa_control.xml 
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
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="com.example.esaii.bt_ard_rxtx.arduinorxtxbt.programaContr
ol">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Dispositivo"
android:id="@+id/dispositivoBT"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Encender"
android:id="@+id/botON"
android:layout_below="@+id/dispositivoBT"
android:layout_centerHorizontal="true" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Apagar"
android:id="@+id/botOFF"
android:layout_below="@+id/botON"
android:layout_centerHorizontal="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:text="Estado LED"
android:id="@+id/estado"
android:layout_below="@+id/tiempo"
android:layout_alignRight="@+id/botOFF"
android:layout_alignEnd="@+id/botOFF" />

<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Desconectar"
android:id="@+id/botdescon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tiempo"
android:id="@+id/tiempo"
android:layout_below="@+id/botOFF"
android:layout_centerHorizontal="true" />

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Trama"
android:id="@+id/trama"
android:layout_below="@+id/estado"
android:layout_centerHorizontal="true" />

</RelativeLayout>
 
Fichero AndroidManifest.xml 
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.esaii.bt_ard_rxtx.arduinorxtxbt">

<uses-permission android:name="android.permission.BLUETOOTH" />


<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"
/>

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".conectabt">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category
android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".programaControl"></activity>
</application>

</manifest>
 

Fichero conectabt.java 
package com.example.esaii.bt_ard_rxtx.arduinorxtxbt;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Set;

public class conectabt extends AppCompatActivity {

// Crea los objetos para enlazar con los objetos gráficos


Button btnconectar;
ListView listadispositivosBT;

//Crea objeto bluetooth


private BluetoothAdapter miBluetooth=null;
//Crea un objeto BluetoothDevice, pero sin elementos duplicados
(java.util.Set <E>)
private Set <BluetoothDevice> disposivosEmparejados;
//Crea un String "direccionBT" que se enviara como identificador de
la dirección a la aplicación
public static String DIRECCION_EXTRA = "direccion BT";
public static String NOMBREBT_EXTRA = "nombre BT";

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_conectabt);

//Crea los enlaces a los objectos gráficos


btnconectar=(Button) findViewById(R.id.button);
listadispositivosBT=(ListView) findViewById(R.id.listView);

//Asigna el adaptador bluetooth por defecto del propio


dispositivo al objeto miBluetooth
miBluetooth = BluetoothAdapter.getDefaultAdapter();

if (miBluetooth==null) //Si el dispositivo propio no tiene


bluetooth indica el error
{
Toast.makeText(getApplicationContext(),"Bluetooth no
existe",Toast.LENGTH_LONG).show();
}
else
{
if (miBluetooth.isEnabled()) //Si esta activado no hace nada
// Recordar añadir al fichero AndroidManifest.xml la linea:
<uses-permission android:name="android.permission.BLUETOOTH" />
{}
else //Si no esta activado llama a la actividad de activar
bluetooth del Adaptador del dispositivo android
{
Intent activaBT=new
Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(activaBT,1);
}
}

btnconectar.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buscarDispositivo(); //Busca dispositivo bluetooth, se
conecta y activa siguiente actividad
}
});
}

private void buscarDispositivo()


{
//Toast.makeText(getApplicationContext(),"Buscando
dispositivos",Toast.LENGTH_SHORT).show();
disposivosEmparejados=miBluetooth.getBondedDevices(); //Mira
los dispositivos BT emparejados
ArrayList lista=new ArrayList(); //Crea un objeto lista
if (disposivosEmparejados.size()>0) //Si hay algún dispositivo
BT emparejado, los añade a la lista
{
for (BluetoothDevice bt:disposivosEmparejados)
{
lista.add(bt.getName()+"\n"+bt.getAddress());
}
}
else //Si no hay dispositivo BT emparejados, avisa
{
Toast.makeText(getApplicationContext(),"No hay dispositivos
Bluetooth emparejados",Toast.LENGTH_LONG).show();
}

//Crea un ArrayAdapter para configurar la lista de dispositivos


y le asigna los encontrados
final ArrayAdapter adaptador=new
ArrayAdapter(this,android.R.layout.simple_list_item_1,lista);
listadispositivosBT.setAdapter(adaptador); //Asigna el
adaptador a la lista
//Asigna al clicklistener de dispositivo seleccionado de la
lista
listadispositivosBT.setOnItemClickListener(miListenerdeLista);

}
//Crea el clickListener que vigile el dispositivo seleccionado de la
lista
private AdapterView.OnItemClickListener miListenerdeLista=new
AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int
position, long id) {
//Convierte de tipo view a textview y extrae el texto del
dispositivo BT seleccionado
String infoBT=((TextView)view).getText().toString();
//Extrae los últimos 17 carácteres que corresponden a la MAC
del dispositivo BT seleccionado
String direccionMACBT=infoBT.substring(infoBT.length()-17);
String nombreBT=infoBT.substring(0,infoBT.length()-18);
//Crea el intent, le añade la dirección MAC, y llama a la
siguiente actividad
Intent i=new Intent(conectabt.this,programaControl.class);
i.putExtra(DIRECCION_EXTRA,direccionMACBT);
i.putExtra(NOMBREBT_EXTRA,nombreBT);
startActivity(i);
//Esta actividad no se cierra y se mantiene en segundo plano
para que en caso de
//algún problema en la siguiente actividad, al cerrarla se
pueda volver a conectar a otro dispositivo
}
};
}
   

Fichero programaControl.java 
package com.example.esaii.bt_ard_rxtx.arduinorxtxbt;

import android.app.ProgressDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.os.Handler;

import java.io.IOException;
import java.util.UUID;

public class programaControl extends AppCompatActivity {

String nombreBT=null;
String direccionBT=null;
//Crea una variable booleana para saber cuando la aplicación esta
conectada al dispositivo
private boolean BTconectado=false; //Inicialmente se supone que no
esta conectada

private ProgressDialog progresoind;

BluetoothAdapter miBluetooth=null;
BluetoothSocket btSocket=null;
static final UUID UUIDserie=UUID.fromString("00001101-0000-1000-
8000-00805F9B34FB");

final int estadohandler = 0; //Sirve como identificador del mensaje


gestionado por el Handler
Handler leeBThandler; //El import ha de ser: import
android.os.Handler;
StringBuilder datosdeBTString=new StringBuilder(); //Crea un objeto
para manipular Strings
private HiloConexion HiloLectura;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_programa_control);

//Crea y enlaza los elementos graficos


TextView
dispositivoBT=(TextView)findViewById(R.id.dispositivoBT);
Button botON=(Button)findViewById(R.id.botON);
Button botOFF=(Button)findViewById(R.id.botOFF);
Button botdesc=(Button)findViewById(R.id.botdescon);
final TextView estado=(TextView)findViewById(R.id.estado);
final TextView trama=(TextView)findViewById(R.id.trama);
final TextView tiempo=(TextView)findViewById(R.id.tiempo);

//Crea un intent para leer los datos enviados por la actividad


de seleccionar dispositivo BT
Intent intentanterior=getIntent();

direccionBT=intentanterior.getStringExtra(conectabt.DIRECCION_EXTRA);

nombreBT=intentanterior.getStringExtra(conectabt.NOMBREBT_EXTRA);

dispositivoBT.setText(nombreBT+" : "+direccionBT);

//Ejecuta la tarea en segundo plano ConectarBT para conectarse


al dispositivo seleccionado
new ConectarBT().execute();
//Crea listeners de los botones
botON.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
EnciendLedBT();
}
});

botOFF.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ApagaLedBT();
}
});

botdesc.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
DesconectarBT();
}
});

//Crea el Handler para recibir los datos del bluetooth leidos


por el Thread
leeBThandler = new Handler(){

public void handleMessage(Message msg) { //Ha de estar


importado: import android.os.Message
if (msg.what==estadohandler){ //Si los datos del
handler son los leidos por el Thread
String datosleidosBT = (String) msg.obj; //Lee los
datos del Thread leidos de Bluetooth
datosdeBTString.append(datosleidosBT); // Copia los
datos leidos al objeto String
int indicefintrama = datosdeBTString.indexOf("@");
//Busca la posicion del carácter de fin de trama
if (indicefintrama>0){
String tramadatos
=datosdeBTString.substring(0,indicefintrama); //Extrae toda la trama de
datos

int longtrama = tramadatos.length();


trama.setText("Trama Recibida = "+tramadatos+"
long bytes:"+String.valueOf(longtrama));

if (tramadatos.charAt(0)== '*'){ //Comprueba si


el primer caracter es el inicio de trama
int masind1=tramadatos.indexOf("+");
int
masind2=tramadatos.indexOf("+",masind1+1);
String
tiempoBT=tramadatos.substring(1,masind1);
tiempo.setText("Tiempo: "+tiempoBT);
String
estadoled=tramadatos.substring(masind1+1,masind2);
estado.setText("Estado: "+estadoled);//+"
mas1:"+String.valueOf(masind1)+" mas2:"+String.valueOf(masind2));
}
datosdeBTString.delete(0,datosdeBTString.length());
tramadatos="";
}

}
}
};
}

//Crea una tarea asíncrona en segundo plano (AsynTask) sin


parámetros para conectarse al dispositivo Bluetooth
//Si no se hiciera en segundo plano, al estar bloqueado el hilo
principal, si se tocara en pantalla apareceria error
private class ConectarBT extends AsyncTask <Void,Void,Void>
{
//Crea una variable para indicar en la tarea que se ha conectado
al dispositivo BT
private boolean Sehaconectado=true; //Inicialmente suponemos que
nos conectaremos correctamente

@Override
protected void onPreExecute() {
//super.onPreExecute();
//Muestra una rueda de progreso con el título Conectando y
el texto Paciencia

progresoind=ProgressDialog.show(programaControl.this,"Conectando...","Pa
ciencia");
}

//Mientras muestra la rueda, intenta conectar al dispositivo


@Override
protected Void doInBackground(Void... params) {

//Si no existe una conexión anterior o no esta conectado el


dispositivo, intenta conectarse con control de error
try
{
if (btSocket==null||!BTconectado)
{
//Asigna el adaptador bluetooth del propio
dispositivo
miBluetooth=BluetoothAdapter.getDefaultAdapter();
//Crea un objeto disposito y lo asigna al BT remoto
mediante la dirección
BluetoothDevice
dispositivo=miBluetooth.getRemoteDevice(direccionBT);
//Asigna al objeto Socket, una conexión serie RFComm
con eel dispositivo remoto

btSocket=dispositivo.createInsecureRfcommSocketToServiceRecord(UUIDserie
);
//Deja de buscar dispositivos remotos

BluetoothAdapter.getDefaultAdapter().cancelDiscovery();
//Recordar poner en el AndroidManifest : <uses-
permission android:name="android.permission.BLUETOOTH_ADMIN" />
//Intenta iniciar la conexión con el dispositivo
remoto
btSocket.connect();
}
}
//En caso de error de conexión indica que no se ha conectado
catch (IOException e)
{
Sehaconectado=false;
}
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
//Verificar si funciona sin la siguiente linea
//super.onPostExecute(aVoid);

//Tras intentar conectarse, si no se conecta, indica el


error y finaliza la tarea ConectarBT
if (!Sehaconectado)
{
String msg="Error de conexión. El dispositivo remoto
soporta Bluetooth serie SPP? Prueba otra vez";

Toast.makeText(getApplicationContext(),msg,Toast.LENGTH_SHORT).show();
finish(); //Finaliza la actividad actual y la cierra
}
else //Si se ha conectado indica que se ha conectado
{

Toast.makeText(getApplicationContext(),"Conectado",Toast.LENGTH_SHORT).s
how();
BTconectado=true;
//Activa el Thread en segundo plano para la lectura de
bluetooth
HiloLectura = new HiloConexion();
HiloLectura.start();

}
progresoind.dismiss(); //Finaliza el indicador de la rueda
de progreso
}
}

//Crea una nuevo hilo en segundo plano para leer continuamente la


entrada de datos por Bluetooth
private class HiloConexion extends Thread {

//Codigo que se ejecutará


public void run() {
byte[] buffer=new byte[256];
int bytes;

while (true){ //Estará continuamente ejecutandose la lectura


de bluetooth en segundo plano
try{
bytes=btSocket.getInputStream().read(buffer); //lee
el dispositivo de Bluetooth
String datosBTleidos = new String(buffer, 0, bytes);
//Crea el String con los datos leidos
if (bytes<20) { //Como la trama sabemos que tiene
menos de 20 carácteres, si hay más borramos la trama ya que no la
enviamos
leeBThandler.obtainMessage(estadohandler, bytes,
-1, datosBTleidos).sendToTarget(); //Envia los datos al Handler
}
}
catch (IOException e){
break;
}
}
}

//Crea las funciones y acciones de los botones

//Envia los datos para encender el led


private void EnciendLedBT()
{
if(btSocket!=null)
{
try
{
btSocket.getOutputStream().write("1".getBytes());
}
catch (IOException e)
{
Toast.makeText(getApplicationContext(),"Error encender
Led",Toast.LENGTH_SHORT).show();
}
}
}

//Envia los datos para apagar el led


private void ApagaLedBT()
{
if(btSocket!=null)
{
try
{
btSocket.getOutputStream().write("0".getBytes());
}
catch (IOException e)
{
Toast.makeText(getApplicationContext(),"Error apagar
Led",Toast.LENGTH_SHORT).show();
}
}
}

//Apaga la conexión y cierra la actividad


private void DesconectarBT()
{
if(btSocket!=null)
{
try
{
btSocket.close();
}
catch (IOException e)
{
Toast.makeText(getApplicationContext(),"Error
desconexión",Toast.LENGTH_SHORT).show();
}
}
finish(); //Finaliza la actividad actual y la cierra
}