Category: Main page » Arduino

Data transfer between Android and Arduino via Bluetooth

This article, shows two examples of working with Bluetooth: 1. Send data to Arduino 2. Data transfer between Android and Arduino.

Arduino

Wiring diagram is the same as in the previous article:

Connect Bluetooth module to Arduino

I use Arduino Nano V3 and Bluetooth module HC-06. Also, I connected the external LED to pin 12. Our program:

char incomingByte;  // incoming data
int  LED = 12;      // LED pin

void setup() {
  Serial.begin(9600); // initialization
  pinMode(LED, OUTPUT);
  Serial.println("Press 1 to LED ON or 0 to LED OFF...");
}

void loop() {
  if (Serial.available() > 0) {  // if the data came
    incomingByte = Serial.read(); // read byte
    if(incomingByte == '0') {
       digitalWrite(LED, LOW);  // if 1, switch LED Off
       Serial.println("LED OFF. Press 1 to LED ON!");  // print message
    }
    if(incomingByte == '1') {
       digitalWrite(LED, HIGH); // if 0, switch LED on
       Serial.println("LED ON. Press 0 to LED OFF!");
    }
  }
}

Android

We will use the Java code with an explicit MAC-address of the device. Find MAC-address can be in the program for Android: Bluetooth Terminal:

MAC-address

Our device is "BOLUTEK" with MAC-address 00:15:FF:F2:19:4C.

The first program is very simple, the main activity will contain two buttons: turn on LED and turn off LED. Data transfer in the program will be implemented only on Android devices to Arduino

Main activity

And our Java code of main activity:

package com.example.bluetooth1;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;
 
import com.example.bluetooth1.R;
 
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
 
public class MainActivity extends Activity {
  private static final String TAG = "bluetooth1";
   
  Button btnOn, btnOff;
   
  private BluetoothAdapter btAdapter = null;
  private BluetoothSocket btSocket = null;
  private OutputStream outStream = null;
   
  // SPP UUID service 
  private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
 
  // MAC-address of Bluetooth module (you must edit this line)
  private static String address = "00:15:FF:F2:19:5F";
   
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
 
    setContentView(R.layout.activity_main);
 
    btnOn = (Button) findViewById(R.id.btnOn);
    btnOff = (Button) findViewById(R.id.btnOff);
     
    btAdapter = BluetoothAdapter.getDefaultAdapter();
    checkBTState();
 
