Android SDK
The Android SDK can only be used to set up Gen 2 devices (P1 and Photon). It will be deprecated in the future.
The Particle Android SDK consists of two parts:
- the Cloud SDK: a wrapper for our REST API which enables your mobile app to interact with Particle-powered hardware through the Particle Device Cloud
- the Device Setup library: a library which provides an easy setup wizard for your app's users to set up their Photon/P1-powered devices
Requirements
Both the Cloud SDK and Device Setup libraries have the following requirements:
- a
minSdkVersion
of 21 (Android 5.0) or higher compileOptions
set to Java 8- The AndroidX versions of the Jetpack support libraries
Support and contributions
- If you need help, visit the Mobile category in our community forums for discussion, troubleshooting, and feedback around the Android Cloud SDK and Device Setup library.
- If you have found a bug, and can provide steps to reliably reproduce it, open an issue in the appropriate repo on GitHub, and apply the
bug
label. - If you have a feature request, open an issue on GitHub, and apply the
enhancement
label. - If you want to contribute, submit a pull request! Also be sure to check out the contribution guidelines, and sign our CLA.
Android Cloud SDK
Introduction
The Particle Android Cloud SDK enables Android apps to interact with Particle-powered connected products via the Particle Cloud. As an easy-to-use wrapper for the Particle REST API, the Cloud SDK can:
- Get a list of Particle devices claimed by a user account
- Read variables from devices
- Invoke functions on devices
- Publish events from your mobile app and subscribe to events coming from devices
- Get data usage information for cellular devices
- Claim/unclaim devices for a user account
- Manage & inject user sessions for the Particle Cloud (access tokens, encrypted session management)
The complete SDK sources are available to browse on GitHub.
For usage info, check out the examples below, or play with the sdk_example_app
module included in the git repository.
Installation
Just add implementation 'io.particle:cloudsdk:1.0.1'
to your app's build.gradle
dependencies, and then follow these instructions if you'll be distributing an app based on the SDK.
dependencies {
implementation 'io.particle:cloudsdk:1.0.1'
}
Then, from your Application class, add ParticleCloudSDK.init()
in onCreate()
:
public class MyApp extends Application {
...
@Override
public void onCreate() {
super.onCreate();
ParticleCloudSDK.init(this);
}
...
}
Overview
Cloud SDK usage mostly revolves around two main classes:
ParticleCloud
, which is the interface for all cloud operations not specific to a claimed device, such as user authentication, retrieving a user's device list, claiming devices, and moreParticleDevice
, which represents a claimed device. Each instance enables operations specific to that device, e.g.: invoking functions, reading variables, and accessing basic info like the device's name and version info.
Blocking APIs ftw
preemptive tl;dr: many of the SDK's methods make blocking network calls, meaning they can't be called from the app's main thread. The strongly recommended way of handling this requirement is to write your app in Kotlin and use coroutines to make call these SDK methods off the main thread. If you are unable to use Kotlin, the first example in the API usage section shows another way to handle this requirement.
All the SDK's methods have been very intentionally implemented as synchronous, blocking calls, including calls which use the internet, meaning they cannot be called directly on the main thread. This is because there are many easy ways to make a blocking API non-blocking (Kotlin coroutines, RxJava, Executors, AsyncTasks, etc), but going the other way around is awkward and bug-prone. The Cloud SDK's use of blocking calls makes it easy to pair it with the asynchronous programming approach of your choice.
As mentioned above, if Kotlin coroutines are not an option for you, the SDK includes an alternative in the form of the Async
and ApiWork
convenience classes. These form a simple, purpose-built wrapper around Android's AsyncTask
, with the boilerplate kept to a minimum. There's an example of using this class further below.
Finally, to make it clear which calls can be made from the UI thread, and which must be called from a background thread, the SDK APIs have been carefully annotated with @WorkerThread
and @MainThread
where applicable. Besides offering a hint to developers, this annotation also causes Android Studio to warn you if you try to make a blocking network call in the SDK from the main thread.
Common tasks
Here are some example usages for common API tasks:
SDK calls from the UI thread
Most of the methods on the ParticleCloud
and ParticleDevice
classes make blocking network calls. Since Android doesn't allow making network calls on the main/UI thread, you'll need to make these calls from a background/worker thread. As mentioned previously, Kotlin's coroutines are the best way to handle this, but the Cloud SDK provides the Async
class if Kotlin is not an option.
Here's an example of reading a variable from a device using the ParticleDevice
API with the Async
class:
// "someDevice" is a ParticleDevice instance
Async.executeAsync(someDevice, new Async.ApiWork<ParticleDevice, Integer>() {
public Integer callApi(ParticleDevice particleDevice)
throws ParticleCloudException, IOException {
return particleDevice.getVariable("myVariable");
}
@Override
public void onSuccess(Integer value) {
Toaster.s(MyActivity.this, "Room temp is " + value + " degrees.");
}
@Override
public void onFailure(ParticleCloudException e) {
Log.e("some tag", "Something went wrong making an SDK call: ", e);
Toaster.l(MyActivity.this, "Uh oh, something went wrong.");
}
});
Cloud login
Log in to the Particle Device Cloud:
ParticleCloudSDK.getCloud().logIn("ido@particle.io", "myl33tp4ssw0rd");
Toaster.s(someActivity, "Logged in!");
Injecting session access token (two-legged authentication)
If you use your own backend to authenticate users in your app, you can now easily inject the access token your backend gets from the Particle cloud using one of the new setAccessToken()
methods on ParticleCloud
. Additionally, the SDK will now automatically renew an expired session if a refresh token exists.
ParticleCloudSDK.getCloud().setAccessToken("9bb912533940e7c808b191c28cd6aaaf8d12986c");
List devices
List the devices that belong to the currently logged-in user, and find a specific device by name:
List<ParticleDevice> devices = ParticleCloudSDK.getCloud().getDevices();
for (ParticleDevice device : devices) {
if (device.getName().equals("myDevice")) {
doSomethingWithMyDevice(device);
break;
}
}
Get device instance
Get a device instance by its ID:
ParticleDevice myDevice = ParticleCloudSDK.getCloud().getDevice("53fa73265066544b16208184");
Read device information
Accessing information about a device.
// 'myDevice' here is a ParticleDevice instance
String nameString = myDevice.getName();
int productIdInt = myDevice.getProductID();
int platformIdInt = myDevice.getPlatformID();
String ipAddressString = myDevice.getIpAddress();
String lastNameString = myDevice.getLastAppName();
String statusString = myDevice.getStatus();
Date lastHeardDate = myDevice.getLastHeard();
boolean cellularBoolean = myDevice.isCellular();
String imeiString = myDevice.getImei();
String currentBuildString = myDevice.getCurrentBuild();
String defaultBuildString = myDevice.getDefaultBuild();
Read variables
Accessing variables of all the standard Particle Device Cloud types (integers, strings, doubles, and booleans):
// 'myDevice' here is a ParticleDevice instance
int anInteger = myDevice.getIntVariable("someIntValue");
String aString = myDevice.getStringVariable("someOtherStringValue");
double aDouble = myDevice.getDoubleVariable("someDoubleValue");
boolean aBoolean = myDevice.getBooleanVariable("someBooleanValue");
Call a function
Invoke a function on the device with a list of parameters. The return value from callFunction()
is result code returned from the function on the device.
// Call function "digitalwrite" with params ("D7", "1"), which will tell digitalWrite to set the value of D7 to "1"
int resultCode = someDevice.callFunction("digitalwrite", list("D7", "1"));
Toaster.s(someActivity, "Result of calling digitalwrite: " + resultCode);
List variables and functions
ParticleDevice.getFunctions()
returns a list of function names. ParticleDevice.getVariables()
returns a map of variable names to types.
for (String funcName : someDevice.getFunctions()) {
Log.i("some tag", "Device has function: " + funcName);
}
Map<String, VariableType> variables = someDevice.getVariables();
for (String name : variables.keySet()) {
Log.i("some tag", String.format("variable '%s' type is '%s'", name, variables.get(name)));
}
Rename a device
Set a new name for a claimed device:
particleDevice.setName("rocket_bubble");
Log out
Log out the user, clearing their session and access token:
ParticleCloudSDK.getCloud().logOut()
Events sub-system
Using the SDK, you open a stream for receiving Server-Sent Events (SSEs) from devices. Calling one of the subscribe...()
methods opens a connection to the Particle Device Cloud. Unlike regular HTTP calls which end as soon as the request is handled, this connection will stay open until explicitly closed. Then, when your Particle device publishes an event, your event handler will receive the event
Events can be filtered by name using the optional eventNamePrefix
param. When this prefix is specified, your event handler will only receive events with names that begin with the specified prefix. For example, specifying an event name filter of 'temp' will return events with names 'temp', 'tempo', and 'temperature'.
Subscribe to events
Subscribe to all events published by all the devices the user owns:
long subscriptionId; // save this for later, for unsubscribing
subscriptionId = ParticleCloudSDK.getCloud().subscribeToMyDevicesEvents(
null, // the first argument, "eventNamePrefix", is optional
new ParticleEventHandler() {
public void onEvent(String eventName, ParticleEvent event) {
Log.i("some tag", "Received event with payload: " + event.dataPayload);
}
public void onEventError(Exception e) {
Log.e("some tag", "Event error: ", e);
}
});
Subscribe to events from one specific device. This requires that the device be claimed to the same account that the subscription request is made from.
long subscriptionId; // save this for later, for unsubscribing
ParticleCloud cloud = ParticleCloudSDK.getCloud();
subscriptionId = cloud.subscribeToDeviceEvents(null, "53ff6c065075535119511687", someHandler);
Another option for subscribing to events from a particular device is calling same method via the ParticleDevice
instance. Using this method guarantees that private events will be received, since the API only provides access to the user's claimed devices.
long subscriptionId; // save this for later, for unsubscribing
subscriptionId = someDevice.subscribeToEvents(null, someHandler);
Unsubscribing from events
When subscribing to events, keep a reference to the subscription ID returned, and pass this as the parameter to the unsubscribe method:
// "subscriptionId" was provided earlier from the subscribe call
ParticleCloudSDK.getCloud().unsubscribeFromEventWithID(subscriptionId);
or via the ParticleDevice
instance, if applicable:
// "subscriptionId" was provided earlier from the subscribe call
someDevice.unsubscribeFromEvents(subscriptionId);
Publishing an event
You can also publish an event from your app to the Particle Device Cloud:
ParticleCloudSDK.getCloud().publishEventWithName(
"event_from_app", // the event name
"some_event_payload", // the event payload data
ParticleEventVisibility.PRIVATE // event visibility, either PRIVATE (the default), or PUBLIC
// the TTL (time to live), in seconds for this event. After this time, the event is
// considered stale/outdated
60
);
API Reference
For a complete interface reference, check out the JavaDoc and source code in the cloudsdk
module in the Git repo.
If you're working in Android Studio, you can get the JavaDoc for each method or class by putting the cursor over it and hitting F1
. (This shortcut is for Mac OS; shortcuts on other platforms may vary.)
OAuth client configuration
If you're distributing your own app, you are required to provide the cloud SDK with an OAuth client ID and secret. These are used to identify users coming from your specific app to the Particle Device Cloud. You'll need to create a new pair of these credentials for each app that you plan to release. i.e. If you plan to release two different apps, then you'll need two sets of credentials, one for each app.
These credentials will persist forever and do not need to be refreshed.
Supplying credentials to the SDK
The first way is to provide them as string resources, using the names oauth_client_id
and oauth_client_secret
, respectively, as shown here and in the example app:
<string name="oauth_client_id">(client ID string goes here)</string>
<string name="oauth_client_secret">(client secret 40-char hex string goes here)</string>
If you would prefer not to ship these OAuth strings as Android string resources, an alternative approach is provided via a separate SDK init method, ParticleCloudSDK.initWithOauthCredentialsProvider()
. For this option, you'll need to create a custom OauthBasicAuthCredentialsProvider
implementation, and pass it to the init method, as seen here:
ParticleCloudSDK.initWithOauthCredentialsProvider(someContext,
new OauthBasicAuthCredentialsProvider() {
public String getClientId() {
return (the client ID, accessed however you like)
}
public String getClientSecret() {
return (the client secret, accessed however you like)
}
});
Logging
HTTP logging can be configured by setting the http_log_level
string resource. Valid values follow the LogLevel
enum from Retrofit (1.x): NONE
, BASIC
, HEADERS
, HEADERS_AND_ARGS
, or FULL
. The default for release builds is NONE
.
For example, to set logging to BASIC
, you would add the following to your strings.xml
:
<string name="http_log_level">BASIC</string>
Android device setup library
Introduction
The Particle Device Setup library provides everything you need to offer your users a simple initial setup process for Photon/P1-powered devices. This includes all the necessary device communication code, an easily customizable UI, and a simple developer API.
The setup UI can be customized by a modifying Android XML resource files. Available customizations include: look & feel, colors, fonts, custom brand logos and more. Customization isn't required for a nice looking setup process, though: good defaults are used throughout, with styling rooted in Google's Material Design.
With the Device Setup library, you only need to make a single call from your app, and the Particle setup process UI launches to guide the user through the device setup process. When that process finishes, the user is returned to the Activity where they were left off, and a broadcast intent is sent out with the ID of the device she just set up and claimed.
Configuration for the Photon uses what we call a “soft AP” mode: during setup, the Photon advertises itself as a Wi-Fi access point ("AP"). The mobile app configures the Android device to connect to this soft AP network, and using this connection, it can provide the Particle device with the credentials it needs for the Wi-Fi network you want the to Photon to use.
Installation
Just add implementation 'io.particle:devicesetup:0.7.3'
to your app's build.gradle
dependencies, and then follow these instructions if you'll be distributing an app based on the SDK.
dependencies {
implementation 'io.particle:devicesetup:0.7.3'`
}
Basic usage
The Device Setup library has two main requirements:
- You must call
ParticleDeviceSetupLibrary.init(...)
in your Application.onCreate() or in the onCreate() of your first Activity, e.g.:
ParticleDeviceSetupLibrary.init(this.getApplicationContext(), MyMainActivity.class);
The class passed in as the second argument to init()
is used to return you to a specified activity of your app once setup has completed.
Configure device Wi-Fi credentials without claiming it
If your app requires the ability to let users configure device Wi-Fi credentials without changing its ownership you can also do that via initWithSetupOnly. Invoking setup will go thru the setup steps required for configuring device Wi-Fi credentials but not for claiming it.
ParticleDeviceSetupLibrary.initWithSetupOnly(this.getApplicationContext());
Then, to invoke the Device Setup wizard in your app, just call:
ParticleDeviceSetupLibrary.startDeviceSetup(someContext);
Advanced
You can get the device ID of the successfully set-up device after setup
completes by listening for the intent broadcast defined by
ParticleDeviceSetupLibrary.DeviceSetupCompleteContract
.
A convenience wrapper for this broadcast has been created as well,
ParticleDeviceSetupLibrary.DeviceSetupCompleteReceiver
. Just override
the required methods, then call the .register()
before starting the
device setup wizard, and call .unregister()
once it's done.
DeviceSetupCompleteReceiver receiver = new DeviceSetupCompleteReceiver() {
@Override
public void onSetupSuccess(String configuredDeviceId) {
Toaster.s(someContext, "Hooray, you set up device " + configuredDeviceId);
}
@Override
public void onSetupFailure() {
Toaster.s(someContext, "Sorry, device setup failed. (sad trombone)");
}
};
receiver.register(someContext);
ParticleDeviceSetupLibrary.startDeviceSetup(someContext);
And then when setup is complete...
receiver.unregister(someContext);
(Short version: listen for the ACTION_DEVICE_SETUP_COMPLETE
intent broadcast; the device ID will be available as a String
with key EXTRA_CONFIGURED_DEVICE_ID
)
Customization
The look and feel of the setup UI can be customized by overriding values from the customization.xml
file
under devicesetup -> src -> main -> res -> values
.
Product/brand info:
<string name="brand_name">Particle</string>
<string name="app_name">@string/brand_name</string>
<string name="device_name">Photon</string>
<drawable name="device_image">@drawable/photon_vector</drawable>
<drawable name="device_image_small">@drawable/photon_vector_small</drawable>
<drawable name="brand_image_horizontal">@drawable/particle_horizontal_blue</drawable>
<drawable name="brand_image_vertical">@drawable/particle_vertical_blue</drawable>
<drawable name="screen_background">@drawable/trianglifybackground</drawable>
<color name="brand_image_background_color">#641A1A1A</color>
Technical data:
<string name="mode_button_name">Mode button</string>
<string name="listen_mode_led_color_name">blue</string>
<string name="network_name_prefix">@string/device_name</string>
Legal/technical info:
<string name="terms_of_service_uri">https://www.particle.io/tos</string>
<string name="privacy_policy_uri">https://www.particle.io/privacy</string>
<string name="forgot_password_uri">https://www.particle.io/forgot-password</string>
<string name="troubleshooting_uri">https://community.particle.io/t/spark-core-troubleshooting-guide-spark-team/696</string>
<bool name="show_sign_up_page_fine_print">true</bool>
Look & feel:
<color name="page_background_color">#F2F2F2</color>
<color name="form_field_background_color">@android:color/white</color>
<color name="normal_text_color">@android:color/white</color>
<color name="link_text_color">@android:color/white</color>
<color name="link_text_bg">#19AAAAAA</color>
<color name="error_text_color">#FE4747</color>
<color name="element_background_color">#00BAEC</color>
<color name="element_background_color_dark">#0083A6</color>
<color name="element_text_color">@android:color/white</color>
<color name="element_text_disabled_color">#E0E0E0</color>
Product creators
If you're developing an app for your product / you're a product creator you should create a boolean resource as follows: <bool name="productMode">true</bool>
. This will enable product mode which uses different API endpoints to allow adding/setting up devices assigned to your product.
If you set productMode
to true
be sure to also provide the product_id
and product_name
- please read here for how to find your productId number.
Lastly, make sure you inject the ParticleCloud
class with scoped OAuth credentials for creating customers, so app users could create an account. Read here on how to do this.
<!-- enable product mode -->
<bool name="organization">true</bool>
<!-- product display name -->
<string name="product_name">Your Product Name Here!</string>
<!-- Product ID from Particle console -->
<integer name="product_id">12345</integer>
License
As with most Android libraries and AOSP itself, the Particle Android Cloud SDK and Device Setup library are available under the Apache License 2.0. See the LICENSE file for the complete text of the license.