Always On, Always Connected Week 9 - Our Own Accessories - Bluetooth

Android + Arduino via Bluetooth

All of these devices that we have been talking about communicate with each other via BlueTooth. Although commonly thought of as something that provides audio connectivity from to wireless headsets BlueTooth is much more.

BlueTooth devices can implement different profiles which cover anything from Hands Free Profile (HFP) typical used in cars to Dial-up Networking Profile (DUN) which is typically to provide internet access to other devices from a phone.

For a list, see: Wikipedia Bluetooth Profile http://en.wikipedia.org/wiki/Bluetooth_profile

Arduino + Bluetooth Mate

The easiest profile for us to get a handle on for phone to device communication is probably the Serial Port Profile (SPP). Arduino has good support for Serial communication and with the addition of something like a Bluetooth Mate that gives us a wide range of possibilities.

Bluetooth Mate: https://www.sparkfun.com/products/10393

To get started using something like a Bluetooth Mate, you'll first need to get it working with an Arduino.

Sparkfun has a good tutorial online here: https://www.sparkfun.com/tutorials/264

After it is wired up to the Arduino, we can try out the following sketch from the tutorial:

#include <SoftwareSerial.h>

int bluetoothTx = 2;  // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3;  // RX-I pin of bluetooth mate, Arduino D3

SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

void setup()
{
  Serial.begin(9600);  // Begin the serial monitor at 9600bps
  
  bluetooth.begin(115200);  // The Bluetooth Mate defaults to 115200bps
  bluetooth.print("$$$");  // Enter command mode
  delay(100);  // Short delay, wait for the Mate to send back CMD
  bluetooth.println("U,9600,N");  // Temporarily Change the baudrate to 9600, no parity
  // 115200 can be too fast at times for NewSoftSerial to relay the data reliably
  bluetooth.begin(9600);  // Start bluetooth serial at 9600
}

void loop()
{
  if(bluetooth.available())  // If the bluetooth sent any characters
  {
    // Send any characters the bluetooth prints to the serial monitor
    Serial.print((char)bluetooth.read());  
  }
  if(Serial.available())  // If stuff was typed in the serial monitor
  {
    // Send any characters the Serial monitor prints to the bluetooth
    bluetooth.print((char)Serial.read());
  }
  // and loop forever and ever!
}

This sketch will relay serial data from the standard serial input through bluetooth and vice versa.

One thing we can do right away is enter into command mode and see what the device will tell us. After running the sketch, open up the Serial Monitor, make sure that it is set to 9600 baud and No line ending. Type "$$$" and click Send. The Arduino should relay that to the Bluetooth Mate which should respond with CMD.

At this point you should switch to Newline and type "D". The Mate should respond with something along these lines:

***Settings***
BTA=000666421FDF
BTName=RN42-1FDF
Baudrt=115K
Parity=None
Mode  =Slav
Authen=0
Encryp=0
PinCod=1234
Bonded=0
Rem=000666049D7B

These are interesting to us. The first entry is the Bluetooth MAC address which is also on the device's label. We'll need it to make a connection once we get there.

To exit out of command mode, type "---".

The next very interesting portion is the PinCod entry which is the code that we'll need to use to pair with the device. For this device it is fixed to "1234".

Connecting to your computer via Bluetooth

First we have to pairing the Mate with our computer. On a Mac, under System Preferences there is a Bluetooth panel which you can use to pair devices. To use the Bluetooth Mate with another device, it must be paired first.

After pairing, the Mac should automatically setup a serial port which you can use with any application that supports serial. I like goSerial: http://www.furrysoft.de/?page=goserial

Here are the settings in goSerial:

After connecting, we should be able send serial data through the serial monitor on the Arduino through the Mate and see it arrive in goSerial.

Connecting to your Android

Now, istead of using goSerial and the Bluetooth on our computer, let's get it working with our Android devices.

First we have to pair it with our phone: In Settings, there is a Bluetooth section where you can turn Bluetooth on and pair your phone with it.

Following that we can test the connection by using a bluetooth serial app:

BlueTerm seems to be a good one: https://play.google.com/store/apps/details?id=es.pymasde.blueterm&feature=related_apps#?t=W251bGwsMSwyLDEwOSwiZXMucHltYXNkZS5ibHVldGVybSJd