    btnOn.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        sendData("1");
        Toast.makeText(getBaseContext(), "Turn on LED", Toast.LENGTH_SHORT).show();
      }
    });
 
    btnOff.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
        sendData("0");
        Toast.makeText(getBaseContext(), "Turn off LED", Toast.LENGTH_SHORT).show();
      }
    });
  }
  
  private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
      if(Build.VERSION.SDK_INT >= 10){
          try {
              final Method  m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
              return (BluetoothSocket) m.invoke(device, MY_UUID);
          } catch (Exception e) {
              Log.e(TAG, "Could not create Insecure RFComm Connection",e);
          }
      }
      return  device.createRfcommSocketToServiceRecord(MY_UUID);
  }
   
  @Override
  public void onResume() {
    super.onResume();
 
    Log.d(TAG, "...onResume - try connect...");
   
    // Set up a pointer to the remote node using it's address.
    BluetoothDevice device = btAdapter.getRemoteDevice(address);
   
    // Two things are needed to make a connection:
    //   A MAC address, which we got above.
    //   A Service ID or UUID.  In this case we are using the
    //     UUID for SPP.
   
	try {
		btSocket = createBluetoothSocket(device);
	} catch (IOException e1) {
		errorExit("Fatal Error", "In onResume() and socket create failed: " + e1.getMessage() + ".");
	}
       
    // Discovery is resource intensive.  Make sure it isn't going on
    // when you attempt to connect and pass your message.
    btAdapter.cancelDiscovery();
   
    // Establish the connection.  This will block until it connects.
    Log.d(TAG, "...Connecting...");
    try {
      btSocket.connect();
      Log.d(TAG, "...Connection ok...");
    } catch (IOException e) {
      try {
        btSocket.close();
      } catch (IOException e2) {
        errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
      }
    }
     
    // Create a data stream so we can talk to server.
    Log.d(TAG, "...Create Socket...");
 
    try {
      outStream = btSocket.getOutputStream();
    } catch (IOException e) {
      errorExit("Fatal Error", "In onResume() and output stream creation failed:" + e.getMessage() + ".");
    }
  }
 
  @Override
  public void onPause() {
    super.onPause();
 
    Log.d(TAG, "...In onPause()...");
 
    if (outStream != null) {
      try {
        outStream.flush();
      } catch (IOException e) {
        errorExit("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
      }
    }
 
    try     {
      btSocket.close();
    } catch (IOException e2) {
      errorExit("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
    }
  }
   
  private void checkBTState() {
    // Check for Bluetooth support and then check to make sure it is turned on
    // Emulator doesn't support Bluetooth and will return null
    if(btAdapter==null) { 
      errorExit("Fatal Error", "Bluetooth not support");
    } else {
      if (btAdapter.isEnabled()) {
        Log.d(TAG, "...Bluetooth ON...");
      } else {
        //Prompt user to turn on Bluetooth
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, 1);
      }
    }
  }
 
  private void errorExit(String title, String message){
    Toast.makeText(getBaseContext(), title + " - " + message, Toast.LENGTH_LONG).show();
    finish();
  }
 
  private void sendData(String message) {
    byte[] msgBuffer = message.getBytes();
 
    Log.d(TAG, "...Send data: " + message + "...");
 
    try {
      outStream.write(msgBuffer);
    } catch (IOException e) {
      String msg = "In onResume() and an exception occurred during write: " + e.getMessage();
      if (address.equals("00:00:00:00:00:00")) 
        msg = msg + ".\n\nUpdate your server address from 00:00:00:00:00:00 to the correct address on line 35 in the java code";
      	msg = msg +  ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + " exists on server.\n\n";
       
      	errorExit("Fatal Error", msg);       
    }
  }
}

Android - transmit and receive data to the Arduino

To receive data from Arduino, in Android application we need to use threads. On the main window activity we add a new element TextView, which will be used to display the received data from the Arduino

package com.example.bluetooth2;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.UUID;
 
import com.example.bluetooth2.R;
 
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
 
public class MainActivity extends Activity {
  private static final String TAG = "bluetooth2";
   
  Button btnOn, btnOff;
  TextView txtArduino;
  Handler h;
   
  final int RECIEVE_MESSAGE = 1;		// Status  for Handler
  private BluetoothAdapter btAdapter = null;
  private BluetoothSocket btSocket = null;
  private StringBuilder sb = new StringBuilder();
  
  private ConnectedThread mConnectedThread;
   
  // SPP UUID service
  private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
 
  // MAC-address of Bluetooth module (you must edit this line)
  private static String address = "00:15:FF:F2:19:5F";
   
  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
 
    setContentView(R.layout.activity_main);
 
    btnOn = (Button) findViewById(R.id.btnOn);					// button LED ON
    btnOff = (Button) findViewById(R.id.btnOff);				// button LED OFF
    txtArduino = (TextView) findViewById(R.id.txtArduino);		// for display the received data from the Arduino
    
    h = new Handler() {
    	public void handleMessage(android.os.Message msg) {
    		switch (msg.what) {
            case RECIEVE_MESSAGE:													// if receive massage
            	byte[] readBuf = (byte[]) msg.obj;
            	String strIncom = new String(readBuf, 0, msg.arg1);					// create string from bytes array
            	sb.append(strIncom);												// append string
            	int endOfLineIndex = sb.indexOf("\r\n");							// determine the end-of-line
            	if (endOfLineIndex > 0) { 											// if end-of-line,
            		String sbprint = sb.substring(0, endOfLineIndex);				// extract string
                    sb.delete(0, sb.length());										// and clear
                	txtArduino.setText("Data from Arduino: " + sbprint); 	        // update TextView
                	btnOff.setEnabled(true);
                	btnOn.setEnabled(true); 
                }
            	//Log.d(TAG, "...String:"+ sb.toString() +  "Byte:" + msg.arg1 + "...");
            	break;
    		}
        };
	};
     
    btAdapter = BluetoothAdapter.getDefaultAdapter();		// get Bluetooth adapter
    checkBTState();
 
