Introduction

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.

Requirements

To start you should have:

  1. one Arduino UNO
  2. one BLE Shield v2.0 or later from RedBearLab
  3. a smartphone supporting Bluetooth 4.0-4.1 (aka Bluetooth Smart)
  4. a micro USB cable to deploy application to your smartphone
  5. Android Studio
  6. SAndroidE zip package: download and exctract the zip file
  7. basic programming knowledge of Android applications

Usage

Implementation consists of three steps:

  1. devices firmware flashing (if needed)
  2. enumerating the resources provided by external devices we want to interact with (only the first time)
  3. developing an Android app which exploits the SAndrodE framework to implement the desired application logic

Enumerating resources

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

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

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

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.

App development

First of all install Android Studio, the official development environment to develop Android apps.

Sandroide Library inclusion

Copy the SAndroidE.aar file from the zip to your app's libs folder.

arduino-app-dev-2.jpg

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

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.


Writing the app

App's layout

The application layout is created by editing the file res/layout/activity_main.xml.

arduino-app-dev-activity-1.jpg

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>

App's logic

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) {

		                                            }
		                                        });

		                                    }
		                                }
		                            

Let's run it

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

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.