Connecting to a device lets you change its settings (Minor, Major, advertising interval etc.). To edit seetings you need to be an owner of the beacon in Estimote Cloud. Every attempt to connect with device that is not linked to your Estimote Account will fail.
At first, you will need to scan for configurable devices around you:
BeaconManager beaconManager = new BeaconManager(this);
// set foreground scan periods. This one will scan for 2s and wait 2s
beaconManager.setForegroundScanPeriod(2000, 2000);
// connects beacon manager to underlying service
beaconManager.connect(new BeaconManager.ServiceReadyCallback() {
@Override
public void onServiceReady() {
// add listener for ConfigurableDevice objects
beaconManager.setConfigurableDevicesListener(new BeaconManager.ConfigurableDevicesListener() {
@Override
public void onConfigurableDevicesFound(List<ConfigurableDevice> configurableDevices) {
// handle the configurable device here. You can use it to acquire connection from DeviceConnectionProvider
}
});
beaconManager.startConfigurableDevicesDiscovery();
Once you have your ConfigurableDevice
object, you want to acquire DeviceConnection
for it. To do that, you need to be connected to DeviceConnectionProvider
.
It creates simple service that lets you handle multiple connections at once. This provider is bound to your context, so you only need to connect once during your context lifetime. Here is how to do that in your activity onCreate
method:
@Override
protected void onCreate(Bundle savedInstanceState) {
DeviceConnectionProvider connectionProvider = new DeviceConnectionProvider(this);
connectionProvider.connectToService(new DeviceConnectionProvider.ConnectionProviderCallback() {
@Override
public void onConnectedToService() {
// Handle your actions here. You are now connected to connection service.
// For example: you can create DeviceConnection object here from connectionProvider.
});
}
Remember to call connectionProvider.destroy()
method in your activity onDestroy()
:
@Override
protected void onDestroy() {
connectionProvider.destroy();
super.onDestroy();
}
When your Activity is connected to ConnectionProvider
, and you got your ConfigurableDevice
object, you can now try to establish device connection. Doing that is really easy from now on:
// Pass your ConfigurableDevice to connection provider method
DeviceConnection connection = connectionProvider.getConnection(device);
connection.connect(new DeviceConnectionCallback() {
@Override
public void onConnected() {
// Do something with your connection.
// You can for example read device settings, or make an firmware update.
Log.d("DeviceConnection", "onConnected");
}
@Override
public void onDisconnected() {
// Every time your device gets disconnected, you can handle that here.
// For example: in this state you can try reconnecting to your device.
Log.d("DeviceConnection", "onDisconnected");
}
@Override
public void onConnectionFailed(DeviceConnectionException exception) {
// Handle every connection error here.
Log.d("DeviceConnection", "onConnectionFailed");
}
});
Now you can use DeviceConnection
object to communicate with a configurable device. Remember that every time your connection fails, your DeviceConnectionCallback
needs to handle that.
Don't worry about connection state while switching application context - after first creation, your connection is always kept in the underlying service. Launching new activity and creating new DeviceConnection
object for the same ConfigurableDevice
only adds new observers to current connection.
If you only want to detach your activity callbacks from connection, just use connection.destroy()
method in your activity onDestroy()
method:
@Override
protected void onDestroy() {
super.onDestroy();
connection.destroy();
}
To completely close the underlying connection just call:
connection.close()
From now on, if any application context holds active DeviceConnectionCallback
, it will have it's onDisconnected()
called. Of course, it will only happen when you haven't called connection.destroy()
on that context. Be sure to handle that!
Unfortunately due to the differences between Bluetooth implementations on many Android devices, you may facem problems with achieving stable connection to devices. It often occurs as randomly thrown BluetoothGatt error 133
. We are trying our best to find a workaround, but the issue is linked to low-level libraries we cannot modify.
Just after your device is connected, you can perform actions to read or write data to it. Please bear in mind that all these actions are performed asynchronously. For each operation you will need to define a callback object that will handle all possible results for you.
You can access all reading methods via connection.settings
object. It holds references for many objects containing device data. Feel free to choose what you need, and then call get(SettingCallback<T> callback)
on it. Be sure to implement callback methods! Take a look at that example:
connection.settings.deviceInfo.firmware().get(new SettingCallback<Version>() {
@Override
public void onSuccess(final Version value) {
// Handle read data here.
// For example: display them in UI. This callback will be called in the same thread as connection was created (not opened).
// You can use your activity method runOnUIThread(Runnable runnable) to handle that.
Log.d("DeviceRead","Read firmware version: " + value.toString());
}
@Override public void onFailure(DeviceConnectionException exception) {
// Handle exceptions here.
Log.d("DeviceRead","Reading firmware version failed.");
}
});
Writing data to device is similar - in this case you need to call set(SettingCallback<T> callback)
instead of get.
Keep in mind that some device settings are read only!
Writing device eddystone interval example:
int advertisingInterval = 1000;
connection.settings.eddystone.tlm.advertisingInterval().set(advertisingInterval, new SettingCallback<Integer>() {
@Override
public void onSuccess(Integer value) {
// Data saved to device
Log.d("DeviceWrite","Written new Eddystone interval: " + value.toString());
}
@Override
public void onFailure(DeviceConnectionException exception) {
// Handle exceptions here.
Log.d("DeviceWrite","Write new Eddystone interval failed.");
}
});
If entered value is invalid, the DeviceConnectionException object will contain information about possible values. Once you got the idea how to read/write device setting, let's learn how to make advanced operations.
It might come in handy to update firmware or multiple settings at once - we've got you covered!
In order to make bulk settings write, you have to create SettingsEditor object. Take a look at example:
// Take your connected DeviceConnection object and get it's editor
SettingsEditor edit = connection.edit()
edit.set(connection.settings.beacon.proximityUUID(), UUID.fromString("B9407F30-F5F8-466E-AFF9-25556B57FE6D"));
edit.set(connection.settings.beacon.major(), 1000);
edit.set(connection.settings.beacon.minor(), 100);
edit.commit(new SettingCallback() {
@Override
public void onSuccess(Object value) {
// Handle success here. It will be called only when all settings have been written.
Log.d("DeviceBulkWrite","Bulk write successful");
}
@Override
public void onFailure(DeviceConnectionException exception) {
// Handle exceptions
Log.d("DeviceBulkWrite","Bulk write failed");
});
}
To check if a device i up to date - use checkForFirmwareUpdate()
method on your Connection object.
connection.checkForFirmwareUpdate(new DeviceConnection.CheckFirmwareCallback() {
@Override
public void onDeviceUpToDate(DeviceFirmware firmware) {
// If device is up to date, handle that case here. Firmware object contains info about current version.
Log.d("DeviceFirmwareUpdate","Device firmware is up to date.");
}
@Override
public void onDeviceNeedsUpdate(DeviceFirmware firmware) {
// Handle device update here. Firmware object contains info about latest version.
Log.d("DeviceFirmwareUpdate","Device needs firmware update.");
}
@Override
public void onError(DeviceConnectionException exception) {
// Handle errors here
Log.d("DeviceFirmwareUpdate","Error checking device firmware: " + exception.getMessage());
}
});
When your device needs an update, use updateFirmware(FirmwareUpdateCallback callback)
on your Connection object. Remember to implement your callback methods!
connection.updateDevice(new DeviceConnection.FirmwareUpdateCallback() {
@Override
public void onSuccess() {
// Handle success
Log.d("DeviceFirmwareUpdate","Device firmware updated.");
}
@Override
public void onProgress(float progress, String message) {
// Handle progress - range is 0.0 - 1.0
Log.d("DeviceFirmwareUpdate","Device firmware update progress: " + progress + " Message: " + message);
}
@Override
public void onFailure(DeviceConnectionException e) {
// Handle failure. Don't worry about device state - upon failure, it resets back to its old version.
Log.d("DeviceFirmwareUpdate","Device firmware update failure: " + e.getMessage());
}
});
Please keep in mind that firmware update is an asynchronous long-term process. Be sure to inform your user about it, and take care of UI reports - you can use onProgress(float progress, String message)
to get current update progress.
All nearables have their own advertisers assigned to setting tree. You can access each setting via calling connection.settings.estimote.nearable
. You can change advertised packet by switching broadcasting scheme setting:
connection.settings.estimote.nearable.broadcastingScheme().set(NearableMode.IBEACON, new SettingCallback<NearableMode>() {
@Override
public void onSuccess(NearableMode value) {
// Handle success
Log.d("BroadcastingScheme","Changed nearable broadcastung scheme. ");
}
@Override
public void onFailure(DeviceConnectionException exception) {
// Handle errors here
Log.d("Broadcasting Scheme","Error setting broadcasting scheme: " + exception.getMessage());
}
});
In addition, from Sticker firmware version 1.3 there is a possiblity to setup Eddystone URL using our SDK. You can simply achieve that by accessing proper setting:
connection.settings.estimote.nearable.eddystoneUrl().set("http://estimote.com", new SettingCallback<String>() {
@Override
public void onSuccess(String value) {
// Handle success
Log.d("Eddystone URL","Changed nearable eddystone url. ");
}
@Override
public void onFailure(DeviceConnectionException exception) {
// Handle errors here
Log.d("Eddystone URL Scheme","Error changing eddystone url: " + exception.getMessage());
}
});