    btnOn.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
    	btnOn.setEnabled(false);
    	mConnectedThread.write("1");	// Send "1" via Bluetooth
        //Toast.makeText(getBaseContext(), "Turn on LED", Toast.LENGTH_SHORT).show();
      }
    });
 
    btnOff.setOnClickListener(new OnClickListener() {
      public void onClick(View v) {
    	btnOff.setEnabled(false);  
    	mConnectedThread.write("0");	// Send "0" via Bluetooth
        //Toast.makeText(getBaseContext(), "Turn off LED", Toast.LENGTH_SHORT).show();
      }
    });
  }
  
  private BluetoothSocket createBluetoothSocket(BluetoothDevice device) throws IOException {
      if(Build.VERSION.SDK_INT >= 10){
          try {
              final Method  m = device.getClass().getMethod("createInsecureRfcommSocketToServiceRecord", new Class[] { UUID.class });
              return (BluetoothSocket) m.invoke(device, MY_UUID);
          } catch (Exception e) {
              Log.e(TAG, "Could not create Insecure RFComm Connection",e);
          }
      }
      return  device.createRfcommSocketToServiceRecord(MY_UUID);
  }
   
  @Override
  public void onResume() {
    super.onResume();
 
    Log.d(TAG, "...onResume - try connect...");
   
    // Set up a pointer to the remote node using it's address.
    BluetoothDevice device = btAdapter.getRemoteDevice(address);
   
    // Two things are needed to make a connection:
    //   A MAC address, which we got above.
    //   A Service ID or UUID.  In this case we are using the
    //     UUID for SPP.
    
	try {
		btSocket = createBluetoothSocket(device);
	} catch (IOException e) {
		errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
	}
   
    // Discovery is resource intensive.  Make sure it isn't going on
    // when you attempt to connect and pass your message.
    btAdapter.cancelDiscovery();
   
    // Establish the connection.  This will block until it connects.
    Log.d(TAG, "...Connecting...");
    try {
      btSocket.connect();
      Log.d(TAG, "....Connection ok...");
    } catch (IOException e) {
      try {
        btSocket.close();
      } catch (IOException e2) {
        errorExit("Fatal Error", "In onResume() and unable to close socket during connection failure" + e2.getMessage() + ".");
      }
    }
     
    // Create a data stream so we can talk to server.
    Log.d(TAG, "...Create Socket...");
   
    mConnectedThread = new ConnectedThread(btSocket);
    mConnectedThread.start();
  }
 
  @Override
  public void onPause() {
    super.onPause();
 
    Log.d(TAG, "...In onPause()...");
  
    try     {
      btSocket.close();
    } catch (IOException e2) {
      errorExit("Fatal Error", "In onPause() and failed to close socket." + e2.getMessage() + ".");
    }
  }
   
  private void checkBTState() {
    // Check for Bluetooth support and then check to make sure it is turned on
    // Emulator doesn't support Bluetooth and will return null
    if(btAdapter==null) { 
      errorExit("Fatal Error", "Bluetooth not support");
    } else {
      if (btAdapter.isEnabled()) {
        Log.d(TAG, "...Bluetooth ON...");
      } else {
        //Prompt user to turn on Bluetooth
        Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
        startActivityForResult(enableBtIntent, 1);
      }
    }
  }
 
  private void errorExit(String title, String message){
    Toast.makeText(getBaseContext(), title + " - " + message, Toast.LENGTH_LONG).show();
    finish();
  }
 
  private class ConnectedThread extends Thread {
	    private final InputStream mmInStream;
	    private final OutputStream mmOutStream;
	 
	    public ConnectedThread(BluetoothSocket socket) {
	        InputStream tmpIn = null;
	        OutputStream tmpOut = null;
	 
	        // Get the input and output streams, using temp objects because
	        // member streams are final
	        try {
	            tmpIn = socket.getInputStream();
	            tmpOut = socket.getOutputStream();
	        } catch (IOException e) { }
	 
	        mmInStream = tmpIn;
	        mmOutStream = tmpOut;
	    }
	 
	    public void run() {
	        byte[] buffer = new byte[256];  // buffer store for the stream
	        int bytes; // bytes returned from read()

	        // Keep listening to the InputStream until an exception occurs
	        while (true) {
	        	try {
	                // Read from the InputStream
	                bytes = mmInStream.read(buffer);		// Get number of bytes and message in "buffer"
                    h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();		// Send to message queue Handler
	            } catch (IOException e) {
	                break;
	            }
	        }
	    }
	 
	    /* Call this from the main activity to send data to the remote device */
	    public void write(String message) {
	    	Log.d(TAG, "...Data to send: " + message + "...");
	    	byte[] msgBuffer = message.getBytes();
	    	try {
	            mmOutStream.write(msgBuffer);
	        } catch (IOException e) {
	            Log.d(TAG, "...Error data send: " + e.getMessage() + "...");     
	          }
	    }
	}
}

