DFRobot is a Shanghai-based company that has launched many different products aimed for hardware engineers for just over six years. In this post we will show you how to write a mobile application for your Bluno – a development board that integrates Arduino Uno hardware with the CC2540 Bluetooth Smart (BLE) chip manufactured by Texas Instruments. We will demonstrate how to send and receive data between a Bluno development board and a mobile application deployed on iOS or Android.
If you want to start playing around with the code immediately you can find the complete source code on GitHub.
What you need
To run this example you need the following equipment:
- Evothings Workbench (free download)
- Any modern smartphone with Bluetooth Smart, Bluetooth 4.0.
- Evothings Client (iOS, Android), download from AppStore or Google Play
- DFRobot – Bluno hardware
- Electronic parts needed: an LED, 220 Ohm resistor and a potentiometer.
You also need an iOS device (7+) or Android device (4.3+) with support for Bluetooth Low Energy. Please note that BLE support on Android is still not fully mature and results may vary – a point to note if you experience difficulties running this example. If the application stops working, simply restart the Evothings client app and/or reset Bluetooth on the device.
This tutorial is based on a Bluno that has been updated to the latest firmware (version 1.92). DFRobot provides an excellent tutorial on how to update the firmware of the device which is available on their website.
Step 1. Building the Arduino circuit.
All the components you need to build this circuit can be found in the Arduino Starter Kit, e.g. leds, resistors, and wires – however you can also find them in most hobby electronic stores or hobby development kits.
We will create a simple circuit to demonstrate sending and receiving data over a BLE connection between the Bluno and the mobile device. A LED is used to confirm the receipt of information sent from the mobile application to the Bluno. Connect a LED in series with the 220 Ohm resistor, then connect the resistor to ground and the LED to PIN 2 on the Bluno. A potentiometer is used to obtain analog information which it to be sent from the Bluno to the mobile application, connect the ground, 5V power and the data pin to PIN A0 (analog 0).
A fritzing sketch of the circuit can be found below, it is the exact same wiring configuration we use in our Arduino BLE example.
Before we continue to the next steps; it will be useful to download the complete source code from our GitHub repository:
Step 2. Compiling and uploading the Arduino sketch.
void setup() { Serial.begin(115200); pinMode(2, OUTPUT); pinMode(A0, INPUT); }
First we need to establish a serial connection to the Bluetooth Low Energy chip, which is performed over the Serial hardware interface – the documentation states that the default baud rate is 115200. Then we configure PIN 2 as output so a signal can be sent to the LED which can turn it on or off. Finally, we configure the PIN A0 as input in order to be able to obtain an analog value from the potentiometer.
void loop() { int sensorReading = analogRead(A0); byte buffer[3] = { 0xAD, (byte)(sensorReading), (byte)(sensorReading >> 8) }; Serial.write(buffer, sizeof(buffer)); if (Serial.available()) { byte cmd = Serial.read(); if (cmd == 0x01) { digitalWrite(2, HIGH); } else if (cmd == 0x00) { digitalWrite(2, LOW); } } delay(200); }
In the loop()
function we build our application logic. Our first task is to obtain the analog value from the potentiometer and create a buffer storing the result. Since the analog input by default is a 10-bit value (0..1023
) the result must be split into two bytes – we use an 0xAD
value as a sentinel to know where our data starts. The buffer (three bytes long) is then written to the BLE serial connection using the Serial.write()
method.
If there is data available in the serial receive buffer the data is read and decoded. In this case we expect the received data to be either 0x00
(LED off) or 0x01
(LED on). In order to create more advanced communications protocol you should read all data available in the serial receive buffer, not only one byte and process it accordingly.
We introduce a 200 milliseconds delay to ensure that data is sent and received a maximum of five times per second.
Finally, build and upload the sketch to your Bluno.
Step 3. Mobile application (iOS and Android)
We use Evothings Studio to develop a mobile application for iOS and Android that can send and receive data from the Bluno sketch that was created above.
The application utilizes the easyble.js
library developed by Evothings (included with the example code on GitHub). This library implements basic functionality that is needed to establish and maintain a BLE serial connection. The latest version of the EasyBLE library can be found on GitHub. If you want to learn more about BLE we have previously posted an introduction to Bluetooth Low Energy app development.
The application mainly consists of two files, index.html
and app.js
. The index.html
file contains the user interface and the app.js
contains the business logic. It is assumed that you have basic knowledge of HTML and JavaScript.
To get started, the user must first find a Bluno device – the screenshot above depicts the first screen that is presented after starting the mobile application. The code related to the screen is defined as below.
<div id="startView"> <img class="center" style="width:100%" src="img/bluno.jpg"> <button class="red wide">Scan</button> </div>
The application uses a couple of different sections (identified with the <div>
) that are hidden and shown depending on what is happening. Each section contains all the HTML-code required to render the interface in each state. As you can see, the startView
section only has one button that, when clicked, executes the app.startScan()
method.
app.startScan = function() { app.disconnect(); console.log('Scanning started...'); app.devices = {}; var htmlString = '<img src="img/loader_small.gif" style="vertical-align:middle">' + '<p>Scanning...</p>'; $( "#scanResultView" ).append( $( htmlString ) ); $( "#scanResultView" ).show(); function onScanSuccess(device) { if (device.name != null) { app.devices[device.address] = device; console.log('Found: ' + device.name + ', ' + device.address + ', ' + device.rssi); var htmlString = '<div class="deviceContainer">' + '<p class="deviceName">' + device.name + '</p>' + '<p class="deviceAddress">' + device.address + '</p>' + '</div>'; $( "#scanResultView" ).append( $( htmlString ) ); } }; function onScanFailure(errorCode) { app.disconnect('Failed to scan for devices.'); console.log('Error ' + errorCode); }; evothings.easyble.reportDeviceOnce(true); evothings.easyble.startScan(onScanSuccess, onScanFailure); $( "#startView" ).hide(); };
The app.startScan()
method starts to scan for nearby BLE enabled devices. Once the scanning has been initiated the scanning will continue until the user tries to connect to a specific device – as a device is found, information about that device is added to the user interface as shown in the following screenshot.
Each device found is represented by an individual and clickable section (implemented using the <div>
tag). When a section is clicked the app.connectTo()
method is executed as you can see in the code below. This method initiates a connection to the selected BLE device.
var htmlString = '<div class="deviceContainer" onclick="app.connectTo(\'' + device.address + '\')">' + '<p class="deviceName">' device.name + '</p>' + '<p class="deviceAddress">' + device.address + '</p>' + '</div>'; $( "#scanResultView" ).append( $( htmlString ) );
When you try to establish a connection the application first checks whether the device provides the right BLE characteristics needed in order for the application to send and receive data. This prevents the application from connecting to devices from different manufacturers or have been built for another purpose – but makes sure we connect to a Bluno running the right Arduino sketch. If the characteristics needed is present in the device, a connection is established.
function onServiceSuccess(device) { app.connected = true; app.device = device; console.log('Connected to ' + device.name); $( "#loadingView" ).hide(); $( "#scanResultView" ).hide(); $( "#controlView" ).show(); device.enableNotification(app.DFRBLU_CHAR_RXTX_UUID, app.receivedData, function(errorcode){console.log('BLE enableNotification error: ' + errorCode);}); };
The Bluno development board uses one BLE service and a single characteristic in order to send and receive data over the serial connection. The UUIDs of this service and characteristic are outlined in the table below.
Type | UUID | Variable name in application |
Service | 0000dfb0-0000-1000-8000-00805f9b34fb | DFRBLU_SERVICE_UUID |
Characteristic | 0000dfb1-0000-1000-8000-00805f9b34fb | DFRBLU_CHAR_RXTX_UUID |
As soon as a connection is established, a subscription for the DFRBLU_CHAR_RXTX_UUID
characteristic is enabled in order to handle data received from the Bluno development board. The subscription is made by calling the device.enableNotification()
method.
The user interface is then changed to allow for interaction with the Bluno device:
This view is called the controlView
and is implemented as follows:
<div id="controlView" style="display:none"> <h1>Led</h1> <button class="green wide" onclick="app.sendData([0x01])">On</button> <button class="red wide" onclick="app.sendData([0x00])">Off</button> <h1>Analog In</h1> <button id="analogDigitalResult" class="aluminum wide">-</button> <hr> <button id="disconnectButton" class="red wide" onclick="app.disconnect()">Disconnect</button> </div>
The first two buttons are connected to app.sendData()
which is a method that takes an array of bytes and sends them to the connected device – in this case our Arduino sketch on the Bluno device. The value of 0x01
is sent to turn LED on and 0x00
is sent to turn LED off.
app.sendData = function(data) { if (app.connected) { function onMessageSendSucces() { console.log('Succeded to send message.'); } function onMessageSendFailure(errorCode) { console.log('Failed to send data with error: ' + errorCode); app.disconnect('Failed to send data'); }; data = new Uint8Array(data); app.device.writeCharacteristic(app.DFRBLU_CHAR_RXTX_UUID, data, onMessageSendSucces, onMessageSendFailure); } else { app.disconnect('Disconnected'); console.log('Error - No device connected.'); } };
The data provided as a parameter to the app.sendData()
is used to create a Uint8Array that is then used in the method app.device.writeCharacteristic()
. This method writes the data to the app.DFRBLU_CHAR_RXTX_UUID
characteristic.
A button is used to show the values the mobile application receives from the Bluno device via the potentiometer. We chose to use a button in order to simplify the user interface, nothing happens when the button is pressed – you could just as easily implement a Canvas2D and show a graph of received data like we did in our Arduino BLE example. When data is received from the device, the app.receivedData()
method is executed.
app.receivedData = function(data) { if (app.connected) { var data = new Uint8Array(data); if (data[0] === 0xAD) { console.log('Data received: [' + data[0] +', ' + data[1] +', ' + data[2] + ']'); var value = (data[2] << 8) | data[1]; console.log(value); $( '#analogDigitalResult').text(value); }; } else { app.disconnect('Disconnected'); console.log('Error - No device connected.'); } };
An Uint8Array
is created using the data received over the BLE communication channel. If the first element in the array is equal to 0xAD
(our sentinel to define where the real data starts) the second and third element is combined to create a 10-bit value containing the value from the potentiometer on the device. The value is then set as the label on the Analog In button.
Besides the code presented above the code contains some error handling which in all cases executes the app.disconnect()
method, which is outlined below:
app.disconnect = function(errorMessage) { if (errorMessage) { navigator.notification.alert(errorMessage,function alertDismissed() {}); } app.connected = false; app.device = null; // Stop any ongoing scan and close devices. evothings.easyble.stopScan(); evothings.easyble.closeConnectedDevices(); console.log('Disconnected'); $( "#scanResultView" ).hide(); $( "#scanResultView" ).empty(); $( "#controlView" ).hide(); $( "#startView" ).show(); };
The method shows an alert if it is executed with a error message as a parameter. Then the scanning is stopped and all connected devices are disconnected. All views but the start view is hidden, which is like the application was closed and restarted and allows for connection to another Bluno device.
Summary
This tutorial shows how you can build your own mobile application that connects to your Bluno using nothing but web technologies. The next step for you is to download Evothings Studio and the source code and start explore what you can build using the tools – you will be up and running within minutes. There is also several other examples available within the application.
If you have any questions, do not hesitate to post them in our forum.
Happy tinkering!