We should now be able to do the same thing, send data back and forth from the Arduino via serial monitor to our phone and vice versa.

Now that we have that working, we can write an Android app that does something similar.

Writing an Android Bluetooth App

The Arduino folks have put together BtSerial, a nice Processing for Android bluetooth library that we can leverage.

https://github.com/arduino/BtSerial

Here is a quick example: https://github.com/vanevery/BlueToothSerialTest (note: I made some significant changes to the BtSerial library and have included it in the project on GitHub as I haven't had a chance to clean it up and send it to the Arduino folks yet.)

Don't forget permissions:

android.permission.BLUETOOTH

Android + Arduino via Bluetooth for Analog Data

Receiving sampled analog data on our phones from a sensor attached to an Arduino is illustrative of many tasks that we might want to accomplish using so let's go through a full example.

Arduino Reading Analog Sensor Values

As you probably know better than I do, the Arduino has pins dedicated to sampling analog voltages as delivered from a sensor or a potentiometer. The Arduino site has a basic tutorial for reading those values periodically and sending them serially. This is precisely what we'll need to do but instead of sending via the normal serial connection we'll send via bluetooth.

By modifying Arduino's Analog Read Serial Tutorial: http://arduino.cc/en/Tutorial/AnalogReadSerial and combining it with our Bluetooth Serial Arduino code from last week we come up with something like the following:

#include <SoftwareSerial.h>

int bluetoothTx = 2;  // TX-O pin of bluetooth mate, Arduino D2
int bluetoothRx = 3;  // RX-I pin of bluetooth mate, Arduino D3

// PIN that the sensor or potentiometer is connected to
int analogPin = A0;

// Setup the SoftwareSerial connection for our bluemate
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);

void setup()
{
  Serial.begin(9600);  // Begin the serial monitor at 9600bps - Just so we can see on the serial monitor

  bluetooth.begin(115200);  // The Bluetooth Mate defaults to 115200bps
  bluetooth.print("$$$");  // Enter command mode
  delay(100);  // Short delay, wait for the Mate to send back CMD
  bluetooth.println("U,9600,N");  // Temporarily Change the baudrate to 9600, no parity
  // 115200 can be too fast at times for NewSoftSerial to relay the data reliably
  bluetooth.begin(9600);  // Start bluetooth serial at 9600
}

void loop()
{
  if(bluetooth.available())  // If the bluetooth sent any characters
  {
    // Send any characters the bluetooth prints to the serial monitor
    // Just informational
    Serial.print((char)bluetooth.read());
  }

   // Simply read the value and print it out via println.  This will send the value as ASCII
  int analogValue = analogRead(analogPin);
  bluetooth.println(analogValue);
  // Also prints it to the serial monitor, just informational
  Serial.println(analogValue);
}

Android Reading incoming bluetooth data

This is using a modified version of the BtSerial library from the Arduino folks that is included in the GitHub repo below.

In this example there is a button with the ID of "connectButton" that we are using to do the connection to the Arduino via bluetooth.

package com.example.bluetoothanalog;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import cc.arduino.btserial.BtSerial;

public class MainActivity extends Activity implements OnClickListener {

	public static final String LOGTAG = "BlueToothAnalog";
	
	// I know the MAC address of the bluetooth address already
	public static final String BLUETOOTH_MAC_ADDRESS = "00:06:66:42:1F:DF";
	
	// The println function on the Arduino will send a newline or ASCII code 10 after each sensor reading
	public static final int DELIMITER = 10;  // Newline in ASCII

	// The modified version of the Arduino BtSerial library for Processing/Android	
	BtSerial btserial;

	// The connect button	
	Button connectButton;
		
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		// Setup the connect button
		connectButton = (Button) this.findViewById(R.id.connectButton);
		connectButton.setOnClickListener(this);
		
