This client library describes how to use devices with the Java WIoTP client library. For help with getting started with this module, see Java Client Library - Introduction.
This section contains information on how devices can connect to the Internet of Things Platform Device Management service using Java and perform device management operations like firmware update, location update, and diagnostics update.
The device management feature enhances the IBM Watson Internet of Things Platform service with new capabilities for managing devices. Device management makes a distinction between managed and unmanaged devices:
- Managed Devices are defined as devices which have a management agent installed. The management agent sends and receives device metadata and responds to device management commands from the IBM Watson Internet of Things Platform.
- Unmanaged Devices are any devices which do not have a device management agent. All devices begin their lifecycle as unmanaged devices, and can transition to managed devices by sending a message from a device management agent to the IBM Watson Internet of Things Platform.
The device model describes the metadata and management characteristics of a device. The device database in the IBM Watson Internet of Things Platform is the master source of device information. Applications and managed devices are able to send updates to the database such as a location or the progress of a firmware update. Once these updates are received by the IBM Watson Internet of Things Platform, the device database is updated, making the information available to applications.
The device model in the WIoTP client library is represented as DeviceData and to create a DeviceData one needs to create the following objects,
- DeviceInfo (Optional)
- DeviceLocation (Optional, required only if the device wants to be notified about the location set by the application through Watson IoT Platform API)
- DeviceFirmware (Optional)
- DeviceMetadata (optional)
The following code snippet shows how to create the object DeviceInfo along with DeviceMetadata with sample data:
DeviceInfo deviceInfo = new DeviceInfo.Builder().
serialNumber("10087").
manufacturer("IBM").
model("7865").
deviceClass("A").
description("My RasPi Device").
fwVersion("1.0.0").
hwVersion("1.0").
descriptiveLocation("EGL C").
build();
/**
* Create a DeviceMetadata object
**/
JsonObject data = new JsonObject();
data.addProperty("customField", "customValue");
DeviceMetadata metadata = new DeviceMetadata(data);The following code snippet shows how to create the DeviceData object with the above created DeviceInfo and DeviceMetadata objects:
DeviceData deviceData = new DeviceData.Builder().
deviceInfo(deviceInfo).
metadata(metadata).
build();ManagedDevice - A device class that connects the device as managed device to IBM Watson Internet of Things Platform and enables the device to perform one or more Device Management operations. Also the ManagedDevice instance can be used to do normal device operations like publishing device events and listening for commands from application.
ManagedDevice exposes 2 different constructors to support different user patterns,
Constructor One
Constructs a ManagedDevice instance by accepting the DeviceData and the following properties,
- Organization-ID - Your organization ID.
- Domain - (Optional) The messaging endpoint URL. By default the value is "internetofthings.ibmcloud.com"(Watson IoT Production server)
- Device-Type - The type of your device.
- Device-ID - The ID of your device.
- Authentication-Method - Method of authentication (The only value currently supported is "token").
- Authentication-Token - API key token
- clean-session - true or false (required only if you want to connect the device in durable subscription. By default the clean-session is set to true).
- Port - Specify the port to connect to, supported ports are 8883 and 443. (default port is 8883).
- WebSocket - true or false (default is false, required if you want to connect the device using websockets).
- MaxInflightMessages - Sets the maximum number of inflight messages for the connection (default value is 100).
- Automatic-Reconnect - true or false (default: false). When set, the library will automatically attempt to reconnect to the Watson IoT Platform while the client is in disconnected state.
- Disconnected-Buffer-Size - The maximum number of messages that will be stored in memory while the client is disconnected. Default: 5000.
Note: One must set clean-session to false to connect the device in durable subscription. Refer to Subscription Buffers and Clean Session for more information about the clean session.
All these properties are required to interact with the IBM Watson Internet of Things Platform.
The following code shows how to create a ManagedDevice instance:
Properties options = new Properties();
options.setProperty("Organization-ID", "uguhsp");
options.setProperty("Device-Type", "iotsample-arduino");
options.setProperty("Device-ID", "00aabbccde03");
options.setProperty("Authentication-Method", "token");
options.setProperty("Authentication-Token", "AUTH TOKEN FOR DEVICE");
ManagedDevice managedDevice = new ManagedDevice(options, deviceData);The existing users of DeviceClient might observe that the names of these properties have changed slightly. These names have been changed to mirror the names in the IBM Watson Internet of Things Platform Dashboard, but the existing users who want to migrate from the DeviceClient to the ManagedDevice can still use the old format and construct the ManagedDevice instance as follows:
Properties options = new Properties();
options.setProperty("org", "uguhsp");
options.setProperty("type", "iotsample-arduino");
options.setProperty("id", "00aabbccde03");
options.setProperty("auth-method", "token");
options.setProperty("auth-token", "AUTH TOKEN FOR DEVICE");
ManagedDevice managedDevice = new ManagedDevice(options, deviceData);Constructor Two
Construct a ManagedDevice instance by accepting the DeviceData and the MqttClient instance. This constructor requires the DeviceData to be created with additional device attributes like Device Type and Device Id as follows:
// Code that constructs the MqttClient (either Synchronous or Asynchronous MqttClient)
.....
// Code that constructs the DeviceData
DeviceData deviceData = new DeviceData.Builder().
typeId("Device-Type").
deviceId("Device-ID").
deviceInfo(deviceInfo).
metadata(metadata).
build();
....
ManagedDevice managedDevice = new ManagedDevice(mqttClient, deviceData);Note this constructor helps the custom device users to create a ManagedDevice instance with the already created and connected MqttClient instance to take advantage of device management operations. But we recommend the users to use the library for all the device functionalities.
The device can invoke sendManageRequest() method to participate in device management activities. The manage request will initiate a connect request internally if the device is not connected to the IBM Watson Internet of Things Platform already:
managedDevice.sendManageRequest(0, true, true);As shown, this method accepts following 3 parameters,
- lifetime The length of time in seconds within which the device must send another Manage device request in order to avoid being reverted to an unmanaged device and marked as dormant. If set to 0, the managed device will not become dormant. When set, the minimum supported setting is 3600 (1 hour).
- supportFirmwareActions Tells whether the device supports firmware actions or not. The device must add a firmware handler to handle the firmware requests.
- supportDeviceActions Tells whether the device supports Device actions or not. The device must add a Device action handler to handle the reboot and factory reset requests.
Refer to the documentation for more information about the manage operation.
A device can invoke sendUnmanageRequest() method when it no longer needs to be managed. The IBM Watson Internet of Things Platform will no longer send new device management requests to this device and all device management requests from this device will be rejected other than a Manage device request.
managedDevice.sendUnmanageRequest();Refer to the documentation for more information about the Unmanage operation.
Devices that can determine their location can choose to notify the IBM Watson Internet of Things Platform about location changes. The Device can invoke one of the overloaded updateLocation() method to update the location of the device.
// update the location with latitude, longitude and elevation
int rc = managedDevice.updateLocation(30.28565, -97.73921, 10);
if(rc == 200) {
System.out.println("Location updated successfully !!");
} else {
System.err.println("Failed to update the location !!");
}Refer to the documentation for more information about the Location update.
Devices can choose to notify the IBM Watson Internet of Things Platform about changes in their error status. The Device can invoke addErrorCode() method to add the current errorcode to Watson IoT Platform.
int rc = managedDevice.addErrorCode(300);Also, the ErrorCodes can be cleared from IBM Watson Internet of Things Platform by calling the clearErrorCodes() method as follows:
int rc = managedDevice.clearErrorCodes();Devices can choose to notify the IBM Watson Internet of Things Platform about changes by adding a new log entry. Log entry includes a log messages, its timestamp and severity, as well as an optional base64-encoded binary diagnostic data. The Devices can invoke addLog() method to send log messages,
Also, the log messages can be cleared from IBM Watson Internet of Things Platform by calling the clearLogs() method as follows:
rc = managedDevice.clearLogs();The device diagnostics operations are intended to provide information on device errors, and does not provide diagnostic information relating to the devices connection to the IBM Watson Internet of Things Platform.
Refer to the documentation for more information about the Diagnostics operation.
The firmware update process is separated into two distinct actions:
- Downloading Firmware
- Updating Firmware.
The device needs to do the following activities to support Firmware Actions:
1. Construct DeviceFirmware Object (Optional)
In order to perform Firmware actions the device can optionally construct the DeviceFirmware object and add it to DeviceData as follows:
DeviceFirmware firmware = new DeviceFirmware.Builder().
version("Firmware.version").
name("Firmware.name").
url("Firmware.url").
verifier("Firmware.verifier").
state(FirmwareState.IDLE).
build();
DeviceData deviceData = new DeviceData.Builder().
deviceInfo(deviceInfo).
deviceFirmware(firmware).
metadata(metadata).
build();
ManagedDevice managedDevice = new ManagedDevice(options, deviceData);
managedDevice.connect();The DeviceFirmware object represents the current firmware of the device and will be used to report the status of the Firmware Download and Firmware Update actions to IBM Watson Internet of Things Platform. In case this DeviceFirmware object is not constructed by the device, then the library creates an empty object and reports the status to Watson IoT Platform.
2. Inform the server about the Firmware action support
The device needs to set the firmware action flag to true in order for the server to initiate the firmware request. This can be achieved by invoking the sendManageRequest() method with a true value for supportFirmwareActions parameter,
managedDevice.sendManageRequest(3600, true, false);Once the support is informed to the DM server, the server then forwards the firmware actions to the device.
3. Create the Firmware Action Handler
In order to support the Firmware action, the device needs to create a handler and add it to ManagedDevice. The handler must extend a DeviceFirmwareHandler class and implement the following methods:
public abstract void downloadFirmware(DeviceFirmware deviceFirmware);
public abstract void updateFirmware(DeviceFirmware deviceFirmware);3.1 Sample implementation of downloadFirmware
The implementation must create a separate thread and add a logic to download the firmware and report the status of the download via DeviceFirmware object. If the Firmware Download operation is successful, then the state of the firmware to be set to DOWNLOADED and UpdateStatus should be set to SUCCESS.
If an error occurs during Firmware Download the state should be set to IDLE and updateStatus should be set to one of the error status values:
- OUT_OF_MEMORY
- CONNECTION_LOST
- INVALID_URI
A sample Firmware Download implementation for a Raspberry Pi device is shown below:
public void downloadFirmware(DeviceFirmware deviceFirmware) {
boolean success = false;
URL firmwareURL = null;
URLConnection urlConnection = null;
try {
firmwareURL = new URL(deviceFirmware.getUrl());
urlConnection = firmwareURL.openConnection();
if(deviceFirmware.getName() != null) {
downloadedFirmwareName = deviceFirmware.getName();
} else {
// use the timestamp as the name
downloadedFirmwareName = "firmware_" +new Date().getTime()+".deb";
}
File file = new File(downloadedFirmwareName);
BufferedInputStream bis = new BufferedInputStream(urlConnection.getInputStream());
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file.getName()));
int data = bis.read();
if(data != -1) {
bos.write(data);
byte[] block = new byte[1024];
while (true) {
int len = bis.read(block, 0, block.length);
if(len != -1) {
bos.write(block, 0, len);
} else {
break;
}
}
bos.close();
bis.close();
success = true;
} else {
//There is no data to read, so set an error
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.INVALID_URI);
}
} catch(MalformedURLException me) {
// Invalid URL, so set the status to reflect the same,
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.INVALID_URI);
} catch (IOException e) {
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.CONNECTION_LOST);
} catch (OutOfMemoryError oom) {
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.OUT_OF_MEMORY);
}
if(success == true) {
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.SUCCESS);
deviceFirmware.setState(FirmwareState.DOWNLOADED);
} else {
deviceFirmware.setState(FirmwareState.IDLE);
}
}Device can check the integrity of the downloaded firmware image using the verifier and report the status back to IBM Watson Internet of Things Platform. The verifier can be set by the device during the startup (while creating the DeviceFirmware Object) or as part of the Download Firmware request by the application. A sample code to verify the same is below:
private boolean verifyFirmware(File file, String verifier) throws IOException {
FileInputStream fis = null;
String md5 = null;
try {
fis = new FileInputStream(file);
md5 = org.apache.commons.codec.digest.DigestUtils.md5Hex(fis);
System.out.println("Downloaded Firmware MD5 sum:: "+ md5);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
fis.close();
}
if(verifier.equals(md5)) {
System.out.println("Firmware verification successful");
return true;
}
System.out.println("Download firmware checksum verification failed.. "
+ "Expected "+verifier + " found "+md5);
return false;
}The complete code can be found in the device management sample RasPiFirmwareHandlerSample.
3.2 Sample implementation of updateFirmware
The implementation must create a separate thread and add a logic to install the downloaded firmware and report the status of the update via DeviceFirmware object. If the Firmware Update operation is successful, then the state of the firmware should to be set to IDLE and UpdateStatus should be set to SUCCESS.
If an error occurs during Firmware Update, updateStatus should be set to one of the error status values:
- OUT_OF_MEMORY
- UNSUPPORTED_IMAGE
A sample Firmware Update implementation for a Raspberry Pi device is shown below:
public void updateFirmware(DeviceFirmware deviceFirmware) {
try {
ProcessBuilder pkgInstaller = null;
Process p = null;
pkgInstaller = new ProcessBuilder("sudo", "dpkg", "-i", downloadedFirmwareName);
boolean success = false;
try {
p = pkgInstaller.start();
boolean status = waitForCompletion(p, 5);
if(status == false) {
p.destroy();
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.UNSUPPORTED_IMAGE);
return;
}
System.out.println("Firmware Update command "+status);
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.SUCCESS);
deviceFirmware.setState(FirmwareState.IDLE);
} catch (IOException e) {
e.printStackTrace();
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.UNSUPPORTED_IMAGE);
} catch (InterruptedException e) {
e.printStackTrace();
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.UNSUPPORTED_IMAGE);
}
} catch (OutOfMemoryError oom) {
deviceFirmware.setUpdateStatus(FirmwareUpdateStatus.OUT_OF_MEMORY);
}
}The complete code can be found in the device management sample RasPiFirmwareHandlerSample.
4. Add the handler to ManagedDevice
The created handler needs to be added to the ManagedDevice instance so that the WIoTP client library invokes the corresponding method when there is a Firmware action request from IBM Watson Internet of Things Platform.
DeviceFirmwareHandlerSample fwHandler = new DeviceFirmwareHandlerSample();
managedDevice.addFirmwareHandler(fwHandler);Refer to this page for more information about the Firmware action.
The IBM Watson Internet of Things Platform supports the following device actions:
- Reboot
- Factory Reset
The device needs to do the following activities to support Device Actions:
1. Inform server about the Device Actions support
In order to perform Reboot and Factory Reset, the device needs to inform the IBM Watson Internet of Things Platform about its support first. This can be achieved by invoking the sendManageRequest() method with a true value for supportDeviceActions parameter,
Once the support is informed to the DM server, the server then forwards the device action requests to the device.
2. Create the Device Action Handler
In order to support the device action, the device needs to create a handler and add it to ManagedDevice. The handler must extend a DeviceActionHandler class and provide implementation for the following methods:
public abstract void handleReboot(DeviceAction action);
public abstract void handleFactoryReset(DeviceAction action);2.1 Sample implementation of handleReboot
The implementation must create a separate thread and add a logic to reboot the device and report the status of the reboot via DeviceAction object. Upon receiving the request, the device first needs to inform the server about the support(or failure) before proceeding with the actual reboot. And if the device can not reboot the device or any other error during the reboot, the device can update the status along with an optional message. A sample reboot implementation for a Raspberry Pi device is shown below:
@Override
public void handleReboot(DeviceAction action) {
// set the support before handing over to the pool
action.setStatus(Status.ACCEPTED);
RebootTask task = new RebootTask(action, this);
executor.execute(task);
}
private static class RebootTask implements Runnable {
private DeviceAction action;
private DeviceActionHandlerSample handler;
public RebootTask(DeviceAction deviceAction, DeviceActionHandlerSample handler) {
this.action = deviceAction;
this.handler = handler;
}
@Override
public void run() {
ProcessBuilder processBuilder = null;
Process p = null;
String osname = System.getProperty("os.name");
if(osname.startsWith("Windows")) {
processBuilder = new ProcessBuilder("shutdown", "-r");
} else {
processBuilder = new ProcessBuilder("sudo", "shutdown", "-r", "now");
}
processBuilder.redirectErrorStream(true);
processBuilder.inheritIO();
boolean status = false;
try {
p = processBuilder.start();
// wait for say 2 minutes before giving it up
status = waitForCompletion(p, 2);
System.out.println("Executed restart command "+status);
} catch (IOException e) {
action.setMessage(e.getMessage());
} catch (InterruptedException e) {
action.setMessage(e.getMessage());
}
System.out.println("Executed restart command status ("+status+")");
if(status == false) {
action.setStatus(DeviceAction.Status.FAILED);
}
}
}The complete code can be found in the device management sample DeviceActionHandlerSample.
2.2 Sample implementation of handleFactoryReset
The implementation must create a separate thread and add a logic to reset the device to factory settings and report the status via DeviceAction object. Upon receiving the request, the device first needs to inform the server about the support(or failure) before proceeding with the actual reset. And if the sample can not reset the device or any other error during the reset, the device can update the status along with an optional message. The skeleton of the Factory Reset implementation is shown below:
@Override
public void handleFactoryReset(DeviceAction action) {
/*FactoryResetTask task = new FactoryResetTask(action, this);
executor.execute(task);*/
// As the sample doesn't support factory Rest, it just sends unsupported message now
action.setStatus(Status.UNSUPPORTED);
// Optionally set a message
action.setMessage("Not supported at the moment");
}
private static class FactoryResetTask implements Runnable {
private DeviceAction action;
private DeviceActionHandlerSample handler;
public FactoryResetTask(DeviceAction deviceAction, DeviceActionHandlerSample handler) {
this.action = deviceAction;
this.handler = handler;
}
@Override
public void run() {
/**
* This sample doesn't support factory reset, so respond accordingly
*/
action.setStatus(DeviceAction.Status.UNSUPPORTED);
}
}3. Add the handler to ManagedDevice
The created handler needs to be added to the ManagedDevice instance so that the WIoTP client library invokes the corresponding method when there is a device action request from IBM Watson Internet of Things Platform.
DeviceActionHandlerSample actionHandler = new DeviceActionHandlerSample();
managedDevice.addDeviceActionHandler(actionHandler);Refer to this page for more information about the Device Action.
An extension package is a JSON document which defines a set of device management actions. The actions can be initiated against one or more devices which support those actions. The actions are initiated in the same way as the default device management actions by using either the IoT Platform dashboard or the device management REST APIs.
For Device management extension package format, refer to documentation.
Device management actions defined in an extension package may only be initiated against devices which support those actions. A device specifies what types of actions it supports when it publishes a manage request to the IoT Platform. In order to allow a device to receive custom actions defined in a particular extension package, the device must specify that extension’s bundle identifier in the supports object when publishing a manage request.
Device can call manage() API with the list of bundleIds to inform the Watson IoT Platform that the device supports Device Management Extension Actions for the provided list of bundle Ids present in the manage request.
Here is the code snippet to publish a manage request to indicate Watson IoT Platform that device supports DME Actions:
dmClient.sendManageRequest(0, false, false, "example-dme-actions-v1");The last parameter specifies the custom action that the device supports.
When a custom action is initiated against a device to the Watson IoT Platform, an MQTT message will be published to the device. The message will contain any parameters that were specified as part of the request. The device must add a CustomActionHandler to receive & process the message. The messages are returned as an instance of the CustomAction class which has the following properties:
- bundleId - Unique identifier for the device management extension
- actionId - The Custom action that is initiated
- typeId - The device type against the custom action is initiated
- deviceId - The device against the custom action is initiated
- payload - The actual message containing the list of parameters in Json format
- reqId - The request Id to be used to respond to the custom action request
Below is the sample implementation of a CustomActionHandler,
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.ibm.iotf.client.CustomAction;
import com.ibm.iotf.client.CustomAction.Status;
import com.ibm.iotf.devicemgmt.CustomActionHandler;
public class MyCustomActionHandler extends CustomActionHandler implements Runnable {
// A queue to hold & process the commands for smooth handling of MQTT messages
private BlockingQueue<CustomAction> queue = new LinkedBlockingQueue<CustomAction>();
private long publishInterval = 1000; // default 1 second
@Override
public void run() {
while(true) {
CustomAction action = null;
try {
action = queue.take();
// In this example, we will change the publish interval rate based on the
// value we receive from the DME request
System.out.println(" "+action.getActionId()+ " "+action.getPayload());
JsonArray fields = action.getPayload().get("d").getAsJsonObject().get("fields").getAsJsonArray();
for(JsonElement field : fields) {
JsonObject fieldObj = field.getAsJsonObject();
if("PublishInterval".equals(fieldObj.get("field").getAsString())) {
long val = fieldObj.get("value").getAsLong();
this.publishInterval = val * 1000;
System.out.println("Updated the publish interval to "+val);
}
}
action.setStatus(Status.OK);
} catch (InterruptedException e) {}
}
}
public long getPublishInterval() {
return this.publishInterval;
}
@Override
public void handleCustomAction(CustomAction action) {
try {
queue.put(action);
} catch (InterruptedException e) {
}
}
}When the CustomActionHandler is added to the ManagedDevice instance, the handleCustomAction() method is invoked whenever any custom action is initiated by the application.
The following code sample outlines how to add the CustomActionHandler into the ManagedDevice instance.
MyCustomActionHandler handler = new MyCustomActionHandler();
dmClient.addCustomActionHandler(handler);When the device receives the custom action message, it is expected to either execute the action or respond with an error code indicating that it cannot complete the action at this time. The device must use the setStatus() method to set the status of the action as follows,
action.setStatus(Status.OK);The complete code can be found in the device management samples.
For complete details on Device Management Extension, refer to Extending Device Management.
This WIoTP client library updates the corresponding objects whenever there is an update request from the IBM Watson Internet of Things Platform, these update requests are initiated by the application either directly or indirectly (Firmware Update) via the IBM Watson Internet of Things Platform ReST API. Apart from updating these attributes, the library provides a mechanism where the device can be notified whenever a device attribute is updated.
Attributes that can be updated by this operation are location, metadata, device information and firmware.
In order to get notified, the device needs to add a property change listener on those objects that it is interested.
deviceLocation.addPropertyChangeListener(listener);
firmware.addPropertyChangeListener(listener);
deviceInfo.addPropertyChangeListener(listener);
metadata.addPropertyChangeListener(listener);Also, the device needs to implement the propertyChange() method where it receives the notification. A sample implementation is as follows:
public void propertyChange(PropertyChangeEvent evt) {
if(evt.getNewValue() == null) {
return;
}
Object value = (Object) evt.getNewValue();
switch(evt.getPropertyName()) {
case "metadata":
DeviceMetadata metadata = (DeviceMetadata) value;
System.out.println("Received an updated metadata -- "+ metadata);
break;
case "location":
DeviceLocation location = (DeviceLocation) value;
System.out.println("Received an updated location -- "+ location);
break;
case "deviceInfo":
DeviceInfo info = (DeviceInfo) value;
System.out.println("Received an updated device info -- "+ info);
break;
case "mgmt.firmware":
DeviceFirmware firmware = (DeviceFirmware) value;
System.out.println("Received an updated device firmware -- "+ firmware);
break;
}
}Refer to this page for more information about updating the device attributes.
- SampleRasPiDMAgent - A sample agent code that shows how to perform various device management operations on Raspberry Pi.
- SampleRasPiManagedDevice - A sample code that shows how one can perform both device operations and management operations.
- SampleRasPiDMAgentWithCustomMqttAsyncClient - A sample agent code with custom MqttAsyncClient.
- SampleRasPiDMAgentWithCustomMqttClient - A sample agent code with custom MqttClient.
- RasPiFirmwareHandlerSample - A sample implementation of FirmwareHandler for Raspberry Pi.
- DeviceActionHandlerSample - A sample implementation of DeviceActionHandler
- ManagedDeviceWithLifetimeSample - A sample that shows how to send regular manage request with lifetime specified.
- DeviceAttributesUpdateListenerSample - A sample listener code that shows how to listen for a various device attribute changes.
Refer to the recipe that shows how to connect the Raspberry Pi device as managed device to IBM Watson Internet of Things Platform to perform various device management operations in step by step using this client library.