LED Control using an Android app, Arduino and Bluetooth

This article shows the steps for LED Control using Arduino Bluetooth and Android. Normally the content I post is about C++ concepts, but since this code was used in my latest university engineering project, I wanted to break down and show 3 different technologies being combined together for an application. You can find more details of that project on my personal website.

Setting up the hardware and IDE

You will need the following

The schematic of the Bluetooth module to the Arduino UNO Board

arduino-bluetooth

Setup the Bluetooth code and Library

The tutorials which are currently online regarding the Bluetooth communication code are outdated and I was trying to use that old code for my project, which ended up being a very painful experience, as I spent 3 weeks trying to get the Bluetooth code to work. Luckily I eventually found a solution. That is to use a Bluetooth library dedicated to work with the Arduino microcontroller. The library is called the Bluetooth SPP Library.

bluetoothspp

Once the Bluetooth library has been set up and imported in Android Studio, use the code below for the Bluetooth communication between the Arduino microcontroller and Android app.

MainActivity.java 

</pre><pre>import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import android.view.View.OnClickListener;

import app.akexorcist.bluetotohspp.library.BluetoothSPP;
import app.akexorcist.bluetotohspp.library.BluetoothState;
import app.akexorcist.bluetotohspp.library.BluetoothSPP.BluetoothConnectionListener;
import app.akexorcist.bluetotohspp.library.BluetoothSPP.OnDataReceivedListener;
import app.akexorcist.bluetotohspp.library.DeviceList;


public class MainActivity extends AppCompatActivity
{
    // Widgets
    Button btnPaired;
    Button btnDates;

    BluetoothSPP bt;

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

        bt = new BluetoothSPP(this);

        // Calling widgets
        btnPaired = (Button) findViewById(R.id.BtnConnect);
        btnDates = (Button) findViewById(R.id.btnSetup);


        //-------------------------------------------------
        // Set up Bluetooth
        //-------------------------------------------------
        if (!bt.isBluetoothAvailable()) {
            Toast.makeText(getApplicationContext()
                    , "Bluetooth is not available"
                    , Toast.LENGTH_SHORT).show();
            finish();
        }

        bt.setOnDataReceivedListener(new OnDataReceivedListener() {
            public void onDataReceived(byte[] data, String message) {
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
            }
        });

        bt.setBluetoothConnectionListener(new BluetoothConnectionListener() {
            public void onDeviceConnected(String name, String address) {
                Toast.makeText(getApplicationContext()
                        , "Connected to " + name + "\n" + address
                        , Toast.LENGTH_SHORT).show();
            }

            public void onDeviceDisconnected() {
                Toast.makeText(getApplicationContext()
                        , "Connection lost", Toast.LENGTH_SHORT).show();
            }

            public void onDeviceConnectionFailed() {
                Toast.makeText(getApplicationContext()
                        , "Unable to connect", Toast.LENGTH_SHORT).show();
            }
        });


        //---------------------------------------------------
        // Bluetooth connect button
        //---------------------------------------------------
        btnPaired.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                if (bt.getServiceState() == BluetoothState.STATE_CONNECTED)
                {
                    bt.disconnect();
                }
                else
                {
                    Intent intent = new Intent(getApplicationContext(), DeviceList.class);
                    startActivityForResult(intent, BluetoothState.REQUEST_CONNECT_DEVICE);
                }
            }
        });

        //-----------------------------------------------------
        // This will open up the next page, the Date Setup
        //-----------------------------------------------------
        btnDates.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent myIntent = new Intent(MainActivity.this, DateSetup.class);
                MainActivity.this.startActivity(myIntent);
            }
        });
    }


    public void onDestroy()
    {
        super.onDestroy();
        bt.stopService();
    }


    public void onStart()
    {
        super.onStart();
        if (!bt.isBluetoothEnabled()) {
            Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(intent, BluetoothState.REQUEST_ENABLE_BT);
        } else {
            if(!bt.isServiceAvailable()) {
                bt.setupService();
                bt.startService(BluetoothState.DEVICE_OTHER);
                //setup();
                //turnoff();
            }
        }
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if(requestCode == BluetoothState.REQUEST_CONNECT_DEVICE)
        {
            if(resultCode == Activity.RESULT_OK)
                bt.connect(data);
        }
        else if(requestCode == BluetoothState.REQUEST_ENABLE_BT)
        {
            if(resultCode == Activity.RESULT_OK)
            {
                bt.setupService();
                bt.startService(BluetoothState.DEVICE_OTHER);
                //setup();
                //turnoff();
            }
            else
            {
                Toast.makeText(getApplicationContext()
                        , "Bluetooth was not enabled."
                        , Toast.LENGTH_SHORT).show();
                finish();
            }
        }
    }


}
</pre><pre>