		// Setup BtSerial
		btserial = new BtSerial(this);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}
	
	@Override
	protected void onPause()
	{
		super.onPause();
		
		// Disconnect if our application goes to the background
		btserial.disconnect();
	}

	// btSerialEvent will be triggered whenever there is new data	
	public void btSerialEvent(BtSerial btserialObject) {
	
		// Use the "readStringUntil" function to read until we get the newline
		String serialValue = btserialObject.readStringUntil(DELIMITER);
		
		if (serialValue != null)
		{
			// Assuming it isn't null, log it
			Log.v(LOGTAG,"Data: " + serialValue);			
		}
	}

	// Handle the button click to connect
	@Override
	public void onClick(View clickedView) {
		if (clickedView == connectButton) {
			if (btserial.isConnected()) {
				Log.v(LOGTAG, "Already Connected, Disconnecting");
				btserial.disconnect();
			}
			
			btserial.connect(BLUETOOTH_MAC_ADDRESS);
			if (btserial.isConnected()) {
				Log.v(LOGTAG,"Connected");
			}
			else {
				Log.v(LOGTAG,"Not Connected");
			}
		}
	}
}

If we want to do something with that data, we have to do a bit more work. Here is the above code with the addition of sending the data to a custom view that we can draw on MyDrawingView

package com.example.bluetoothanalog;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import cc.arduino.btserial.BtSerial;

public class MainActivity extends Activity implements OnClickListener {

	public static final String LOGTAG = "BlueToothAnalog";
	public static final String BLUETOOTH_MAC_ADDRESS = "00:06:66:42:1F:DF";
	
	public static final int DELIMITER = 10;  // Newline in ASCII
	
	BtSerial btserial;
	
	// Declare the custom view
	MyDrawingView myDrawingView;
	
	Button connectButton;
		
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		connectButton = (Button) this.findViewById(R.id.connectButton);
		connectButton.setOnClickListener(this);
		
		// Setup the custom view
		myDrawingView = (MyDrawingView) this.findViewById(R.id.myDrawingView);
		
		btserial = new BtSerial(this);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
	}
	
	@Override
	protected void onPause()
	{
		super.onPause();
		btserial.disconnect();
	}

	// Handlers let us interact with threads on the UI thread
	// The handleMessage method receives messages from other threads and will act upon it on the UI thread
	Handler handler = new Handler() {
		  @Override
		  public void handleMessage(Message msg) {
		    
		    // Pull out the data that was packed into the message with the key "serialvalue"
			int messageData = msg.getData().getInt("serialvalue");
			
			// Send it over to the custom view
			myDrawingView.setYoverTime(messageData);
		  }
	};	
	
	public void btSerialEvent(BtSerial btserialObject) {
		String serialValue = btserialObject.readStringUntil(DELIMITER);
		
		if (serialValue != null)
		{
			Log.v(LOGTAG,"Data: " + serialValue);

			try {
				// The data is coming to us as an ASCII string so we have to turn it into an int
				// First we have to trim it to remove the newline
				int intSerialValue = Integer.parseInt(serialValue.trim());

				// Since btSerialEvent is happening in a separate thread, 
				// we need to use a handler to send a message in order to interact with the UI thread
				
				// First we obtain a message object
				Message msg = handler.obtainMessage();
				
				// Create a bundle to hold data
				Bundle bundle = new Bundle();
				
				// Put our value with the key "serialvalue"
				bundle.putInt("serialvalue", intSerialValue);
				
				// Set the message data to our bundle
				msg.setData(bundle);
				
				// and finally send the message via the handler
				handler.sendMessage(msg);
			
			} catch (NumberFormatException nfe) {
				// Not a number
				Log.v(LOGTAG,"" + serialValue + " is not a number");
			}
			
		}
	}

	@Override
	public void onClick(View clickedView) {
		if (clickedView == connectButton) {
			if (btserial.isConnected()) {
				Log.v(LOGTAG, "Already Connected, Disconnecting");
				btserial.disconnect();
			}
			
			btserial.connect(BLUETOOTH_MAC_ADDRESS);
			if (btserial.isConnected()) {
				Log.v(LOGTAG,"Connected");
			}
			else {
				Log.v(LOGTAG,"Not Connected");
			}
		}
	}
}

Here is a full example: https://github.com/vanevery/BlueToothAnalog (note: I made some significant changes to the BtSerial library and have included it in the project on GitHub as I haven't had a chance to clean it up and send it to the Arduino folks yet.)

Don't forget permissions:

android.permission.BLUETOOTH