Creating An Android App to Communicate With a Raspberry Pi Using BLE

Ingredients

Android Device
Android Studio
Raspberry Pi setup from the previous post

Introduction

In this project, the developer will reuse the Raspberry Pi hardware setup from the previous post and create an Android app which will be used to communicate with the Pi over BLE.

If you are using a different Raspberry Pi or Android device for this tutorial, be sure to follow the steps in the Raspberry Pi Setup, Pairing the Android Device with Raspberry Pi, and Setting Up and Connecting the Hardware to the Raspberry Pi sections in the previous post.

Creating the Android App Which Will Communicate Over BLE with the Raspberry Pi

In Android Studio, create a new project and name the project whatever you would like. Once the project is created you will want to setup the user interface. For this project, there are three main features that will need to be triggered from the Android app: Turn On LED, Turn Off LED, and Get Temperature. Create a button for each of these features and add a text box to display the temperature value next to the Get Temperature button. Below is the XML code that should be contained in the activity_main.xml file.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:orientation="vertical"
    android:padding="30dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/turn_on"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="onClick"
            android:text="Turn On LED" />

        <Button
            android:id="@+id/turn_off"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="onClick"
            android:text="Turn Off LED" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/get_temperature"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:onClick="onClick"
            android:text="Get Temperature" />

        <TextView
            android:id="@+id/status"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:textStyle="bold"
            android:textSize="15sp"
            android:text="" />
    </LinearLayout>

Once the activity_main.xml file is setup, the user interface in the design editor should look like this.

The buttons won’t do anything at the moment but run the app through the debugger to make sure that the app builds with no problems. Once this is complete, it is now time to add the code to MainActivity.java which will drive the functionality of the app. Below is the Java code that should be contained in the MainActivity.java file.

package com.androidbluetoothraspberrypiexample;

import android.os.Bundle;
import java.io.IOException;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.util.Log;
import android.content.Intent;
import android.os.Handler;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import android.app.Activity;
import java.io.InputStream;

public class MainActivity extends Activity {

    BluetoothSocket socket;
    BluetoothDevice bt_device = null;

    final byte delimiter = 35;
    int readBufferPosition = 0;

    private final static int REQUEST_ENABLE_BT = 1;

    private BluetoothAdapter bluetoothAdapter;

    private Button turnOnLED;
    private Button turnOffLED;
    private Button getTemperature;
    private TextView status;

    private Set<BluetoothDevice> pairedDevices;
    List<BluetoothDevice> PairedDevices;

    public void sendMessage(String send_message) {

        UUID uuid = UUID.fromString("ae14f5e2-9eb6-4015-8457-824d76384ba0");

        try {

            socket = bt_device.createRfcommSocketToServiceRecord(uuid);
            if (!socket.isConnected()) {
                socket.connect();
            }

            String message = send_message;

            OutputStream btOutputStream = socket.getOutputStream();
            btOutputStream.write(message.getBytes());

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setTitle("Android Bluetooth Raspberry Pi Demo");

        setContentView(R.layout.activity_main);

        turnOnLED = (Button) findViewById(R.id.turn_on);
        turnOffLED = (Button) findViewById(R.id.turn_off);
        getTemperature = (Button) findViewById(R.id.get_temperature);
        status = (TextView) findViewById(R.id.status);

        final Handler handler = new Handler();

        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

        bluetoothAdapter = bluetoothManager.getAdapter();

        pairedDevices = bluetoothAdapter.getBondedDevices();
        PairedDevices = new ArrayList<>(pairedDevices);

        for (int i = 0; i < PairedDevices.size(); i++) {

            String name = PairedDevices.get(i).getName();

            //The name in quotes must match your device
            if(name.equals("raspberry-pi-bt-demo"))
            {
                bt_device = PairedDevices.get(i);
                break;
            }
        }

        //Check if Bluetooth is enabled
        if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        final class workerThread implements Runnable {

            private String message;

            public workerThread(String msg) {
                message = msg;
            }

            public void run() {

                sendMessage(message);

                while(!Thread.currentThread().isInterrupted()) {

                    int bytesAvailable;
                    boolean workDone = false;

                    try {

                        final InputStream inputStream;
                        inputStream = socket.getInputStream();
                        bytesAvailable = inputStream.available();
                        if(bytesAvailable > 0)
                        {

                            byte[] packetBytes = new byte[bytesAvailable];
                            Log.e("Bytes received from", "Raspberry Pi");
                            byte[] readBuffer = new byte[1024];
                            inputStream.read(packetBytes);

                            for(int i=0;i<bytesAvailable;i++)
                            {
                                byte b = packetBytes[i];
                                if(b == delimiter)
                                {
                                    byte[] encodedBytes = new byte[readBufferPosition];
                                    System.arraycopy(readBuffer, 0, encodedBytes, 0, encodedBytes.length);
                                    final String data = new String(encodedBytes, "US-ASCII");
                                    readBufferPosition = 0;

                                    handler.post(new Runnable()
                                    {
                                        public void run()
                                        {
                                            status.setText(data);
                                        }
                                    });

                                    workDone = true;
                                    break;
                                }
                                else
                                {
                                    readBuffer[readBufferPosition++] = b;
                                }
                            }

                            if (workDone == true){
                                socket.close();
                                break;
                            }

                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }

                }

            }
        }

        //Turn On LED Listener
        turnOnLED.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                (new Thread(new workerThread("turn_on_LED"))).start();

            }
        });

