In this document the steps to build an app to handle an Arduino board using the SAndroidE framework are described.
The set up is composed by the following SAndroidE compatible/described devices:
The system described allows to handle the buttons and leds attached to Arduino's GPIOs, exploiting a SAndroidE smartphone application. The logic of the application lights up the led when the button is pressed (echo application). Both the led and the button will be connected to the same Arduino, communicating with smartphone via Bluetooth communication fournished by the BLE shield.
To start you should have:
Implementation consists of three steps:
The resources available on each device shall be enumerated, giving a unique id to each one, which gives the pointer to access at the resources by the framework.
Resources' enumeration requires to have the relative xml description files within the home of our smartphone internal storage. VERY IMPORTANT: withouth these files enumeration of resources and the following steps won't be possible: the BLEEmbeddedFlasher app would find the device but will not be able to handle their resources.
xml-files-to-device-int-storage-600px.jpg
Mandatory files to include are: devices.xml, bledeviceparsers.xml and bledataclustermodels.xml. Example of these files can be found in the SandroidE zip package.
Now we can start the BLEEmbeddedFlasher app to enumerate the device resources.
addressing-resources.jpg
In order to pair the device with the smartphone, we need first to make it discoverable, and then following the instruction in the figures below, to connect with it (to acquire device information) and giving it a unique name. In our case Arduino is discoverable as soon as it is powered up.
NOTE: If the devices is supported/described as previously described the BLE services and attributes will be shown after the connection with the remote device.
In this example the device nickname is BLE Shield (it defines the description of the kind of the device), whereas the name of the specific device is set as arduino.
enumerating-arduino.jpg
The configuration procedure aims to populate the bleresources.xml with the resources, the BLEEmbeddedFlasher application automatically adds them to the file. This procedure dinamically generated file, together with previously mentioned Configuration Files, are needed by the app developed for next step. In case the file already exists (reporting the information of the required devices), because the configuration procedure was previously done, there would be no need to repeat the configuration procedure.
First of all install Android Studio, the official development environment to develop Android apps.
Copy the SAndroidE.aar file from the zip to your app's libs folder.
arduino-app-dev-2.jpg
Then add the following lines into your app's build.gradle file and click Sync now (it will appear at the top-right of the window) to include the library into your project.
#!java
allprojects {
repositories {
jcenter()
flatDir {
dirs 'libs'
}
}
}
dependencies {
compile(name:'SAndroidE', ext:'aar')
}
Your build.gradle should resemble like the one in the figure below:
arduino-app-dev-3.jpg
Now the application has access to SAndroidE library classes.
NOTE: SAndroidE is currently provided as .aar Android library file, instead of the common Java library format (.jar), to let your app automatically inherit all the permissions required by SAndroidE framework for working correctly with your devices.
The application layout is created by editing the file res/layout/activity_main.xml.
arduino-app-dev-activity-1.jpg
The simple layout shown in figure above may be obtained by switching from Design to Text tab in Android Studio IDE and entering the following XML code:
#!xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.my.sarduino.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button not pressed"
android:id="@+id/tvButtonState"
android:textColor="@android:color/holo_red_dark"
android:textSize="36sp" />
</RelativeLayout>
The application logic is implemented in the MainActivity.java file.
Both the virtual objects called by the SAndroidE library, which hadle the remote resources, and the textviews shown on the app's User Interface are declared as global variable:
#!java
TextView tvButtonState;
BLEGeneralIO arduinoButton;
BLEGeneralIO arduinoLed;
In the activity's onCreate method the SAndroidE library is initializated by the means of the BLEContext.init method. It is mandatory to insert this method before any other operations related to the SAndrodE library.
#!java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BLEContext.initBLE(this);
...
In onCreate method both SAndroidE virtual Objects and textviews are initialized:
#!java
tvButtonState=(TextView) findViewById(R.id.tvButtonState);
arduinoLed = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_5");
arduinoButton = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_2");
NOTE: the String parameters passed to the methods, which initialize the SAndrodE Objects are the 'pointer' defined in the configuration procedure. This 'pointer' can be found in the bleresources.xml file. In the current release of the library (version 0.1) this file is stored in the private memory of the 'BLEEmbeddedFlasher' application, thus in order to work correctly the library needs the application to be installed. The parameters can be checked by the 'BLEEMbeddedFlasher' app. In the next releases this limitation will be eliminated.
To handle the GPIO SAndroidE library make available the BLEOnGeneralIOEventListener interface, which is passed to the SAndroidE Object by the means of the 'setOnGeneralIOEventListener' method. When the board is inited the 'onBoardInitEnded' method is triggered, thus the status of the GPIO is defined in this callback. Other methods from the BLEGeneralIO interface are overriden but left empty, because they are useful for our application.
#!java
arduinoLed.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
@Override
public void onBoardInitEnded() {
arduinoLed.setStatus(BLEGeneralIO.GENERAL_IO_DO);
}
@Override
public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {
}
});
and in the same way the button:
#!java
arduinoButton.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
@Override
public void onBoardInitEnded() {
arduinoButton.setStatus(BLEGeneralIO.GENERAL_IO_DI);
}
@Override
public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
Log.d(TAG, "arduino button pressing: "+ bleGeneralIOEvent.values[1]);
if(bleGeneralIOEvent.values[1]==1)
{
Log.d(TAG, "arduino led: setting HIGH");
arduinoLed.setDigitalValueHigh(true);
(MainActivity.this).runOnUiThread(new Runnable() {
@Override
public void run() {
tvButtonState.setText("Button PRESSED");
tvButtonState.setTextColor(Color.BLUE);
}
}
);
} else {
Log.d(TAG, "arduino led: setting LOW");
arduinoLed.setDigitalValueHigh(false);
(MainActivity.this).runOnUiThread(new Runnable() {
@Override
public void run() {
tvButtonState.setText("Button not pressed");
tvButtonState.setTextColor(Color.RED);
}
}
);
}
}
@Override
public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {
}
});
Below the full MainActivity.java source code is reported:
#!java
package com.example.my.sarduino;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import java.util.Timer;
import java.util.TimerTask;
import eu.angel.bleembedded.lib.BLEContext;
import eu.angel.bleembedded.lib.item.generalIO.BLEGeneralIO;
import eu.angel.bleembedded.lib.item.generalIO.BLEGeneralIOEvent;
import eu.angel.bleembedded.lib.item.generalIO.BLEOnGeneralIOEventListener;
public class MainActivity extends AppCompatActivity {
protected static final String TAG = "MainActivity";
TextView tvButtonState;
BLEGeneralIO arduinoButton;
BLEGeneralIO arduinoLed;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BLEContext.initBLE(this);
tvButtonState=(TextView) findViewById(R.id.tvButtonState);
arduinoLed = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_5");
arduinoButton = (BLEGeneralIO) BLEContext.findViewById("arduino_rbs_general_io_2");
arduinoLed.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
@Override
public void onBoardInitEnded() {
arduinoLed.setStatus(BLEGeneralIO.GENERAL_IO_DO);
}
@Override
public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {
}
});
arduinoButton.setOnGeneralIOEventListener(new BLEOnGeneralIOEventListener() {
@Override
public void onBoardInitEnded() {
arduinoButton.setStatus(BLEGeneralIO.GENERAL_IO_DI);
}
@Override
public void onDigitalInputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
Log.d(TAG, "arduino button pressing: "+ bleGeneralIOEvent.values[1]);
if(bleGeneralIOEvent.values[1]==1)
{
Log.d(TAG, "arduino led: setting HIGH");
arduinoLed.setDigitalValueHigh(true);
(MainActivity.this).runOnUiThread(new Runnable() {
@Override
public void run() {
tvButtonState.setText("Button PRESSED");
tvButtonState.setTextColor(Color.BLUE);
}
}
);
} else {
Log.d(TAG, "arduino led: setting LOW");
arduinoLed.setDigitalValueHigh(false);
(MainActivity.this).runOnUiThread(new Runnable() {
@Override
public void run() {
tvButtonState.setText("Button not pressed");
tvButtonState.setTextColor(Color.RED);
}
}
);
}
}
@Override
public void onAnalogValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onDigitalOutputValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onServoValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onPWMValueChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onGeneralIOStatusChanged(BLEGeneralIOEvent bleGeneralIOEvent) {
}
@Override
public void onSetGeneralIOParameter(BLEGeneralIOEvent bleGeneralIOEvent) {
}
});
}
}
Finally run the application connecting the smartphone to the PC with the USB micro cable. Clicking Run button in Android Studio and selecting the connected smartphone the application will be deployed and run on it.
In this example, pressing/realeasing the remote button toggles the led state on/off.
arduino-run.jpg
NOTE: If devices do not connect at startup, please shutdown all Bluetooth applications already running, like the BleembeddedFlasher app or previously launched versions of our app.