Setup the GUI Menu and Buttons

In Android Studio, create the basic GUI by adding in a couple of buttons and use the code below to link up the buttons to the Bluetooth code.

led-switch-menu

IrrigationControl.java 

<pre>public class IrrigationControl extends MainActivity
{

    Button btnOn;
    Button btnOff;
    Button btnBack;

    TextView Display;
    Handler h;
    //TextView txtArduino;


    // Bluetooth connection code
    final int RECEIVE_MESSAGE = 1;
    private BluetoothAdapter btAdapter = null;
    private BluetoothSocket btSocket = null;
    private StringBuilder sb = new StringBuilder();

    private ConnectedThread mConnectedThread;
    private static final String TAG = "bluetooth2";

    // SPP UUID Service
    private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

    // MAC Access of Bluetooth module
    // IMPORTANT: You will need to change the address as each bluetooth module has a different MAC ADDRESS"
    private static String address = "98:D3:35:00:A2:BF";

    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.relay_switch);

        btnOn = (Button)findViewById(R.id.buttonOn);
        btnOff = (Button)findViewById(R.id.buttonOff);
        btnBack = (Button)findViewById(R.id.btn_back);

        Display = (TextView)findViewById(R.id.textViewDisplay);

        //txtArduino = (TextView)findViewById(R.id.Arduinotxt);

        //----------------------------------------------
        // Handler code
        //----------------------------------------------
        h = new Handler()
        {
            public void handleMessage(android.os.Message msg)
            {
                switch(msg.what)
                {
                    case RECEIVE_MESSAGE:
                        byte[] readBuf = (byte[]) msg.obj;
                        String strIncom = new String(readBuf, 0, msg.arg1);

                        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();
        checkBTState();


        //--------------------------------------------
        // On and off button press
        //--------------------------------------------
        btnOn.setOnClickListener(new View.OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Display.setText("On");

                // Send "1" via Bluetooth
                mConnectedThread.write("1");
                // Send Command to the Arduino board
            }
        });

        btnOff.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                Display.setText("Off");

                // Send "0" via Bluetooth
                mConnectedThread.write("0");
                // Send Command to the Arduino board
            }
        });

        //----------------------------------------------------
        // Back to previous activity
        // http://stackoverflow.com/questions/4038479/android-go-back-to-previous-activity
        //-----------------------------------------------------
        btnBack.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v)
            {
                Intent myIntent = new Intent(IrrigationControl.this, DateSetup.class);
                IrrigationControl.this.startActivity(myIntent);
            }
        });

    }


    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 stream
            // 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(RECEIVE_MESSAGE, bytes, -1, buffer).sendToTarget();     // Send to message queue Handler
                }
                catch (IOException e)
                {
                    break;
                }
            }
        }

        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() + "...");
            }
        }

    }

}

Arduino code
Once the Android app code is complied and running, we can then implement the Aruduino code that will receive the bluetooth commands from the Android app and control the LED. Copy and paste the codebelow into the Arduino IDE and compile the code. Once it’s been compiled, send it to the Arduino microncontroller via USB.


#include <SoftwareSerial.h>

SoftwareSerial BT(10, 11);
// creates a "virtual" serial port/UART
// connect BT module TX to D10
// connect BT module RX to D11
// connect BT Vcc to 5V, GND to GND
void setup()
{
// set digital pin to control as an output
pinMode(13, OUTPUT);
// set the data rate for the SoftwareSerial port
BT.begin(9600);
// Send test message to other device
BT.println("Hello from Arduino");
}
char a; // stores incoming character from other device
void loop()
{
if (BT.available())
// if text arrived in from BT serial...
{
a=(BT.read());
if (a=='1')
{
digitalWrite(13, HIGH);
BT.println("LED on");
}
if (a=='0')
{
digitalWrite(13, LOW);
BT.println("LED off");
}
}
}

 

Share this post