Building an Android App to Communicate With a Raspberry Pi to Detect and Record When Sound Level Exceeds a Decibel Threshold

Ingredients

Android Device
Android Studio
Fully Setup Raspberry Pi with Header (Zero W is what is used for this tutorial)
Sound Detection Module LM393
Short Wires
Breadboard
A decibel meter app such as dB Meter
Phillips Head Screwdriver

Introduction

In this project, the developer will reuse the Raspberry Pi setup from the first post and create an Android app similar to the second post 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 first post.

The purpose of the project is to use a sound detection sensor connected to a Raspberry Pi to record a timestamp when the sound level of the environment exceeds a preset decibel limit. The project could be used in an environment where noise is a persistent problem to prevent hearing damage or to know when a noise ordinance violation is being committed.

Setting Up and Connecting the Sensor to the Raspberry Pi

The sound detection module (LM393) will be connected to the Pi using three pins. These three pins are VCC, GND, and OUT. The LM393 will have these pins on its printed circuit board. Connect a red wire to VCC (Power). Connect a black wire to GND (Ground). Connect a yellow wire to OUT (Data). Here is a picture of the wires connected to the LM393 sensor:

Each of the three wires will now need to be connected to pins on the Raspberry Pi. A diagram of the Raspberry Pi pinout can be found here: https://pi4j.com/1.2/pins/model-zerow-rev1.html

The red power wire will be connected to Pin# 17 on the Pi. The black ground wire will be connected to Pin# 25 on the Pi. The yellow data wire will be connected to Pin# 15 on the Pi. Below is a picture of the wires connected between the LM393 sensor and the Pi:

Setting Up the Python Script on the Raspberry Pi

Once the hardware is set up, the next step is to add the Python script file to the Raspberry Pi. Use your favorite text editor to add the following Python code to your Raspberry Pi. Name the file “DecibelLogger.py”.

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

channel = 22
GPIO.setmode(GPIO.BCM)
GPIO.setup(channel, GPIO.IN)

data_amount = 10 #Amount of data points recorded in the log file
delay_time = 10 #Minimum delay time between each recorded event

