dimanche 22 juin 2014

Estimotes and monitoring, a practical example



In the last article, we saw what an estimote is, and how it works.
It's time, my friends, to get our hands dirty.

The main goal of this article is to esplain how to monitor if we get close to an estimote beacon in an android application. We don't especialy want the main app to be launched to do this, we just want a notification to pop if we are close to a beacon. No error handling here : that's not our point.
To do this, we will create a receiver, a service, and launch the beaconManager service, provided by the estimote api when required.

The sequence will be like this :
- When bluetooth is turned on, for example when the system boots or when the user decides to turn it on, then we start a service, which will start the monitoring activity.

- When bluetooth is turned off, then we stop monitoring estimote beacons, and stop the application service.

Step 1 : Reacting on bluetooth status changes.
First, add the following permissions to your AndroidManifest.xml file :
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>
Then, in the application node, add the following :

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
    <receiver android:name=".EstimoteReceiver" >
        <intent-filter>
            <action android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
        </intent-filter>
    </receiver>
</application>
          
This will tell the Android system that we intend to launch a receiver, which class name is "EstimoteService", and which is expected to receive only system broadcasted events related to the bluethooth status changes (when bluetooth is turned on or off).

Step 2 : Create the receiver.
The code is pretty simple and self explainable :

package com.estimote.notificationstest;

import android.bluetooth.BluetoothAdapter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class EstimoteReceiver extends BroadcastReceiver {
 private Intent estimoteServiceIntent;

 // Method called when bluetooth is turned on or off.
 @Override
 public void onReceive(Context context, Intent intent) {
  final String action = intent.getAction();
  if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) {
   final int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
     BluetoothAdapter.ERROR);
   switch (state) {
   case BluetoothAdapter.STATE_TURNING_OFF:
    // When bluetooth is turning off, lets stop estimotes ranging
    if (estimoteServiceIntent != null) {
     context.stopService(estimoteServiceIntent);
     estimoteServiceIntent = null;
    }
    break;
   case BluetoothAdapter.STATE_ON:
    // When bluethooth is turned on, let's start estimotes monitoring
    if (estimoteServiceIntent == null) {
     estimoteServiceIntent = new Intent(context,
       EstimoteService.class);
     context.startService(estimoteServiceIntent);
    }
    break;
   }
  }
 }
}

Step 3 : Let's create a service.
We need to create a service, because we just can't launch the estimote monitoring from the receiver. The receiver's phylosophy is to perform quick tasks in reaction to broadcasted events. Tasks running for more than 10 seconds in a receiver are automatically killed by android itself.

package com.estimote.notificationstest;

import android.app.NotificationManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;

public class EstimoteService extends Service {
 @Override
 public IBinder onBind(Intent arg0) {
  return null;
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {
  try {
   EstimoteManager.Create((NotificationManager) this
     .getSystemService(Context.NOTIFICATION_SERVICE), this,
     intent);
  } catch (Exception e) {
  }
  return START_STICKY;
 }

 @Override
 public void onDestroy() {
  super.onDestroy();
  EstimoteManager.stop();
 }
}
Now we just need the service to be declared in our AndroidManifest.xml file :
<application />
<!-- ... -->
<service android:name=".EstimoteService" />
As you can see, we now need to go into the real thing : estimotes monitoring !

Step 4 : Let's start monitoring.

package com.estimote.notificationstest;

import java.util.List;
import java.util.concurrent.TimeUnit;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;

import com.estimote.sdk.Beacon;
import com.estimote.sdk.BeaconManager;
import com.estimote.sdk.Region;
import com.estimote.sdk.BeaconManager.MonitoringListener;

public class EstimoteManager {
 private static final int NOTIFICATION_ID = 123;
 private static BeaconManager beaconManager;
 private static NotificationManager notificationManager;
 public static final String EXTRAS_BEACON = "extrasBeacon";
 private static final String ESTIMOTE_PROXIMITY_UUID = "B9407F30-F5F8-466E-AFF9-25556B57FE6D";
 private static final Region ALL_ESTIMOTE_BEACONS = new Region("regionId",
   ESTIMOTE_PROXIMITY_UUID, null, null);

 private static Context currentContext;