Video:

Code updated: 28.01.2013

Download APK-files for Android: bluetooth1.apk and bluetooth2.apk

Download source code for Arduino and Android

Author: Koltykov A.V.

Ajay 2014-09-05 15:19:11
Hi....
I have used this code in one of my programs and i find that when i open the app without enabling bluetooth, there is a prompt to turn on bluetooth. However the app crashes without waiting for the bluetooth to turn on. However i dont face any issues when i run the app after turning on bluetooth. Any help regarding this is appreciated.

[Reply] [Reply with quote]
↑ +3 ↓
Alessandro 2014-08-29 17:32:21
Thank you very much!!
Only, I need to use SoftwareSerial library... so instead of using Serial.println("bla bla bla"), I us bluetooth.print("bla bla bla"), into my Arduino mega 2560 sketch. So android doesn't receive the Arduino message. Instead, the opposite works(commands to Arduino). Do you have any suggestion?
Thanks a lot!! :-D

[Reply] [Reply with quote]
↑ 0 ↓
Martin 2014-08-24 16:17:27
Hello,

now I found a solution to display values (e.g. from a sensor) at the droids screen in a proper way.

Just "take" the system-time in onCreate (or elsewhere) and update your screen at fixed rate. I called my variable "oneTick", see down below.

Hope this will help others  :)

code:
if ((oneTick + 300) < System.currentTimeMillis()) {
oneTick = System.currentTimeMillis();
textViewAlcValues.setText("Data: " + sbprint); // update TextView
}

[Reply] [Reply with quote]
↑ 0 ↓
Martin 2014-08-24 04:33:06
Hello brother,
for the most part I understand your code and the setup. But very strange things happen to my experiment... Only if I switch RX/TX at one device I will be able to use your code.
Do you know why this happens?

Thank you so much, your tutorials are quiet perfect.  :)

[Reply] [Reply with quote]
↑ +2 ↓
M 2014-08-19 06:47:34
Hello once again. I solved my problem by appending data in thread, not handler. I see now that the handler can be delayed and simply miss data, or even start to display existing data while thread is overwriting it. I still call the handler each time data is received simply to tell it to send text to gui.

[Reply] [Reply with quote]
↑ +3 ↓
M 2014-08-19 04:32:34
Further to my previous comment, it appears that the code receives the data perfectly according to output log in Eclipse. The issue is transferring the data to the handler.

[Reply] [Reply with quote]
↑ 0 ↓
M 2014-08-19 03:54:06
Firstly thank you very much for posting this example code. It has been very helpful.

Secondly, I have a problem appending data in the handler. Maybe a race condition, or buffer clear issue as it will occasionally skip information or display it wrong. My small modification to your code basically removes endOfLineIndex and continually appends data but I get the following example output:


trimpot = 166
trimpot = 167
trimpot = 166
trimpot =
6
trimpot = 163
trimpot = 6
rrimpot =
6
t
62 ot =
62
trimpot =
66


I notice the issue with your original code (BTW I am not using Arduino but my microcontroller works fine with BlueTerm). Is this a known issue? I cannot see anything wrong with your code, but I am very new to Android. Help appreciated!

M

[Reply] [Reply with quote]
↑ 0 ↓
John Michael Clarin 2014-08-14 09:08:45
sir, are you using Eclipse IDE or Processing IDE?

[Reply] [Reply with quote]
↑ +3 ↓
Phalguni 2014-07-11 18:38:09
Hi grum,
Thanking you u done good job.God bless you  :like:

[Reply] [Reply with quote]
↑ +4 ↓
Dhakshina 2014-07-03 16:03:24
Same error
Fatal Error - In onResume() and an exception occured during write: socket closed.
Check that the SPP UUID: 0001101-0000-1000-8000-00805f9b34fb exists on server

[Reply] [Reply with quote]
↑ +6 ↓
altinay 2014-05-15 12:37:08
by the way, Digilent ChipKIT Max32 can be used instead of Arduino. BT HC-06 talks on Serial1 port of Max32. thats all.

[Reply] [Reply with quote]
↑ +4 ↓
Andrei Apopei 2014-04-17 14:07:13
What should be modified if I wanted to send characters to the Arduino - for more than 10 commands.
Thanks,
Andrei

[Reply] [Reply with quote]
↑ +5 ↓
Zahra Torabi 2014-02-25 15:55:27
Hi.
Thank you for your good example.
I have a question.
can i use this code for transfer data between two mobile with o.s Android?or it only work with Arduino?

[Reply] [Reply with quote]
↑ +4 ↓
baseball07 2014-02-20 21:01:57
Hi, when I run this on my device (4.2.2) the program immediately crashes saying "Unfortunately, Bluetooth2 has stopped". My device is Bluetooth enabled (have used the Bluetooth before on it) and both Bluetooth permissions are included in the build.

Does this have something to do with
"private BluetoothAdapter btAdapter = null;"

[Reply] [Reply with quote]
↑ +5 ↓
Greg 2014-02-19 03:49:09
Thanks for the great tutorial! I had the example running in no time and minutes later I created my own app to display data streaming from my arduino. Thank you!

[Reply] [Reply with quote]
↑ +6 ↓
Emika 2014-02-09 02:54:52
im use android gingerbread 2.3.6 and i have error message "In on Resume() and an exception occurred during write: socked closed.
check that SPP UUID:00001101-0000-1000-8000-00805F9B34FB exists on server
"

how should I solve the above is problem?... please help me

[Reply] [Reply with quote]
↑ +2 ↓
shannon 2014-02-04 16:42:11
Hi thanks for the example code! I managed to establish connection between the android phone and the Bluetooth remote device but could not send data from the phone to the device. What is lacking and what is the main purpose of the handler in the code?

[Reply] [Reply with quote]
↑ +2 ↓
Monte 2014-01-31 20:49:36
tried to compile the code, but the auto generated com.example.bluetooth1.R.java file is missing. The attachment provided by you doesn't contain this file. As such some error prevails. Please suggest a solution. Thanks in advance.

[Reply] [Reply with quote]
↑ +3 ↓
Helo 2014-06-18 08:13:03
Same as how you have change your first line of code:
package com.example.bluetooth1;
to your own package name,
package com.example.yourAppName;
you must do the same for line 8(first app) or 9(second app):
import com.example.bluetooth1.R;
to
import com.example.yourAppName.R;

[Reply] [Reply with quote]
↑ +2 ↓
Ralph 2014-02-09 11:58:59
i encounter this problem always in res library
sometimes i forgot to put correct id or the
draw-able file. png files only working for me with small letters

[Reply] [Reply with quote]
↑ -1 ↓
Ralph 2014-01-29 22:46:44
very much thanks to this website and to the author of the project.

bluetooth1 is working. you must set the bluetooth address correctly.
i get a hard time inputing the right address of my bt device. when i checked it in terminal it show's like this 0000:1:30403 i don't understand it at first i thought it was like this 00:00:01:30:40:03
but the correct address 00:00:01:03:40:03

bluetooth2 i this is also working but it has a little bug for me. when i click the on & off button it stay in press mode. you need to rotate the screen before it changes in unpress mode


[Reply] [Reply with quote]
↑ +6 ↓
Diane 2014-04-29 23:29:52
Hello, I have the same problem. Did you figure out how to fix it and allow the button to release after being pushed?

[Reply] [Reply with quote]
↑ +2 ↓
Emilio 2014-01-24 19:59:51
Hi, i'm reciving an error en onPause() it seems that de outstream is empty and can't fulsh() data.
Anyone has the same issue?

[Reply] [Reply with quote]
↑ +6 ↓

Pages: [1] | [2] | [3] | [4] | [5] [Next] | [Last]

Leave a comment

Your name:
Your Email:

Comment:
Type the characters: *
captcha
Refresh