def callback(channel):

        print( "Sound Detected!")

        #Get the current date and time
        now = datetime.datetime.now()
        now_string = str(now.year).zfill(4) + "-" + str(now.month).zfill(2) + "-" + str(now.day).zfill(2) + "   " + str(now.hour).zfill(2) + ":" + str(now.minute).zfill(2) + ":" + str(now.se$

        #Open or create the log file
        file =  open('decibel_log.txt','a+')

        if os.path.getsize("decibel_log.txt") == 0: #If file is new and empty
                file.write('1\n')
                file.write(now_string + '\n')

                #Fill in the rest of the file temporarily with '.'
                i = 1
                while i < data_amount:
                        file.write(".\n")
                        i += 1
        else:
                with open('decibel_log.txt','r') as file:
                        #Get the index of where the file was last updated
                        file.seek(0)
                        lines = file.readlines()
                        file_index = lines[0]
                        file_index_number = int(file_index)

                with open('decibel_log.txt','w') as file:
                        #If the last updated index was not the last line of the file
                        if file_index_number < data_amount:
                                file_index_number += 1
                                lines[0] = str(file_index_number) + "\n" #Update the last updated index
                                lines[file_index_number] = now_string + "\n" #Update the line with the current date and time
                        #If the last updated index was the last line of the file
                        else:
                                lines[0] = "1\n" #New last updated index is 1
                                lines[1] = now_string + "\n" #Update the line 1 with the current date and time
                        file.writelines(lines) #Write the updated lines to the file
        file.close() #Close the file
        time.sleep(delay_time) #Delay before next recorded event

GPIO.add_event_detect(channel, GPIO.FALLING, bouncetime=500)
GPIO.add_event_callback(channel, callback)

server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
server_sock.bind(("",bluetooth.PORT_ANY))
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:

        time.sleep(1)

        print "Waiting for connection on RFCOMM channel %d" % port
        client_sock, client_info = server_sock.accept()
        print "Accepted connection from", client_info
        print "Sock number:", client_sock


        try:
                data = client_sock.recv(255)
                if len(data) == 0: 
                        break
                print "received [%s]" % data

                #Separate message and date
                message = ""
                date = ""
                for element in range(0, len(data)):
                        if (data[element] != "*"): #Create the message string
                                message = message + data[element]
                        else: #Create the date string
                                element2 = element + 1
                                for element2 in range(element2, len(data)):
                                        date = date + data[element2]
                                break

                if message == "get_decibel_log":
                        file = open("decibel_log.txt")
                        line = file.read()
                        file.close()
                        send_data = line + "#"
                elif message == "update_date_time":
                        os.system('sudo date -s %s' % date)
                        send_data = "Update Date & Time Successful#"
                else:
                        send_data = "\nInvalid Input\n"

                client_sock.send(send_data)

        except IOError:
                pass

       except KeyboardInterrupt:
                client_sock.close()
                server_sock.close()
                break

The Python code sets up the pins on the Pi, turns the Pi into a Bluetooth server, sets up the commands to communicate with the Pi, and contains the logic to create and update the log file containing the timestamps for decibel exceed events.

Each time the LM393 sensor detects that the sound level exceeds the level it was calibrated at, the Raspberry Pi will log a timestamp in the decibel_log.txt file which is contained in the same folder as the DecibelLogger.py file.

The Pi will have the ability to receive two different messages over BLE. One is the “get_decibel_log” message which will cause the Pi to send the decibel_log.txt file to the Android device. The second message the Pi can receive is the “update_date_time” message which will cause the Pi to update its internal clock to the date and time it received from the Android device. This is a useful feature for the Pi to sync its internal clock if the Pi isn’t connected to another computer over the USB connector. The capability will ensure that the Pi is recording accurate timestamps.

Next, exit out of the text editor and run the Python script by entering:

pi@raspberrypi:~ $ python DecibelLogger.py

Tuning the Sound Detection Sensor to a Certain Decibel Level

Tuning the LM393 sensor to a certain decibel threshold can be tricky because the LM393 is sensitive to background noise. The best way to do this is to put the project setup in a quiet room to calibrate the LM393 sensor. Next you will want to download a decibel detection app on the Android device like the dB Meter app. On a computer you will want to play consistent sounds at various levels in order to calibrate your sensor to the right threshold. The best way to do this is to play a sound like the one found here: https://www.youtube.com/watch?v=3FBijeNg_Gs. You will vary your computer volume to match the decibel level that you want detected by the Raspberry Pi.

On the LM393 sensor there is a small knob with a cross shape screwdriver imprint. You will use a Phillips Head screwdriver to turn the knob clockwise or counter-clockwise to calibrate the sensor. Turning the knob counter-clockwise makes the sensor less sensitive (higher decibel threshold). Turning the knob clockwise makes the sensor more sensitive (lower decibel threshold).

Modify the DecibelLogger.py script so that sound detection events will display faster during the calibration session. Change the line delay_time = 10 to delay_time = 1 in the DecibelLogger.py script. Now run the script:

pi@raspberrypi:~ $ python DecibelLogger.py

Open the dB Meter app so that you can view the decibel level at any given moment. Play a consistent sound from the computer. Adjust the volume on the computer so that the decibel level displayed on the app is equal to the decibel threshold you want triggered by the sensor. Now turn the knob until the Pi terminal goes from adding new “Sound Detected!” messages to no longer adding new “Sound Detected!” messages. Now turn the knob back slightly until new “Sound Detected!” messages are being displayed. Stop turning the knob. The sensor is now calibrated to the decibel threshold that you want to be detected.

Modify the DecibelLogger.py script back to the original delay time. Change the line delay_time = 1 to delay_time = 10 in the DecibelLogger.py script. Run the script again.

Creating an Android App Which Will Communicate Over BLE with the Raspberry Pi to Retrieve and Display When Sound Level Limits Were Exceeded

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 two main features that will need to be triggered from the Android app: Get Decibel Log and Update Pi Date and Time. Create a button for each of these features. Add three TextViews: one to display the communication status with the Pi, one to display the column headers, and one to display the date and timestamps recorded by the Pi. Below is the XML code that should be contained in the activity_main.xml file.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical">

        <Button
            android:id="@+id/get_decibel_log"
            android:layout_width="wrap_content"
            android:layout_height="60dp"
            android:layout_marginTop="15dp"
            android:layout_marginLeft="15dp"
            android:onClick="onClick"
            android:text="Get Decibel Log" />

        <Button
            android:id="@+id/update_date_time"
            android:layout_width="wrap_content"
            android:layout_height="60dp"
            android:layout_marginTop="15dp"
            android:layout_marginLeft="15dp"
            android:onClick="onClick"
            android:text="Update Pi Date and Time"
            android:layout_below="@id/get_decibel_log"/>

        <TextView
            android:id="@+id/status"
            android:layout_width="wrap_content"
            android:layout_height="60dp"
            android:layout_marginTop="0dp"
            android:layout_marginLeft="20dp"
            android:gravity="center"
            android:text=""
            android:maxLines = "1"
            android:textSize="15sp"
            android:textStyle="bold"
            android:layout_below="@id/update_date_time"/>

        <TextView
            android:id="@+id/tableHeader"
            android:layout_width="wrap_content"
            android:layout_height="20dp"
            android:layout_marginTop="0dp"
            android:layout_marginLeft="20dp"
            android:gravity="bottom"
            android:text="         Date           Time     "
            android:maxLines = "1"
            android:textSize="15sp"
            android:textStyle="bold"
            android:layout_below="@+id/status"/>

        <TextView
            android:id="@+id/table"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            android:layout_marginLeft="20dp"
            android:gravity="top"
            android:text="No Data"
            android:textSize="15sp"
            android:layout_below="@+id/tableHeader"/>

</RelativeLayout>

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.decibelexceedlog;

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;
import android.graphics.Paint;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MainActivity extends Activity {

    BluetoothSocket socket;
    BluetoothDevice bt_device = null;

    final byte delimiter = 35;
    int readBufferPosition = 0;
    String data = "";
    String[] dataRows;
    String final_data = "";

    private final static int REQUEST_ENABLE_BT = 1;

    private BluetoothAdapter bluetoothAdapter;

    private Button getDecibelLog;
    private Button updateDateTime;
    private TextView status;
    private TextView tableHeader;
    private TextView table;

    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("Decibel Exceed Log");

        setContentView(R.layout.activity_main);

        getDecibelLog = (Button) findViewById(R.id.get_decibel_log);
        updateDateTime = (Button) findViewById(R.id.update_date_time);
        status = (TextView) findViewById(R.id.status);
        tableHeader = (TextView) findViewById(R.id.tableHeader);
        table = (TextView) findViewById(R.id.table);

        tableHeader.setPaintFlags(tableHeader.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);

        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 = 0;
                    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);
                                    data = new String(encodedBytes, "US-ASCII");

                                    String[] copy = data.split(System.getProperty("line.separator"));

                                    //Clear extraneous characters from front of sequence
                                    String firstLine = "";
                                    for (int h = 0; h < copy[0].length(); h++)
                                    {
                                        int c = copy[0].charAt(h);
                                        if (c > 0x1F && c < 0x7F) {
                                            firstLine = firstLine + copy[0].charAt(h);
                                        }
                                    }
                                    copy[0] = firstLine;

                                    if (copy[0].equals("Update Date & Time Successful"))
                                    {
                                        handler.post(new Runnable() {
                                            public void run() {
                                                status.setText("Date & Time Update Successful!");
                                            }
                                        });
                                    }
                                    else {
                                        //Retrieve first element, remove first element and reorder from most recent to least recent
                                        int l = copy.length;
                                        int pointer = Integer.valueOf(copy[0]);
                                        dataRows = new String[l - 1];

                                        int k = 0;  //Copy array pointer
                                        for (int j = pointer; j > 0; j--) {
                                            dataRows[k] = copy[j];
                                            k++;
                                        }

                                        for (int j = l - 1; j > pointer; j--) {
                                            dataRows[k] = copy[j];
                                            k++;
                                        }

                                        final_data = "";

                                        for (int m = 0; m < dataRows.length; m++) {
                                            final_data = final_data + dataRows[m] + "\n";
                                        }

                                        readBufferPosition = 0;

                                        handler.post(new Runnable() {
                                            public void run() {
                                                status.setText("Data Collection Successful!");
                                                table.setText(final_data);
                                            }
                                        });
                                    }

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

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

                        }
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        status.setText("Data Collection Problem!");
                        e.printStackTrace();
                    }

                }
            }
        }

        //Get Decibel Log Listener
        getDecibelLog.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                Log.e("Button pressed ", "Get Data");
                (new Thread(new workerThread("get_decibel_log"))).start();

            }
        });

        //Get Decibel Log Listener
        updateDateTime.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {

                SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
                Date now = new Date(); //Get current date and time
                String strDate = date.format(now);  //Turn into string
                Log.e("Button pressed ", "Update Date Time");
                (new Thread(new workerThread("update_date_time"+"*"+strDate))).start();  //Add date and time string to command

            }
        });

    }
}