        //Turn Off LED Listener
        turnOffLED.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                (new Thread(new workerThread("turn_off_LED"))).start();

            }
        });

        //Get Temperature Listener
        getTemperature.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                (new Thread(new workerThread("getTemperature"))).start();

            }
        });

    }

}

This app code will create the Bluetooth socket with the Raspberry Pi, get the Raspberry Pi from the list of paired devices on the Android device, send a command to the Raspberry Pi upon a button press in the app and listen for a status back from the Raspberry Pi to indicate whether the command was executed. Run the app through the debugger to make sure it builds.

Setting Up the BLE Communication on the Raspberry Pi

The next step is to set up the BLE communication code on the Raspberry Pi. The code is a slight modification from the Raspberry Pi code in the first post. Log into your Raspberry Pi and create a file called “bluetooth_demo_2.py”. Copy and paste the following code into that file.

import os
import glob
import time
import bluetooth
import RPi.GPIO as GPIO

base_dir = ‘/sys/bus/w1/devices/‘
device_folder = glob.glob(base_dir + os.sep + ’28*’)[0]
device_file = device_folder + ‘/w1_slave’

def read_temp_raw():
	f = open(device_file, ‘r’)
	lines = f.readlines()
	f.close()
	return lines

#Celcius Calculation
def read_temp_c():
	lines = read_temp_raw()
	while lines[0].strip()[-3:] != ‘YES’:
		time.sleep(0.2)
		lines = read_temp_raw()
	equals_pos = lines[1].find(‘t=‘)
	if equals_pos != -1:
		temp_string = lines[1][equals_pos+2:]
		temp_c = int(temp_string) / 1000.0
		temp_c = str(round(temp_c, 1))
		return temp_c

#Fahrenheit Calculation
def read_temp_f():
	lines = read_temp_raw()
	while lines[0].strip()[-3:] != ‘YES’:
		time.sleep(0.2)
		lines = read_temp_raw()
	equals_pos = lines[1].find(‘t=‘)
	if equals_pos != -1:
		temp_string = lines[1][equals_pos+2:]
		temp_f = (int(temp_string) / 1000.0) * 9.0 / 5.0 + 32.0
		temp_f = str(round(temp_f, 1))
		return temp_f

host = “”
port = 1

led_pin = 13
GPIO.setmode(GPIO.BCM)
GPIO.setup(led_pin, GPIO.OUT)

server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
print(‘Bluetooth Socket Created’)
server_sock.bind((“”,bluetooth.PORT_ANY))
print(“Bluetooth Binding Completed”)
server_sock.listen(1)

port = server_sock.getsockname()[1]

uuid = “ae14f5e2-9eb6-4015-8457-824d76384ba0”

bluetooth.advertise_service(server_sock,”raspberry-pi-bt-demo”,service_id = uuid, service_classes = [ uuid, bluetooth.SERIAL_PORT_CLASS ], profiles = [ bluetooth.SERIAL_PORT_PROFILE ] )

while True:
	print “Waiting for connection on RFCOMM channel %d” % port

	client_sock, client_info = server_sock.accept()
	print “Accepted connection from”, client_info

	try:
		data = client_sock.recv(1024)
		if len(data) == 0: break
		print “received [%s]” % data

		if data == “turn_off_LED”:
			GPIO.output(led_pin, GPIO.LOW)
			send_data = “Light is Off!#”
		elif data == “turn_on_LED”:
			GPIO.output(led_pin, GPIO.HIGH)
			send_data = “Light is On!#”
		elif data == “getTemperature”:
			send_data = “Temp (F): “ + read_temp_f() + “   Temp (C): “ + read_temp_c() + “#”
		else:
			send_data = “\nInvalid Input\n”

		client_sock.send(send_data)
		print “sending [%s]” % send_data

	except IOError:
		pass

	except KeyboardInterrupt:
		
		print “disconnected”
		
		client_sock.close()
		server_sock.close()
		print “all done”

		break

Now the Raspberry Pi should be able to receive commands from the Android device to turn the LED on or off or read the temperature. After the Raspberry Pi receives and executes a command, it will return a status back to the app to display. The UUID (“ae14f5e2-9eb6-4015-8457-824d76384ba0”) referenced in this demo may be any UUID generated here as long as the UUID in the Android code matches the UUID referenced in the Raspberry Pi python code. Now run the python code on the Raspberry Pi by typing the command “python bluetooth_demo_2.py” into the Pi. This will put the Pi in a state where it is listening for commands from the app.

Final Step

The last step is to build the project through Android studio onto the device. When the app is up and running on the device, the app code will create the socket to communicate with the Pi. Press the “Turn On LED” button in the app and the LED on the breadboard should light up. A status will be returned to the app from the Pi to indicate that turning on the LED was successful. The app should display “Light is On!” in the status textbox. Try the other two buttons to ensure that they work as well. You have now created a way to communicate over BLE between an Android device and Raspberry Pi!