BlueCArd - part 6 - Controlling the Arduino Nano Bluetooth module from Android device
Updated: Jun 26, 2020
How to connect to and control an Arduino Nano with an AT-09 / HM-10 Bluetooth Low Energy (BLE) module from an Android device.
This tutorial is part of the BlueCArd tutorials series with the ultimate to build the BlueCArd Arduino based RC car controlled from Android phone through Bluetooth.
In the last tutorial I showed you how to connect the Bluetooth module to the Arduino microcontroller and how to send data between the Arduino Nano and the BLE module.
In this tutorial we will use the board and the source code from the last tutorial. You can find the previous tutorial here: BlueCArd - part 5 - Arduino Nano Bluetooth module how to (AT-09 or HM-10)
I also made a short overview video for all the steps I did to make this work. You can watch the video here:
Reuse the board from the last tutorial: DC DC Boost Converter - what is it and why we need it
For this tutorial You will need to have an Android device with developer mode switched on. You also need to have Android studio installed and know how to build and run App on the Android device.
You can download the Android studio from here: https://developer.android.com/studio
This is the Android App that we will build in this tutorial in action:
Create the Android Studio project
Start the Android Studio and create a new android project
Choose the empty activity and click Next
Choose a name, package name and location.
For Language select Java.
IMPORTANT - Minimum SDK should be at least 18!
To be able to use bluetooth and search for other bluetooth devices we need to add some permission. To do this open the manifest file: app->manifests->AndroidManifest.xml
And add this permissions right before the "<application ..." tag:
The fine location permission is needed to be able to search for other bluetooth devices. Without this permission will be impossible to search for the bluetooth module by name.
Create the UI
Now let's create a simple UI. Open the activity_main.xml file: app->src->main->res->layout->activity_main.xml
And try to create the following UI:
The layout is not very important. What is important is to have these elements in the UI:
TextView element with id "logView"
Button with id "connectButton" and text "Connect"
Button with id "disconnectButton" and text "Disconnect"
Button with id "switchButton" and text "Switch LED"
In the TextView we will show some information. E.g. when the bluetooth device is found, connected, disconnected, etc...
With this the UI is ready. Now let's write some code!
An easy way to show information to the user
Open the main activity code app->java->"package name"->MainActivity
We will use the TextView component to show some information to the user.
Make a variable logView and init it in the onCreate() method:
and then init it in the onCreate() :
Now we need a method to easily log data to the text view. Add this method to the MainActivity class:
Executing the code in runOnUiTrhead(...) give us the possibility to call this method from other threads except the UI thread.
Now we can show the user what is happening. Let's start with the Bluetooth stuff!
Check if the Android device is ready to use Bluetooth
First, we have to check if the device can use Bluetooth. To do this we have to use the hasSystemFeature() method.
Add this method to the MainActivity class and call if in onCreate():
If Bluetooth is not supported we can't do anything else, so just toast a message to the user and finish the activity (app).
The next Thing is to check if the Bluetooth is enabled. For this add this method to the onStart(): method.
We do this in the onStart() method, because the user can disable the bluetooth at any time when the activity is paused.
Further if the Bluetooth is disabled we just ask the user to enable it.
The last thing to check is if the user has granted the fine location permission and if not to ask him to do so.
Add this method to the MainActivity() and call it from onCreate() and onStart() methods.
In this way if the user grants or declines the permission after the onCreate() call we can check it again in the onStart().
If the permission is not granted all we can do is to request it. We have no control over the dialog that is presented to the user.
With this the Bluetooth preparations are finished. Now we know that:
We have a Bluetooth capabilities
Bluetooth is enabled
And we have all the permission needed to search for BLE devices and connect to them
Now let's search for BLE devices
Finding and connecting to Bluetooth Low Energy devices
To have the code good organized I put all the Bluetooth code in a separate class. Also, later we will need to use the Bluetooth connection in another activity. The easiest way will be to make the BLE class a singleton.
Create a class named BLEController and make it singleton. The getInstance() method needs a Context (needed for the system BluetoothManager).
Now we have a BLEController singleton class with a BluetoothManager. Next step is to start the search for Bluetooth devices.
First, we need a list to save the devices we find (may be used later to choose for multiple compatible devices):
The string key here will be the device MAC address.
Next we need a BluetoothLeScanner object to scan for the available BLE devices:
Before we start scanning for BLE devices we have to take care of the communication between the BLEController class and the other parts of the App (e.g. the MainActivity). In particular there are three events that are important for us:
When a compatible Bluetooth LE device is found
When connected to a BLE device
BLEController shouldn't care who needs the events, so the easiest way is to use listeners. To keep the things simple, I created a listener with three methods for the three events.
Now we have to add functionality to the BLEController to add and remove a BLEControllerListener and also methods to fire the events:
device is the current connected device.
Now the interested classes can implement the BLEControllerListener interface and register themself for the events.
Now we can start scanning for BLE devices. First, we have to define a callback that will be called when a device is found or the scan failed:
When a device is found a callback function will be executed. Before we start scanning for BLE devices we need to define the callback function.
When a Bluetooth device is found we have to check if this is a device, we recognize. In the previous tutorial we set the device name to "BlueCArd" so now we can look for devices with this name -> device.getName().startsWith("BlueCArd")
When a compatible device is found we put it in the devices map and fire device found event.
Before we write the code to respond to this event, we need one more thing. A initialization method to start the scan:
Now let's integrate the BLEController in the MainActivity class.
First let's implement the BLEControllerListener and implement the three methods:
Create a BLEController variable:
and initialize it in the onCreate() method:
Add the MainActivity as a listener in the onResume() method and start the scan (if we have the needed permissions to search for BLE devices):
The last thing to do is to remove the listener in onPause():
Now we can test the App.
Connect the Arduino Nano circuit from the last tutorial to the computer
Build and run the App on an Android device
When the App starts on your device it should find the BLE module and show the address in the TextView.
Connect to the Bluetooth BLE module
First we have to add a connectToDevice(String address) method to the BLEController class:
First, we stop the scanner (we obviously found a suitable device already).
Then we can start the connection process. As usual the connectGatt() method expects a callback.
The callback has two methods.
onConnectionStateChange(...) is called when the connection state is changed (connected / disconnected / whatever).
When the state is connected we start the discoverServices() right away. BLE uses services and we have to find the right one (we have set up the right one in the previous tutorial)
When the state is disconnected, we just fire a disconnected event, so the listeners can show the appropriate state (e.g. show connect button again and disable remote functionality)
onServicesDiscovered(...) is called when a service is discovered (for the device we called discoverServices() on).
Here we have to find the right service that we configured in the previous tutorial. We are looking for a service with UUID that starts with "0000FFE0" and Characteristic UUID that starts with "0000FFE1".
When we find the right BluetoothGattCharacteristic we have to store it in a local variable. We will need it to send data to the Bluetooth device later.
One last thing we need is a way to disconnect from the BLE device. For this add this method:
With this the connection is established and we can fire the connected event.
Now we can use this functionality from the MainActivity.
First, we need to initialize the Connect and Disconnect buttons:
These two methods are pretty straight forward and the buttons just use the corresponding methods in the BLEController class.
Now call this methods in the onCreate() method. Also don't forget to disable the buttons in onCreate().
The last thing to do is to enable / disable the buttons in the connect and disconnect callbacks from the BLEController.
In BLEControllerConnected() disable the Connect button and enable the Disconnect button.
in BLEControllerDisconnected() enable the Connect button and disable the Disconnect button.
Warning: these methods are not called from the UI thread, so you have to use runOnUiThread(...) e.g.:
Now build and run the App. After the Bluetooth device is found the Connect button should be enabled.
When you click it the Android App should connect to the Arduino Nano BLE module and:
The Connect button should be disabled again
The Disconnect button should be enabled again
The connection LED on the BLE module should be on (no blinking)
Send data to the Arduino Nano microcontroller (Arduino Side)
To send the data we will the following command format:
byte 0: START (0x1) byte 1: Command byte 2: Num of parameters byte 2+n for n > 0: The nth parameter
This may look like an overkill for a simple led switch, but it is a good structure to send different commands. We will use it in the next tutorials to control the engine and the steering (servo motor) of the BlueCArd RC car.
First we have to modify the Arduino sketch.
Create a new file called controller.ino. In this file we will put all the parse and controller logic.
SWITCH_LED is the command for the LED control.
We connected the LED to the pin D9. In the initController() we set the D9 as an OUTPUT.
The executeCommand() function becomes a int array with the command structure we described above.
The switchLight() function sets the LED to the given value. With this we could also change the LED intensity.
The initController() function should be executed only once on start. We can call this function from the setup() function.
What is left is to read the command in the bluetooth.ino file.
First add this constant to the bluetooth file:
We also need an int array to read the command into and a variable for the current position in this array:
Add also these methods at the end of the file:
This code reads the data from the BLE module and checks if it is a command (START_COMMAND). If so, it reads the whole command and when finish sends it to the controller.
Now in the loop() function remove updateSerial() and add readCommand() instead.
With this the Arduino part is finished.
Send data to the Arduino Nano microcontroller (Android Side)
First, we have to add a method to send data to the BLE module in the BLEController class:
Now we can use this method to send data. Create a new class RemoteControl and add this code to it:
This class uses the BLEController to send data to the Arduino microcontroller.
The createControlWord() method creates a byte array command for the given command type and parameters.
For now, we can send only one command. For more convenient use I added the switchLED() method.
Now in the MainActivity class add a remoteController variable and initialize it in the onCreate() method.
Also add this method to initialize the switch LED button:
Call this method in the onCreate() after the calls for the other two buttons. Also disable the button in onCreate() and BLEControllerDisconnected() and enable it in BLEControllerConnected()
With this the LED remote control is finished.
Now upload the sketch to the Arduino Nano microcontroller and build and run the Android App.
With this the Android part of the Bluetooth setup is completed. You can find the source code for this tutorial on github here:
in the "tutorial_06_connect_BLE_Android" folder.
In the next tutorial I'll show you how to connect a DC motor to Arduino Nano microcontroller using a H-Bridge and how to control it remotely (RC) from an Android device.