The 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. If the Get Decibel Log button is pressed, the app will display the log of timestamps collected from the Pi. Run the app through the debugger to make sure it builds.

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 Get Decibel Log button in the app and a log of timestamps in descending order that were collected by the Pi will be displayed in the app. A status will be returned to the app from the Pi to indicate that the data transmission was successful. Pressing the Update Pi Date and Time button will update the Pi date and time with the date and time from the Android app. A status will be returned to the app from the Pi to indicate that the date and time on the Pi was updated successfully. You have now created a way to communicate the Pi’s log and update the Pi’s date and time using BLE from an Android device!

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!

Using BlueTerm to Communicate Between an Android Device and Raspberry Pi Over BLE

Ingredients

Android Device
Raspberry Pi with header (Zero W is what is used for this tutorial)
MicroSD card to store Raspbian OS
Short wires
Resistors (one 220 Ohm and one 4.7k Ohm)
Breadboard
LED
Temperature sensor (DS18B20)

Raspberry Pi Setup

For setting up the Raspberry Pi headless over Wifi follow the directions here:

https://desertbot.io/blog/setup-pi-zero-w-headless-wifi

For setting up the Raspberry Pi over USB follow the directions here:

https://desertbot.io/blog/ssh-into-pi-zero-over-usb

For setting up Bluetooth on the Raspberry Pi follow the directions here:

https://pimylifeup.com/raspberry-pi-bluetooth/

Pairing the Android Device with the Raspberry Pi

First you will need to put your Android device in Bluetooth pairing mode.
Next on the Raspberry Pi type in the following commands in bold:

pi@raspberrypi:~ $ sudo bluetoothctl
[bluetooth]# agent on
[bluetooth]# default-agent
[bluetooth]# scan on
[bluetooth]# scan off

Next find the Bluetooth address of your Android device in the scan results. The Bluetooth address will look something like XX:XX:XX:XX:XX:XX and will be displayed next to your Android device name in the scan results. Type in the following command on your Pi where the X’s are your Bluetooth address.

[bluetooth]# pair XX:XX:XX:XX:XX:XX
[bluetooth]# paired-devices

The paired-devices command should display your Android device if successfully paired. Next exit out of Bluetooth device configurations.

[bluetooth]# exit

If you weren’t able to follow along, this video is a useful demonstration of pairing the Raspberry Pi with another device:

https://www.youtube.com/watch?v=sEmjcgbmoRM

Setting Up and Connecting the Hardware to the Raspberry Pi

For this tutorial you will be connecting the Pi to a LED and a temperature sensor. You will be able to turn a LED on or off or get the temperature of the room using an Android app called BlueTerm.