 // Create everything we need to monitor the beacons
 public static void Create(NotificationManager notificationMngr,
   Context context, final Intent i) {
  try {
   notificationManager = notificationMngr;
   currentContext = context;

   // Create a beacon manager
   beaconManager = new BeaconManager(currentContext);

   // We want the beacons heartbeat to be set at one second.
   beaconManager.setBackgroundScanPeriod(TimeUnit.SECONDS.toMillis(1),
     0);

   // Method called when a beacon gets...
   beaconManager.setMonitoringListener(new MonitoringListener() {
    // ... close to us.
    @Override
    public void onEnteredRegion(Region region, List beacons) {
     postNotificationIntent("Estimote testing",
       "I have found an estimote !!!", i);
    }

    // ... far away from us.
    @Override
    public void onExitedRegion(Region region) {
     postNotificationIntent("Estimote testing",
       "I have lost my estimote !!!", i);
    }
   });
   
   // Connect to the beacon manager...
   beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
    @Override
    public void onServiceReady() {
     try {
      // ... and start the monitoring
      beaconManager.startMonitoring(ALL_ESTIMOTE_BEACONS);
     } catch (Exception e) {
     }
    }
   });
  } catch (Exception e) {
  }
 }

 // Pops a notification in the task bar
 public static void postNotificationIntent(String title, String msg, Intent i) {
  i.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
  PendingIntent pendingIntent = PendingIntent.getActivities(
    currentContext, 0, new Intent[] { i },
    PendingIntent.FLAG_UPDATE_CURRENT);
  Notification notification = new Notification.Builder(currentContext)
    .setSmallIcon(R.drawable.ic_launcher).setContentTitle(title)
    .setContentText(msg).setAutoCancel(true)
    .setContentIntent(pendingIntent).build();
  notification.defaults |= Notification.DEFAULT_SOUND;
  notification.defaults |= Notification.DEFAULT_LIGHTS;
  notificationManager.notify(NOTIFICATION_ID, notification);
 }

 // Stop beacons monitoring, and closes the service
 public static void stop() {
  try {
   beaconManager.stopMonitoring(ALL_ESTIMOTE_BEACONS);
   beaconManager.disconnect();
  } catch (Exception e) {
  }
 }
}
The required xml stuff to be added to our AndroidManifest.xml file is this :
<application>
<!-- ... -->
    <service android:name="com.estimote.sdk.service.BeaconService" android:exported="false"/>
</application>

We also need this in order to use the beacons api, but we already included it earlier :
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>

That's all we need !

Result is just this, when you get close to a beacon :


You can get your hands on the source code by following this link.


mercredi 4 juin 2014

Estimote : The future of indoor geospacing and augmented reality ?

Yesterday, my boss gave me an estimote box, containing 3 beacons. Each of these beacons acts as a bluetooth emiter, allowing a receiver to know how far the beacon is.



As far as I understood how it works, the strenght of the signal is the key to know how far the beacon is. A strong signal means that the beacon is close to the receiver (your phone for example), and of course, on the opposite side, a weak signal tels us the beacon is far away. Bluetooth signals can be altered by objects, walls, human bodies, ... but it seems that the API provided by the estimote team is able to compute the distance anyway.
To be honest, I didn't tryed the API yet : I prefer to imagine what I can do with this new toy first !

What can we do with only one beacon ?
Well, I could create somekind of a "find me" game. You can find back the beacon because the closer you are, the stronger the signal is.
You could also put it in a shop : if a customer gets close to the beacon, you can push discounted products straight to his phone. That's the example they give on their website.
Interesting... but this only gives me the ability to track one target location, which is the beacon's location.

What could we do with two beacons ?
Imagine we have a long wall full of products. On each sides of the wall, we have one beacon. The API will tell us how far we are from the yellow beacon, and how far we are from blue one. It means that we should be able to know where the receiver is.

This is good, because if we want to know if the receiver is close to the shirts in the middle, 2 beacons ensures us that the consumer is not "outiside" the room. On top of this, this allows us to track all of the positions between the two points. But this method does not tell us if the receiver is on the right side of the wall, or on the other side. If the receiver is on the other side, the distance between the yellow beacon and the phone, and the blue beacon and the receiver will remain the same...

What could we do with three beacons ?
Pretty much the same, but we will be sure, this time, that the consumer is on the right side of the wall !



In other word, with 3 beacons, we could know where the receiver is, anywhere in the room !

But imagine we want to lead our customer to the shirts within the square. We are able to know where he is, where are the shirts, but we are not able to tell him if these shirts are on his left, right, in front or behind him, because a point is a point, and a point does not have any direction...



except... is we use another sensor : the phone's gyroscope ! This could tell us the direction the phone is pointing at, giving us the missing part of our equation.

Let's go 3D
The 3 points of our triangle, created by our 3 beacons, gives us a "flat" triangle (who has ever seen a triangle which is not flat anyway ?). The position of the shirts, or even the consumer, gives us a fourth location, allowing us to create some kind of a pyramid. But the thing is that we will not be able to know if our pyramid is pointing up or down...
To give an example : Let's say the 3 beacons are on the floor. The customer holds his phone in his hand, so the phone (the receiver), is not on the floor. We know, because we have a brain, that the pyramid created by the 3 points and the phone makes a pyramid pointing up... But in fact, distances between the various beacons and the receiver would be pretty much the same if the receiver is floor below...

What could we do with four beacons ?
If we stick one more beacon on the ceilling of the room we ensure the customer is really in the right room, and not on another floor. I think we have to put this in a way our four beacons are not on the same plane, in order to create a 3D space.

Adding the sensor capabilities to our reflection, we could also tell if the targeted point (the shirts) are up or down... If we go a little bit further, we can even imagine coupling this with the phone's camera ! The idea behind this, is to point your phone to a distant target, watch the camera's picture, and see some kind of an inlaid text that says "hey, these shirts are discounted !".

Of course, this will not really work if there are walls and stuff between the consumer and the discounted shirts, but I guess we could put some knowledge about these elements in our system, right ?

On top of this, I think this would be much more performant to create indoor augmented reallity at the size of a room than using image processing, which is not processor free...

Another usage example : Imagine you are in a museum, pointing at a painting or a sculpture could give the visitor more informations about it... nice, huh ?

I'll not be able to do that as I have only 3 beacons in my hands, but I'll try to play with "2D" geospacing anyway.




What could we do with five beacons ?
The same as previous... except each beacons will not be a SPOF in our system :)