Overview

Skill Level: Any Skill Level

Step-by-step

  1. Prerequisites

    Android side :

    • Install Android Studio : https://developer.android.com/sdk/index.html
    • An Android mobile
    • An android Watch

    IBM Bluemix side :

    • An IBM Bluemix account : https://console.ng.bluemix.net/
  2. Create an new Android Wear Project

    First, create a new Android Project (File->New->New Project)

    In the wizard, type HeartRate as application name and select your project location.

    Click Next .

    Select Phone and Tablet and Wear and choose the minimun SDK depending on your devices.

    Click Next .

    Select Blank Activity for the mobile application.

    Click Next

    Type HeartRateMobileActivity in Activity Name field.

    Click Next

    Select Blank Wear Activity for the wear application.

    Click Next

    Type HeartRateWearActivity in Activity Name field.

    Click Finish

  3. Develop the basic wearable application

    Permission

    Make sure the mobile and wear manifest files have the BODY_SENSOR permission :

     <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.ibm.hcs.heartrate" >
    <uses-permission android:name="android.permission.BODY_SENSORS" />

    Update the wearable activity

    • Add a label in the wear string.xml files :
     <string name="heartRateText">Heart Rate : N/A</string>

    • Open the wear layout round_activity_heart_rate_wear.xml then change the id field with heartRateTextView, and the text field with @string/heartRateText.
    • Open HeartRateWearActivity file and change onCreate function
     @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_heart_rate_wear);
    final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
    stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
    @Override
    public void onLayoutInflated(WatchViewStub stub) {
    mTextView = (TextView) stub.findViewById(R.id.heartRateTextView);
    }
    });
    }

    Create a new service

    • Create a service named HeartRateWearService
    • Verify the manifest file
     <service android:name=".HeartRateWearService">

     

    Paste code above and delete me

    • Replace the generated file with the following code
     public class HeartRateWearService extends Service implements SensorEventListener{
    private SensorManager sensorManager;
    private Sensor heartRateSensor;
    private ScheduledExecutorService heartRateScheduler;
    public HeartRateWearService() {
    }

    @Override
    public void onCreate() {
    super.onCreate();
    getHeartRateValues();
    }

    private void getHeartRateValues() {
    sensorManager = ((SensorManager) getSystemService(SENSOR_SERVICE));
    heartRateSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE);
    if (heartRateSensor != null) {
    heartRateScheduler = Executors.newScheduledThreadPool(1);
    heartRateScheduler.scheduleAtFixedRate(
    new Runnable() {
    @Override
    public void run() {
    sensorManager.registerListener(HeartRateWearService.this, heartRateSensor, SensorManager.SENSOR_DELAY_NORMAL);
    try {
    Thread.sleep(10000);
    } catch (InterruptedException e) {
    }
    sensorManager.unregisterListener(HeartRateWearService.this,heartRateSensor);
    }
    }, 3, 15, TimeUnit.SECONDS);
    }
    }

    @Override
    public IBinder onBind(Intent intent) {
    return null;
    }

    @Override
    public void onDestroy() {
    if (sensorManager != null)
    sensorManager.unregisterListener(this);
    heartRateScheduler.shutdown();

    super.onDestroy();
    }

    @Override
    public void onSensorChanged(SensorEvent event) {
    // sends an Intent to the Activity
    Intent intent = new Intent();
    intent.setAction("heartRateAction");
    intent.putExtra("HeartRate", event.values[0]);
    sendBroadcast(intent);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    Show the heart rate in the activity

    • Open HeartRateWearActivity file
    • Add this attribute
     private HeartRateBroadcastReceiver heartRateBroadcastReceiver;

    • Add this inner class
     private class HeartRateBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context arg0, Intent arg1) {
    // ahr
    Log.v(this.getClass().getName(), "Value Recieved");
    if (arg1.getAction().equals("heartRateAction")) {
    float hr = arg1.getFloatExtra("HeartRate", 0);
    if (HeartRateWearActivity.this.mTextView != null) {
    HeartRateWearActivity.this.mTextView.setText("Heart Rate : " + hr);
    }
    }
    }
    }

    • Add the following methods
     @Override
    protected void onStart() {
    // initialize the broadcast recieiver
    heartRateBroadcastReceiver = new HeartRateBroadcastReceiver();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("heartRateAction");
    registerReceiver(heartRateBroadcastReceiver, intentFilter);

    // start HeartRateWearService
    startService(new Intent(this, HeartRateWearService.class));
    super.onStart();
    }

    @Override
    protected void onStop() {
    unregisterReceiver(heartRateBroadcastReceiver);
    stopService(new Intent(this, HeartRateWearService.class));
    super.onStop();
    }

  4. Send the heart rate to the mobile application

    Update the wear application to send the heart rate

    • Open HeartRateWearService
    • Add the attributes
    private GoogleApiClient googleApiClient;
    private ExecutorService executorService;

    • Initialize executorService in onCreate function
     @Override
    public void onCreate() {


    executorService = Executors.newCachedThreadPool();
    }

    • Add the following functions
      private boolean isConnected() {
    if (googleApiClient == null)
    googleApiClient = new GoogleApiClient.Builder(this.getApplication().getApplicationContext()).addApi(Wearable.API).build();

    if (googleApiClient.isConnected()) {
    return true;
    }

    ConnectionResult result = googleApiClient.blockingConnect(15000, TimeUnit.MILLISECONDS);
    return result.isSuccess();
    }

    private void sendToMobile(final SensorEvent event) {
    executorService.submit(new Runnable() {
    @Override
    public void run() {

    PutDataMapRequest dataMap = PutDataMapRequest.create("/sensor/heartRate");
    dataMap.getDataMap().putLong("timestamp", event.timestamp);
    dataMap.getDataMap().putFloat("value", event.values[0]);
    PutDataRequest putDataRequest = dataMap.asPutDataRequest();
    if (isConnected()) {
    Wearable.DataApi.putDataItem(googleApiClient, putDataRequest).setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
    @Override
    public void onResult(DataApi.DataItemResult dataItemResult) {
    Log.v(this.getClass().getName(), "Sending heartRate: " + dataItemResult.getStatus().isSuccess());
    }
    });
    }
    }
    });
    }

    • Add this instruction in onSensorChanged function
    @Override
    public void onSensorChanged(SensorEvent event) {


    sendToMobile(event);
    }

    Update the mobile activity

    • Add a label in the mobile string.xml files
     <string name="heartRateText">Heart Rate : N/A</string>

    • Open the mobile layout activity_heart_rate_mobile.xml then change the id field with heartRateTextView, and the text field with @string/heartRateText.

    Create an new mobile service

    • Create a new service HeartRateMobileWearableListenerService in the mobile module
    • Update the mobile manifest
     <service android:name=".HeartRateMobileWearableListenerService" >
    <intent-filter>
    <action android:name="com.google.android.gms.wearable.BIND_LISTENER"/>
    </intent-filter>
    </service>

    • Change HeartRateMobileWearableListenerService code
    public class HeartRateMobileWearableListenerService extends WearableListenerService {
    @Override
    public void onDataChanged(DataEventBuffer dataEvents) {
    Log.d(this.getClass().getName(), "onDataChanged()");
    for (DataEvent dataEvent : dataEvents) {
    if (dataEvent.getType() == DataEvent.TYPE_CHANGED) {
    DataItem dataItem = dataEvent.getDataItem();
    Uri uri = dataItem.getUri();
    String path = uri.getPath();
    if (path.equals("/sensor/heartRate")) {
    DataMap map = DataMapItem.fromDataItem(dataItem).getDataMap();
    long timestamp = map.getLong("timestamp");
    float value = map.getFloat("value");
    Intent intent = new Intent();
    intent.setAction("heartRateAction");
    intent.putExtra("HeartRate", value);
    sendBroadcast(intent);
    }
    }
    }
    }
    }

    Show the heart rate in the mobile activity

    • Open HeartRateMobileActivity
    • Add this attribute
     private HeartRateBroadcastReceiver heartRateBroadcastReceiver;

    • Add this inner class
     private class HeartRateBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context arg0, Intent arg1) {
    // ahr
    Log.v(this.getClass().getName(), "Value Recieved");
    if (arg1.getAction().equals("heartRateAction")) {
    float hr = arg1.getFloatExtra("HeartRate", 0);
    ((TextView)HeartRateMobileActivity.this.findViewById(R.id.heartRateTextView)).setText("Heart Rate : " + hr);
    }
    }
    }

    • Add onStart function
     @Override
    protected void onStart() {
    super.onStart();
    // ahr
    heartRateBroadcastReceiver = new HeartRateBroadcastReceiver();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("heartRateAction");
    registerReceiver(heartRateBroadcastReceiver, intentFilter);
    }

  5. Publish the heart rate to IoT Fundation

    Create a device in the IoT Fundation service

    • Connect to your IBM Bluemix account
    • In the Catalog tab, select Internet of Things Fundation Starter
    • Enter HeartRate in the name field and click Create button

    • In the Catalog tab, select Internet of Things
    • Click Create button
    • Launch this Internet of Things dashboard
    • Select the Devices tab, then Add Device
    • Type Wear in Device Type field and myWatch in Device ID field, then Continue

    • Save the device credentials (Organization ID, Device type and ID and Authentication Token)

    Import mqtt libraries in your mobile module

    • Copy in HeartRatemobilelibs org.eclipse.paho.android.service.jar and org.eclipse.paho.client.mqttv3.jar file
    • Close and reopen the project

    Update the mobile manifest

    • Add mqtt service
     <service android:name="org.eclipse.paho.android.service.MqttService" />

    Paste code above and delete me

    • Add WAKE_LOCK permission
     <uses-permission android:name="android.permission.WAKE_LOCK" />

    Paste code above and delete me

    Create MQTTHandler

    • Create new MqttHandler class
    • Copy the following code and change the organization and device token
     public class MqttHandler implements MqttCallback {

    private static MqttHandler instance;
    private MqttAndroidClient mqttClient;
    Context context;

    private static String ORG = "YOUR_IOT_ORGANISATION";
    private static String DEVICE_TYPE = "Wear";
    private static String DEVICE_ID = "myWatch";
    private static String TOKEN = "YOUR_DEVICE_TOKEN";
    private static String TOPIC = "iot-2/evt/hr/fmt/json";

    private MqttHandler(Context context) {
    this.context = context;
    }


    public static MqttHandler getInstance(Context context) {
    if (instance == null) {
    instance = new MqttHandler(context);
    }
    return instance;
    }


    @Override
    public void connectionLost(Throwable throwable) {
    }

    @Override
    public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
    }

    public void connect(IMqttActionListener listener) {
    if (!isConnected()) {
    String iotPort = "1883";
    String iotHost = ORG+".messaging.internetofthings.ibmcloud.com";
    String iotClientId = "d:"+ORG+":"+DEVICE_TYPE+":"+DEVICE_ID;

    String connectionUri = "tcp://" + iotHost + ":" + iotPort;

    if (mqttClient != null) {
    mqttClient.unregisterResources();
    mqttClient = null;
    }

    mqttClient = new MqttAndroidClient(context, connectionUri, iotClientId);
    mqttClient.setCallback(this);

    MqttConnectOptions options = new MqttConnectOptions();
    options.setCleanSession(true);
    options.setUserName("use-token-auth");
    options.setPassword(TOKEN.toCharArray());

    try {
    mqttClient.connect(options, context, listener);
    } catch (MqttException e) {

    }
    }
    }

    public void disconnect(IMqttActionListener listener) {
    if (isConnected()) {
    try {
    mqttClient.disconnect(context, listener);
    mqttClient = null;
    } catch (MqttException e) {
    e.printStackTrace();
    }
    }
    }

    public void publish(long timestamp, float heartRateValue) {
    if (isConnected()) {
    String msg = "{'timestamp':"+timestamp+",'heartRate':"+heartRateValue+"}";
    MqttMessage mqttMsg = new MqttMessage(msg.getBytes());
    mqttMsg.setRetained(false);
    mqttMsg.setQos(0);
    try {
    mqttClient.publish(TOPIC, mqttMsg);
    } catch (Exception e) {

    }
    }
    }

    private boolean isConnected() {
    if (mqttClient != null) {
    return mqttClient.isConnected();
    }
    return false;
    }
    }

    Connect to Watson IoT

    • Open HeartRateMobileActivity
    • Add this attribute
     private boolean connected = false;

    • Add this code at the end of onStart function
     MqttHandler.getInstance(this).connect(new IMqttActionListener() {
    @Override
    public void onSuccess(IMqttToken iMqttToken) {
    connected = true;
    }

    @Override
    public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
    }
    });

    • Add this code at the beginning of onStop function
     MqttHandler.getInstance(this).disconnect(new IMqttActionListener() {
    @Override
    public void onSuccess(IMqttToken iMqttToken) {
    connected = false;
    }

    @Override
    public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
    }
    });

    Send heart rate to IoT Fundation

    • Update onReceive function with the underlined code
     public void onReceive(Context arg0, Intent arg1) {
    // ahr
    Log.v(this.getClass().getName(), "Value Recieved");
    if (arg1.getAction().equals("heartRateAction")) {
    float hr = arg1.getFloatExtra("HeartRate", 0);
    long ts = arg1.getLongExtra("timestamp", 0);
    ((TextView)HeartRateMobileActivity.this.findViewById(R.id.heartRateTextView)).setText("Heart Rate : " + hr);

    if (connected)
    MqttHandler.getInstance(HeartRateMobileActivity.this).publish(ts, hr);

    }
    }

  6. Create the real-time dashboard

    Create an API key

    • Open the IoT Fundation Dashboard
    • Select Access and API Key, then generate a new API Key

    • Keep the key and the authentication token in a file

    Create the Internet of Things Real-Time Insights service

    • Open the IBM Bluemix dashboard, then Catalog and select IoI Real-Time Insights

    • Click USE button

    Add a data source

    • Click the Add a data source button
    • Click Add New data source then type your IoT Fundation organization and the API Key / Anthentication Token

    • Validate
    • Select Devices, Browse Devices, then you will see your IoT device

    Create a message schema

    • Select Manage Schemas then Add new message schema
    • Type a name and link a new data source
    • Select IoT Hear Rate data source and Wear type then validate

    • Add new data points

    • Validate

    Create a rule

    • Select Analytics then Add new rule
    • Type a name and a description

    • Add a condition

    • Click to edit the condition Heart Rate greater than 120 b/m

    • Validate
    • Click to edit the action Send an email to and validate
    • Then you must activate the rule

    Create a dashboard

    • Select Dashboards, Browse Dashboards then Add new Dashboard
    • Type the dashboard name and validate

    • Select the dashboard and add the following components :

    1) A Text component

    2) A Chart component with a Heart Rate line

    3) A Device component mapped to myWatch

    4) A Filtered Devices with alerts component

    5) An Alert for device component

    • The result :

    • Now, when you launch the android wear application, you can see in the chart and the device component the real-time heart rate values. If the heart rate is greater than 120, you will receive and alert email and see it in the alert components.

     

    Paste code above and delete me

  7. Live Demonstration

1 comment on"Bluemix IoT Real-time dashboard for Android Wear application"

  1. restlessankyyy1 January 03, 2016

    Hello Sir,

    I have chosen your project for my college internship project.
    So, I might be needing guidance regarding IoT . So please help me out .
    Can I have Email ID to Contact you in near future.

Join The Discussion