The first step is to connect the LED, temperature sensor, resistors, and wires to the breadboard.

The 220 Ohm resistor needs to connect to the long end (+) of the LED. The short end (-) of the LED will be connected to a black wire. The other side of the resistor will be connected to a red wire.

The three pins of the temperature sensor (DS18B20) need to be connected to the breadboard. With the rounded side facing you, a 4.7k Ohm resistor will need to connect the left most pin and middle pin. The left most pin is power and so a red wire should be connected to it. The middle pin is data and so a yellow wire will connect to it. The right most pin is ground and so a black wire will connect to it.

Here is a picture of everything connected together:

Once the breadboard is connected together, the wires need to be connected to the correct pins on the Raspberry Pi. The red wire connected to the 220 Ohm resistor needs to be connected to Pin# 33 on the Pi. The black wire connected to the LED needs to be connected to Pin# 34 on the Pi. The red wire connected to power on the temperature sensor needs to be connected to Pin# 4 on the Pi. The yellow wire connected to data on the temperature sensor needs to be connected to Pin# 7 on the Pi. The black wire connected to ground on the temperature sensor needs to be connected to Pin# 6 on the Pi. Below is a picture of the wires connected to the Pi:

A diagram of the Raspberry Pi pin numbers can be found here:

https://pi4j.com/1.2/pins/model-zerow-rev1.html

Setting Up and Running the Python Script on the RPi

Once the hardware is set up, the next step is to add the Python script file to the Raspberry Pi. Use your favorite text editor to add the following Python code to your Raspberry Pi. Name the file “bluetooth_demo.py”.

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 + ’28*’)
device_file = device_folder[0] + ‘/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 = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
print(‘Bluetooth Socket Created’)

try:
	server.bind((host, port))
	print(“Bluetooth Binding Completed”)
except:
	print(“Bluetooth Binding Failed”)

server.listen(1)

client, address = server.accept()

print(“Connected To”, address)
print(“Client:”, client)

try:
	while True:
		client.send(“Input 0 = OFF, 1 = ON, 2 = TEMP:”)

		data = client.recv(1024)
		print(data)

		if data == “0”:
			GPIO.output(led_pin, GPIO.LOW)
			send_data = “\nLight Off\n”
		elif data == “1”:
			GPIO.output(led_pin, GPIO.HIGH)
			send_data = “\nLight On\n”
		elif data == “2”:
			send_data = “\nTemp (C): “ + read_temp_c() + “\nTemp (F): “ + read_temp_f() + “\n”
		else:
			send_data = “\nInvalid Input\n”

		client.send(send_data)
except:
	client.close()
	server.close()
finally:
	GPIO.cleanup()

The Python code sets up the pins on the Pi, turns the Pi into a Bluetooth server, and sets up the commands to communicate with the Pi.

A command of “0” will turn the LED off.
A command of “1” will turn the LED on.
A command of “2” will get the temperature of the room in Celsius and Fahrenheit.


Next, exit out of the text editor and run the Python script by entering:

pi@raspberrypi:~ $ python bluetooth_demo.py

Final Step: Download BlueTerm on the Android Device, Connect to the Raspberry Pi, and Run Commands

On your Android device, download the app BlueTerm from the Google Play store located here:

https://play.google.com/store/apps/details?id=es.pymasde.blueterm&hl=en_US

Next, connect your Android device to the Raspberry Pi by clicking on the Connect Device button and selecting the Raspberry Pi from the Paired Devices list.

Once the Android device is connected to the Pi, you may start to send commands (0, 1, or 2) through BlueTerm to the Pi to turn the LED on/off or get the temperature of the room in Celsius and Fahrenheit.